From a0d4ca094fcdd63a76e7f757bf0334c2506a6531 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Thu, 2 Dec 2021 20:28:46 +0100 Subject: [PATCH 001/120] Add first draft --- src/tespy/tools/__init__.py | 1 + src/tespy/tools/optimization.py | 216 ++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 src/tespy/tools/optimization.py diff --git a/src/tespy/tools/__init__.py b/src/tespy/tools/__init__.py index 603fa8b93..269fb1a9f 100644 --- a/src/tespy/tools/__init__.py +++ b/src/tespy/tools/__init__.py @@ -13,3 +13,4 @@ from .data_containers import FluidProperties # noqa: F401 from .data_containers import GroupedComponentProperties # noqa: F401 from .document_models import document_model # noqa: F401 +from .optimization import OptimizationProblem # noqa: F401 diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py new file mode 100644 index 000000000..b4fd5fc22 --- /dev/null +++ b/src/tespy/tools/optimization.py @@ -0,0 +1,216 @@ +try: + import pygmo as pg +except ImportError: + msg = ( + "For this function of TESPy pygmo has to be installed. Either use " + "pip (Linux users only) or conda to install the latest pygmo " + "version. It is also possible to install tespy using the [opt] " + "option: pip install tespy[opt]." + ) + raise ImportError(msg) + +import pandas as pd +from collections import OrderedDict + + +def _nested_OrderedDict(dictionary): + """Create a nested OrderedDict from a nested dict. + + Parameters + ---------- + dictionary : dict + Nested dict. + + Returns + ------- + dictionary : collections.OrderedDict + Nested OrderedDict. + """ + dictionary = OrderedDict(dictionary) + for key, value in dictionary.items(): + if isinstance(value, dict): + dictionary[key] = _nested_OrderedDict(value) + + return dictionary + + +class OptimizationProblem: + r""" + The OptimizationProblem handles the optimization. + + - Set up the optimization problems by specifying constraints, upper and + lower bounds for the decision variables and selection of the objective + function. + - Run the optimization, see + :py:meth:`tespy.tools.optimization.OptimizationProblem.run`. + - Provide the optimization results DataFrame + :code:`OptimizationProblem.individuals`. + + Parameters + ---------- + model : custom class + Object of some class, which provides all the methods required by the + optimization suite, see ... + + variables : dict + Dictionary containing the decision variables and their respective + bounds. + + constraints : dict + Dictionary containing the constraints for the model. + + objective : str + Name of the objective. :code:`objective` is passed to the + :code:`get_objective` method of your tespy model instance. + + Note + ---- + Installation of pygmo via pip is not available for Windows and OSX users + currently. Please use conda instead or refer to their + `documentation `_ + + Example + ------- + Add some example code here, maybe refer to some repositories. + """ + + def __init__(self, model, variables, constraints, objective): + self.model = model + # use OrderedDicts to have consistent order of variables, + # constraints (and objectives in the future) + self.variables = _nested_OrderedDict(variables) + self.constraints = _nested_OrderedDict(constraints) + self.objective = objective + self.variable_list = [] + self.constraint_list = [] + + self.objective_list = [objective] + self.nobj = len(self.objective_list) + + self.bounds = [[], []] + for obj, data in self.variables.items(): + for label, params in data.items(): + for param in params: + self.bounds[0] += [self.variables[obj][label][param]['min']] + self.bounds[1] += [self.variables[obj][label][param]['max']] + self.variable_list += [obj + '-' + label + '-' + param] + + self.input_dict = self.variables.copy() + + self.nic = 0 + for obj, data in self.constraints['upper limits'].items(): + for label, constraints in data.items(): + for param, constraint in constraints.items(): + self.nic += 1 + self.constraint_list += [ + obj + '-' + label + '-' + param + ' <= ' + + str(constraint) + ] + + for obj, data in self.constraints['lower limits'].items(): + for label, constraints in data.items(): + for param, constraint in constraints.items(): + self.nic += 1 + self.constraint_list += [ + obj + '-' + label + '-' + param + ' >= ' + + str(constraint) + ] + + def fitness(self, x): + """Fitness function.""" + i = 0 + for obj, data in self.variables.items(): + for label, params in data.items(): + for param in params: + self.input_dict[obj][label][param] = x[i] + i += 1 + + self.model.solve_model(**self.input_dict) + f1 = [self.model.get_objective(self.objective)] + + cu = [ + self.model.get_param(obj, label, parameter) - constraint + for obj, data in self.constraints['upper limits'].items() + for label, constraints in data.items() + for parameter, constraint in constraints.items() + ] + cl = [ + constraint - self.model.get_param(obj, label, parameter) + for obj, data in self.constraints['lower limits'].items() + for label, constraints in data.items() + for parameter, constraint in constraints.items() + ] + + return f1 + cu + cl + + def get_nobj(self): + """Return number of objectives.""" + return self.nobj + + # inequality constraints (equality constraints not required) + def get_nic(self): + """Return number of inequality constraints.""" + return self.nic + + def get_bounds(self): + """Return bounds of decision variables.""" + return self.bounds + + # throw individuals, params_list, objectives_list, constraint_list into optimization class! + def _process_generation_data(self, gen, pop): + + individual = 0 + for x in pop.get_x(): + self.individuals.loc[(gen, individual), self.variable_list] = x + individual += 1 + + individual = 0 + for objective in pop.get_f(): + self.individuals.loc[(gen, individual), self.objective_list + self.constraint_list] = objective + individual += 1 + + self.individuals['valid'] = ( + self.individuals[self.constraint_list] < 0 + ).all(axis='columns') + + def run(self, algo, num_ind, num_gen): + + self.individuals = pd.DataFrame( + index=range(num_gen * num_ind) + ) + + self.individuals["gen"] = [ + gen for gen in range(num_gen) for ind in range(num_ind) + ] + self.individuals["ind"] = [ + ind for gen in range(num_gen) for ind in range(num_ind) + ] + + self.individuals.set_index(["gen", "ind"], inplace=True) + + algo = pg.algorithm(algo) + pop = pg.population(pg.problem(self), size=num_ind) + + gen = 0 + for gen in range(num_gen - 1): + self._process_generation_data(gen, pop) + print() + print('Evolution: {}'.format(gen)) + for i in range(len(self.objective_list)): + print(self.objective_list[i] + ': {}'.format(round(pop.champion_f[i], 4))) + for i in range(len(self.variable_list)): + print(self.variable_list[i] + ': {}'.format(round(pop.champion_x[i], 4))) + pop = algo.evolve(pop) + + gen += 1 + self._process_generation_data(gen, pop) + + print() + + print('Final evolution: {}'.format(gen)) + for i in range(len(self.objective_list)): + print(self.objective_list[i] + ': {}'.format(round(pop.champion_f[i], 4))) + for i in range(len(self.variable_list)): + print(self.variable_list[i] + ': {}'.format(round(pop.champion_x[i], 4))) + + print() From 7730258b27ed2c5aea9afb28b5e1c7d7bcb3c797 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 17 Dec 2021 20:04:10 +0100 Subject: [PATCH 002/120] Add some docs and class template --- src/tespy/tools/optimization.py | 202 ++++++++++++++++++++++++++++++-- 1 file changed, 191 insertions(+), 11 deletions(-) diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index b4fd5fc22..cf7b2d28b 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -9,9 +9,22 @@ ) raise ImportError(msg) +import numpy as np import pandas as pd from collections import OrderedDict +from tespy.components.basics.cycle_closer import CycleCloser +from tespy.components.heat_exchangers.condenser import Condenser +from tespy.components.heat_exchangers.heat_exchanger_simple import HeatExchangerSimple +from tespy.components.nodes.merge import Merge +from tespy.components.nodes.splitter import Splitter +from tespy.components.piping.valve import Valve +from tespy.components.turbomachinery.pump import Pump +from tespy.components.turbomachinery.turbine import Turbine +from tespy.connections.bus import Bus +from tespy.connections.connection import Connection +from tespy.networks.network import Network + def _nested_OrderedDict(dictionary): """Create a nested OrderedDict from a nested dict. @@ -43,14 +56,15 @@ class OptimizationProblem: function. - Run the optimization, see :py:meth:`tespy.tools.optimization.OptimizationProblem.run`. - - Provide the optimization results DataFrame - :code:`OptimizationProblem.individuals`. + - Provide the optimization results DataFrame in the + :code:`.individuals` attribute of the :code:`OptimizationProblem` class. Parameters ---------- model : custom class Object of some class, which provides all the methods required by the - optimization suite, see ... + optimization suite, see the + :py:class:`tespy.tools.optimization.SamplePlant` for a template. variables : dict Dictionary containing the decision variables and their respective @@ -67,7 +81,7 @@ class OptimizationProblem: ---- Installation of pygmo via pip is not available for Windows and OSX users currently. Please use conda instead or refer to their - `documentation `_ + `documentation `_. Example ------- @@ -117,7 +131,19 @@ def __init__(self, model, variables, constraints, objective): ] def fitness(self, x): - """Fitness function.""" + """Evaluate the fitness function of an individual. + + Parameters + ---------- + x : list + List of the decision variables' values of the current individual. + + Returns + ------- + fitness : list + A list containing the fitness function evaluation as well as the + evaluation of the upper and lower constraints. + """ i = 0 for obj, data in self.variables.items(): for label, params in data.items(): @@ -156,9 +182,17 @@ def get_bounds(self): """Return bounds of decision variables.""" return self.bounds - # throw individuals, params_list, objectives_list, constraint_list into optimization class! def _process_generation_data(self, gen, pop): + """Process the data of the individuals within one generation. + + Parameters + ---------- + gen : int + Generation number. + pop : pygmo.population + PyGMO population object. + """ individual = 0 for x in pop.get_x(): self.individuals.loc[(gen, individual), self.variable_list] = x @@ -166,7 +200,10 @@ def _process_generation_data(self, gen, pop): individual = 0 for objective in pop.get_f(): - self.individuals.loc[(gen, individual), self.objective_list + self.constraint_list] = objective + self.individuals.loc[ + (gen, individual), + self.objective_list + self.constraint_list + ] = objective individual += 1 self.individuals['valid'] = ( @@ -174,6 +211,20 @@ def _process_generation_data(self, gen, pop): ).all(axis='columns') def run(self, algo, num_ind, num_gen): + """Run the optimization algorithm. + + Parameters + ---------- + algo : pygmo.algorithm + PyGMO optimization algorithm. + + num_ind : int + Number of individuals. + + num_gen : int + Number of generations. + """ + print(type(algo)) self.individuals = pd.DataFrame( index=range(num_gen * num_ind) @@ -191,10 +242,11 @@ def run(self, algo, num_ind, num_gen): algo = pg.algorithm(algo) pop = pg.population(pg.problem(self), size=num_ind) + # replace prints with logging gen = 0 for gen in range(num_gen - 1): self._process_generation_data(gen, pop) - print() + print('Evolution: {}'.format(gen)) for i in range(len(self.objective_list)): print(self.objective_list[i] + ': {}'.format(round(pop.champion_f[i], 4))) @@ -205,12 +257,140 @@ def run(self, algo, num_ind, num_gen): gen += 1 self._process_generation_data(gen, pop) - print() - print('Final evolution: {}'.format(gen)) for i in range(len(self.objective_list)): print(self.objective_list[i] + ': {}'.format(round(pop.champion_f[i], 4))) for i in range(len(self.variable_list)): print(self.variable_list[i] + ': {}'.format(round(pop.champion_x[i], 4))) - print() + +class SamplePlant: + """Class template for TESPy model usage in optimization module.""" + def __init__(self): + + self.nw = Network(fluids=['water']) + self.nw.set_attr(p_unit="bar", T_unit="C", h_unit="kJ / kg", iterinfo=False) + + # main cycle components cycle closer + steam_generator = HeatExchangerSimple("steam generator") + close_cycle = CycleCloser("cycle closer") + + turbine_hp = Turbine("turbine high pressure") + turbine_lp = Turbine("turbine low pressure") + extraction = Splitter("steam extraction splitter", num_out=2) + preheater = Condenser("feed water preheater") + valve = Valve("preheater condensate valve") + waste_steam_merge = Merge("waste steam merge") + + condenser = HeatExchangerSimple("main condenser") + feed_pump = Pump("feed water pump") + + # Connections + + # main cycle + c0 = Connection(steam_generator, "out1", close_cycle, "in1", label="0") + c1 = Connection(close_cycle, "out1", turbine_hp, "in1", label="1") + c2 = Connection(turbine_hp, "out1", extraction, "in1", label="2") + c3 = Connection(extraction, "out1", turbine_lp, "in1", label="3") + c4 = Connection(turbine_lp, "out1", waste_steam_merge, "in1", label="4") + c5 = Connection(waste_steam_merge, "out1", condenser, "in1", label="5") + c6 = Connection(condenser, "out1", feed_pump, "in1", label="6") + c7 = Connection(feed_pump, "out1", preheater, "in2", label="7") + c8 = Connection(preheater, "out2", steam_generator, "in1", label="8") + + # steam extraction + c11 = Connection(extraction, "out2", preheater, "in1", label="11") + c12 = Connection(preheater, "out1", valve, "in1", label="12") + c13 = Connection(valve, "out1", waste_steam_merge, "in2", label="13") + + self.nw.add_conns(c0, c1, c2, c3, c4, c5, c6, c7, c8, c11, c12, c13) + + # component specifications + steam_generator.set_attr(pr=0.92) + turbine_hp.set_attr(eta_s=0.9) + turbine_lp.set_attr(eta_s=0.9) + condenser.set_attr(pr=1) + feed_pump.set_attr(eta_s=0.75) + preheater.set_attr(ttd_u=5, pr1=1, pr2=0.98) + + # connection specifications + c1.set_attr(fluid={'water': 1}, p=100, T=600, m=10) + # pressure at connection 2 will be the parameter to optimize + c2.set_attr(p=10) + c6.set_attr(x=0, T=30) + + power_bus = Bus('power output') + power_bus.add_comps( + {'comp': turbine_hp, 'char': 0.97}, + {'comp': turbine_lp, 'char': 0.97}, + {'comp': feed_pump, 'char': 0.97, 'base': 'bus'} + ) + heat_bus = Bus('heat input') + heat_bus.add_comps({'comp': steam_generator}) + self.nw.add_busses(power_bus, heat_bus) + + self.nw.solve("design") + self.stable = "_stable" + self.nw.save(self.stable) + + def get_param(self, obj, label, parameter): + """Get the value of a parameter in the network's unit system. + + Parameters + ---------- + obj : str + Object to get parameter for (Components/Connections). + + label : str + Label of the object in the TESPy model. + + parameter : str + Name of the parameter of the object. + + Returns + ------- + value : float + Value of the parameter. + """ + if obj == 'Components': + return self.nw.get_comp(label).get_attr(parameter).val + elif obj == 'Connections': + return self.nw.get_conn(label).get_attr(parameter).val + + def set_params(self, **kwargs): + + if "Connections" in kwargs: + for c, params in kwargs["Connections"].items(): + self.nw.get_conn(c).set_attr(**params) + + if "Components" in kwargs: + for c, params in kwargs["Components"].items(): + self.nw.get_comp(c).set_attr(**params) + + def solve_model(self, **kwargs): + + self.set_params(**kwargs) + + self.solved = False + try: + self.nw.solve("design") + if self.nw.res[-1] >= 1e-3 or self.nw.lin_dep: + self.nw.solve("design", init_only=True, init_path=self.stable) + else: + # might need more checks here! + if any(self.nw.result['Condenser']['Q'] > 0): + self.solved = False + else: + self.solved = True + except: + self.nw.lin_dep = True + self.nw.solve("design", init_only=True, init_path=self.stable) + + def get_objective(self): + if self.solved: + return -( + self.nw.busses['power output'].P.val / + self.nw.busses['heat bus'].P.val + ) + else: + return np.nan From e28e2557e3931680aedbc414072cfa1474f37741 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 10 Jan 2022 17:45:23 +0100 Subject: [PATCH 003/120] Move some functions to the helpers module --- src/tespy/tools/analyses.py | 2 -- src/tespy/tools/document_models.py | 16 ------------ src/tespy/tools/helpers.py | 39 +++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/tespy/tools/analyses.py b/src/tespy/tools/analyses.py index 929fb2209..bcaa49c4b 100644 --- a/src/tespy/tools/analyses.py +++ b/src/tespy/tools/analyses.py @@ -24,8 +24,6 @@ from tespy.tools import helpers as hlp from tespy.tools.global_vars import err -# %% - class ExergyAnalysis: r"""Class for exergy analysis of TESPy models.""" diff --git a/src/tespy/tools/document_models.py b/src/tespy/tools/document_models.py index 8ccce1ad7..f52f1f173 100644 --- a/src/tespy/tools/document_models.py +++ b/src/tespy/tools/document_models.py @@ -10,8 +10,6 @@ """ import os import sys -from collections.abc import Mapping -from copy import deepcopy from datetime import date import CoolProp as CP @@ -79,20 +77,6 @@ def document_model(nw, path='report', filename='report.tex', fmt={}): f.close() -def merge_dicts(dict1, dict2): - """Return a new dictionary by merging two dictionaries recursively.""" - - result = deepcopy(dict1) - - for key, value in dict2.items(): - if isinstance(value, Mapping): - result[key] = merge_dicts(result.get(key, {}), value) - else: - result[key] = deepcopy(dict2[key]) - - return result - - def set_defaults(nw): """ Set up defaults for report formatting. diff --git a/src/tespy/tools/helpers.py b/src/tespy/tools/helpers.py index 522233f92..aec4b0a3d 100644 --- a/src/tespy/tools/helpers.py +++ b/src/tespy/tools/helpers.py @@ -14,11 +14,48 @@ import CoolProp as CP import numpy as np +from collections import OrderedDict +from collections.abc import Mapping +from copy import deepcopy + from tespy.tools.global_vars import err from tespy.tools.global_vars import fluid_property_data from tespy.tools.global_vars import molar_masses -# %% + +def merge_dicts(dict1, dict2): + """Return a new dictionary by merging two dictionaries recursively.""" + + result = deepcopy(dict1) + + for key, value in dict2.items(): + if isinstance(value, Mapping): + result[key] = merge_dicts(result.get(key, {}), value) + else: + result[key] = deepcopy(dict2[key]) + + return result + + +def nested_OrderedDict(dictionary): + """Create a nested OrderedDict from a nested dict. + + Parameters + ---------- + dictionary : dict + Nested dict. + + Returns + ------- + dictionary : collections.OrderedDict + Nested OrderedDict. + """ + dictionary = OrderedDict(dictionary) + for key, value in dictionary.items(): + if isinstance(value, dict): + dictionary[key] = nested_OrderedDict(value) + + return dictionary class TESPyNetworkError(Exception): From 4222691da5a53ab426953d2efb19525aa8ad7128 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 10 Jan 2022 17:45:42 +0100 Subject: [PATCH 004/120] Add some documentation, move SampleClass --- src/tespy/tools/_optimization_example.py | 163 +++++++++++++++ src/tespy/tools/optimization.py | 251 +++++++---------------- 2 files changed, 240 insertions(+), 174 deletions(-) create mode 100644 src/tespy/tools/_optimization_example.py diff --git a/src/tespy/tools/_optimization_example.py b/src/tespy/tools/_optimization_example.py new file mode 100644 index 000000000..dd8f1c422 --- /dev/null +++ b/src/tespy/tools/_optimization_example.py @@ -0,0 +1,163 @@ +import numpy as np + +from tespy.components.basics.cycle_closer import CycleCloser +from tespy.components.heat_exchangers.condenser import Condenser +from tespy.components.heat_exchangers.heat_exchanger_simple import HeatExchangerSimple +from tespy.components.nodes.merge import Merge +from tespy.components.nodes.splitter import Splitter +from tespy.components.piping.valve import Valve +from tespy.components.turbomachinery.pump import Pump +from tespy.components.turbomachinery.turbine import Turbine +from tespy.connections.bus import Bus +from tespy.connections.connection import Connection +from tespy.networks.network import Network + + +class SamplePlant: + """Class template for TESPy model usage in optimization module.""" + def __init__(self): + + self.nw = Network(fluids=['water']) + self.nw.set_attr(p_unit="bar", T_unit="C", h_unit="kJ / kg", iterinfo=False) + + # main cycle components cycle closer + steam_generator = HeatExchangerSimple("steam generator") + close_cycle = CycleCloser("cycle closer") + + turbine_hp = Turbine("turbine high pressure") + turbine_lp = Turbine("turbine low pressure") + extraction = Splitter("steam extraction splitter", num_out=2) + preheater = Condenser("feed water preheater") + valve = Valve("preheater condensate valve") + waste_steam_merge = Merge("waste steam merge") + + condenser = HeatExchangerSimple("main condenser") + feed_pump = Pump("feed water pump") + + # Connections + + # main cycle + c0 = Connection(steam_generator, "out1", close_cycle, "in1", label="0") + c1 = Connection(close_cycle, "out1", turbine_hp, "in1", label="1") + c2 = Connection(turbine_hp, "out1", extraction, "in1", label="2") + c3 = Connection(extraction, "out1", turbine_lp, "in1", label="3") + c4 = Connection(turbine_lp, "out1", waste_steam_merge, "in1", label="4") + c5 = Connection(waste_steam_merge, "out1", condenser, "in1", label="5") + c6 = Connection(condenser, "out1", feed_pump, "in1", label="6") + c7 = Connection(feed_pump, "out1", preheater, "in2", label="7") + c8 = Connection(preheater, "out2", steam_generator, "in1", label="8") + + # steam extraction + c11 = Connection(extraction, "out2", preheater, "in1", label="11") + c12 = Connection(preheater, "out1", valve, "in1", label="12") + c13 = Connection(valve, "out1", waste_steam_merge, "in2", label="13") + + self.nw.add_conns(c0, c1, c2, c3, c4, c5, c6, c7, c8, c11, c12, c13) + + # component specifications + steam_generator.set_attr(pr=0.92) + turbine_hp.set_attr(eta_s=0.9) + turbine_lp.set_attr(eta_s=0.9) + condenser.set_attr(pr=1) + feed_pump.set_attr(eta_s=0.75) + preheater.set_attr(ttd_u=5, pr1=1, pr2=0.98) + + # connection specifications + c1.set_attr(fluid={'water': 1}, p=100, T=600, m=10) + # pressure at connection 2 will be the parameter to optimize + c2.set_attr(p=10) + c6.set_attr(x=0, p=0.1) + # set liquid state to provide good starting values + c8.set_attr(state='l') + + power_bus = Bus('power output') + power_bus.add_comps( + {'comp': turbine_hp, 'char': 0.97}, + {'comp': turbine_lp, 'char': 0.97}, + {'comp': feed_pump, 'char': 0.97, 'base': 'bus'} + ) + heat_bus = Bus('heat input') + heat_bus.add_comps({'comp': steam_generator}) + self.nw.add_busses(power_bus, heat_bus) + + self.nw.solve("design") + self.stable = "_stable" + self.nw.save(self.stable) + + def get_param(self, obj, label, parameter): + """Get the value of a parameter in the network's unit system. + + Parameters + ---------- + obj : str + Object to get parameter for (Components/Connections). + + label : str + Label of the object in the TESPy model. + + parameter : str + Name of the parameter of the object. + + Returns + ------- + value : float + Value of the parameter. + """ + if obj == 'Components': + return self.nw.get_comp(label).get_attr(parameter).val + elif obj == 'Connections': + return self.nw.get_conn(label).get_attr(parameter).val + + def set_params(self, **kwargs): + + if "Connections" in kwargs: + for c, params in kwargs["Connections"].items(): + self.nw.get_conn(c).set_attr(**params) + + if "Components" in kwargs: + for c, params in kwargs["Components"].items(): + self.nw.get_comp(c).set_attr(**params) + + def solve_model(self, **kwargs): + """ + Solve the TESPy model given the + """ + + self.set_params(**kwargs) + + self.solved = False + try: + self.nw.solve("design") + if self.nw.res[-1] >= 1e-3 or self.nw.lin_dep: + self.nw.solve("design", init_only=True, init_path=self.stable) + else: + # might need more checks here! + if any(self.nw.results['Condenser']['Q'] > 0): + self.solved = False + else: + self.solved = True + except ValueError as e: + self.nw.lin_dep = True + self.nw.solve("design", init_only=True, init_path=self.stable) + + def get_objective(self, objective): + """ + Get the current objective function evaluation. + + Parameters + ---------- + objective : str + Name of the objective function. + + Returns + ------- + objective_value : float + Evaluation of the objective function. + """ + if self.solved: + return -1 / ( + self.nw.busses['power output'].P.val / + self.nw.busses['heat input'].P.val + ) + else: + return np.nan diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index cf7b2d28b..f9c6e399e 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -9,42 +9,9 @@ ) raise ImportError(msg) -import numpy as np import pandas as pd -from collections import OrderedDict -from tespy.components.basics.cycle_closer import CycleCloser -from tespy.components.heat_exchangers.condenser import Condenser -from tespy.components.heat_exchangers.heat_exchanger_simple import HeatExchangerSimple -from tespy.components.nodes.merge import Merge -from tespy.components.nodes.splitter import Splitter -from tespy.components.piping.valve import Valve -from tespy.components.turbomachinery.pump import Pump -from tespy.components.turbomachinery.turbine import Turbine -from tespy.connections.bus import Bus -from tespy.connections.connection import Connection -from tespy.networks.network import Network - - -def _nested_OrderedDict(dictionary): - """Create a nested OrderedDict from a nested dict. - - Parameters - ---------- - dictionary : dict - Nested dict. - - Returns - ------- - dictionary : collections.OrderedDict - Nested OrderedDict. - """ - dictionary = OrderedDict(dictionary) - for key, value in dictionary.items(): - if isinstance(value, dict): - dictionary[key] = _nested_OrderedDict(value) - - return dictionary +from tespy.tools.helpers import merge_dicts, nested_OrderedDict class OptimizationProblem: @@ -79,21 +46,90 @@ class OptimizationProblem: Note ---- + For the required structure of the input dictionaries see the example in + the :py:class:`tespy.tools.optimization.SamplePlant`. + Installation of pygmo via pip is not available for Windows and OSX users currently. Please use conda instead or refer to their `documentation `_. Example ------- - Add some example code here, maybe refer to some repositories. + This example shows the optimization of the thermal efficiency of the + `SamplePlant` with respect to the pressure value at the intermediate + extration of the turbine. + + >>> from tespy.tools.optimization import OptimizationProblem + >>> from tespy.tools._optimization_example import SamplePlant + >>> import pygmo as pg + + Create an instance of your plant class, i.e. :code:`plant = SamplePlant()` + and the instance of :code:`OptimizationProblem` by passing the plant + instance, the variables, the constraints and the objective. + + As the optimization problem can be formulated as unconstrained problem by + defining the lower and the upper limits for the variable values, the + constraints parameter can be left to its default value. The objective + function (:py:meth:`tespy.tools.optimzite.SamplePlant.get_objective`), which + returns the same evaluation for any kind of objective (there is only the + thermal efficiency in this case), the :code:`objective` keyword does not + need to be defined in this example (you could think of defining several + objectives here and returning them according to the selected objective). + + As described, the variable in this example is the extraction pressure at the + turbine. The upper limit is 50 bar and the lower limit 0.4 bar. Of course, + it is possible to use multiple variables and component parameters as + variables as well. Just provide them in the same structure as in this + example. + + >>> plant = SamplePlant() + >>> variables = {"Connections": {"2": {"p": {"min": 0.4, "max": 50}}}} + >>> optimize = OptimizationProblem(plant, variables) + + .. note:: + + Please note, that the sense of optimization is always minimization, + therefore you need to define your objective functions in the appropriate + way. + + After selection of an appropriate algorithm (differential evolution is a + good fit for this application) we can start the optimization run. For more + information on algorithms available in the PyGMO framework and their + individual specifications please refer to the respective section in their + online documentation: + `list of algorithms `_. + Specify the number of individuals (10), the number of generations (15) and + call the :py:meth:`tespy.tools.optimize.OptimizationProblem.run` method of + your :code:`OptimizationProblem` instance passing the algorithm and the + number of individials and generations. + + >>> num_ind = 10 + >>> num_gen = 15 + + >>> algo = pg.de() + >>> ();optimize.run(algo, num_ind, num_gen);() # doctest: +ELLIPSIS + (...) + + In our sample run, we found an optimal value for the extraction pressure of + about 4.45 bar. """ - def __init__(self, model, variables, constraints, objective): + def __init__(self, model, variables={}, constraints={}, objective="objective"): self.model = model - # use OrderedDicts to have consistent order of variables, - # constraints (and objectives in the future) - self.variables = _nested_OrderedDict(variables) - self.constraints = _nested_OrderedDict(constraints) + default_variables = {"Connections": {}, "Components": {}} + default_constraints = { + "lower limits": {"Connections": {}, "Components": {}}, + "upper limits": { "Connections": {}, "Components": {}} + } + # merge the passed values into the default dictionary structure + variables = merge_dicts(variables, default_variables) + constraints = merge_dicts(constraints, default_constraints) + + # pygmo creates a vector for the variables and constraints, which has + # to be in consistent order. Therefore use OrderedDicts instead of + # dictionaries + self.variables = nested_OrderedDict(variables) + self.constraints = nested_OrderedDict(constraints) self.objective = objective self.variable_list = [] self.constraint_list = [] @@ -215,7 +251,7 @@ def run(self, algo, num_ind, num_gen): Parameters ---------- - algo : pygmo.algorithm + algo : pygmo.core PyGMO optimization algorithm. num_ind : int @@ -224,7 +260,6 @@ def run(self, algo, num_ind, num_gen): num_gen : int Number of generations. """ - print(type(algo)) self.individuals = pd.DataFrame( index=range(num_gen * num_ind) @@ -262,135 +297,3 @@ def run(self, algo, num_ind, num_gen): print(self.objective_list[i] + ': {}'.format(round(pop.champion_f[i], 4))) for i in range(len(self.variable_list)): print(self.variable_list[i] + ': {}'.format(round(pop.champion_x[i], 4))) - - -class SamplePlant: - """Class template for TESPy model usage in optimization module.""" - def __init__(self): - - self.nw = Network(fluids=['water']) - self.nw.set_attr(p_unit="bar", T_unit="C", h_unit="kJ / kg", iterinfo=False) - - # main cycle components cycle closer - steam_generator = HeatExchangerSimple("steam generator") - close_cycle = CycleCloser("cycle closer") - - turbine_hp = Turbine("turbine high pressure") - turbine_lp = Turbine("turbine low pressure") - extraction = Splitter("steam extraction splitter", num_out=2) - preheater = Condenser("feed water preheater") - valve = Valve("preheater condensate valve") - waste_steam_merge = Merge("waste steam merge") - - condenser = HeatExchangerSimple("main condenser") - feed_pump = Pump("feed water pump") - - # Connections - - # main cycle - c0 = Connection(steam_generator, "out1", close_cycle, "in1", label="0") - c1 = Connection(close_cycle, "out1", turbine_hp, "in1", label="1") - c2 = Connection(turbine_hp, "out1", extraction, "in1", label="2") - c3 = Connection(extraction, "out1", turbine_lp, "in1", label="3") - c4 = Connection(turbine_lp, "out1", waste_steam_merge, "in1", label="4") - c5 = Connection(waste_steam_merge, "out1", condenser, "in1", label="5") - c6 = Connection(condenser, "out1", feed_pump, "in1", label="6") - c7 = Connection(feed_pump, "out1", preheater, "in2", label="7") - c8 = Connection(preheater, "out2", steam_generator, "in1", label="8") - - # steam extraction - c11 = Connection(extraction, "out2", preheater, "in1", label="11") - c12 = Connection(preheater, "out1", valve, "in1", label="12") - c13 = Connection(valve, "out1", waste_steam_merge, "in2", label="13") - - self.nw.add_conns(c0, c1, c2, c3, c4, c5, c6, c7, c8, c11, c12, c13) - - # component specifications - steam_generator.set_attr(pr=0.92) - turbine_hp.set_attr(eta_s=0.9) - turbine_lp.set_attr(eta_s=0.9) - condenser.set_attr(pr=1) - feed_pump.set_attr(eta_s=0.75) - preheater.set_attr(ttd_u=5, pr1=1, pr2=0.98) - - # connection specifications - c1.set_attr(fluid={'water': 1}, p=100, T=600, m=10) - # pressure at connection 2 will be the parameter to optimize - c2.set_attr(p=10) - c6.set_attr(x=0, T=30) - - power_bus = Bus('power output') - power_bus.add_comps( - {'comp': turbine_hp, 'char': 0.97}, - {'comp': turbine_lp, 'char': 0.97}, - {'comp': feed_pump, 'char': 0.97, 'base': 'bus'} - ) - heat_bus = Bus('heat input') - heat_bus.add_comps({'comp': steam_generator}) - self.nw.add_busses(power_bus, heat_bus) - - self.nw.solve("design") - self.stable = "_stable" - self.nw.save(self.stable) - - def get_param(self, obj, label, parameter): - """Get the value of a parameter in the network's unit system. - - Parameters - ---------- - obj : str - Object to get parameter for (Components/Connections). - - label : str - Label of the object in the TESPy model. - - parameter : str - Name of the parameter of the object. - - Returns - ------- - value : float - Value of the parameter. - """ - if obj == 'Components': - return self.nw.get_comp(label).get_attr(parameter).val - elif obj == 'Connections': - return self.nw.get_conn(label).get_attr(parameter).val - - def set_params(self, **kwargs): - - if "Connections" in kwargs: - for c, params in kwargs["Connections"].items(): - self.nw.get_conn(c).set_attr(**params) - - if "Components" in kwargs: - for c, params in kwargs["Components"].items(): - self.nw.get_comp(c).set_attr(**params) - - def solve_model(self, **kwargs): - - self.set_params(**kwargs) - - self.solved = False - try: - self.nw.solve("design") - if self.nw.res[-1] >= 1e-3 or self.nw.lin_dep: - self.nw.solve("design", init_only=True, init_path=self.stable) - else: - # might need more checks here! - if any(self.nw.result['Condenser']['Q'] > 0): - self.solved = False - else: - self.solved = True - except: - self.nw.lin_dep = True - self.nw.solve("design", init_only=True, init_path=self.stable) - - def get_objective(self): - if self.solved: - return -( - self.nw.busses['power output'].P.val / - self.nw.busses['heat bus'].P.val - ) - else: - return np.nan From 923dcabf71ca304947e6937b0f64cc5d32a933c2 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 21 Jan 2022 17:11:40 +0100 Subject: [PATCH 005/120] Remove py36 --- setup.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index fc3581aa2..78f292a20 100644 --- a/setup.cfg +++ b/setup.cfg @@ -102,7 +102,6 @@ skip = migrations # - can use as many you want python_versions = - py36 py37 py38 From 9e924ede665183baa1eeee9d3a6b77d9f3892d20 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 21 Jan 2022 17:12:02 +0100 Subject: [PATCH 006/120] Fix merge_dicts function call --- src/tespy/tools/document_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tespy/tools/document_models.py b/src/tespy/tools/document_models.py index f52f1f173..ad51f9ba6 100644 --- a/src/tespy/tools/document_models.py +++ b/src/tespy/tools/document_models.py @@ -60,7 +60,7 @@ def document_model(nw, path='report', filename='report.tex', fmt={}): os.makedirs(fig_path) rpt = set_defaults(nw) - rpt = merge_dicts(rpt, fmt) + rpt = hlp.merge_dicts(rpt, fmt) rpt['path'] = path From 35626f6571b74715424fe4f9a11d977c94989484 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 21 Jan 2022 17:12:36 +0100 Subject: [PATCH 007/120] Only throw ImportError on construction of class --- src/tespy/tools/optimization.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index f9c6e399e..d61f48cd7 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -1,13 +1,7 @@ try: import pygmo as pg except ImportError: - msg = ( - "For this function of TESPy pygmo has to be installed. Either use " - "pip (Linux users only) or conda to install the latest pygmo " - "version. It is also possible to install tespy using the [opt] " - "option: pip install tespy[opt]." - ) - raise ImportError(msg) + pg = None import pandas as pd @@ -115,6 +109,15 @@ class OptimizationProblem: """ def __init__(self, model, variables={}, constraints={}, objective="objective"): + if pg is None: + msg = ( + "For this function of TESPy pygmo has to be installed. Either use " + "pip (Linux users only) or conda to install the latest pygmo " + "version. It is also possible to install tespy using the [opt] " + "option: pip install tespy[opt]." + ) + raise ImportError(msg) + self.model = model default_variables = {"Connections": {}, "Components": {}} default_constraints = { From 46a79ccea9e59f9600df1fca64fb084a51ddeb22 Mon Sep 17 00:00:00 2001 From: maltefritz Date: Thu, 9 Jun 2022 12:44:18 +0200 Subject: [PATCH 008/120] Add figures for starting value tutorial. --- .../tutorial_sv_heat_pump_intheatex.svg | 916 ++++++ docs/api/_images/tutorial_sv_logph.svg | 2571 +++++++++++++++++ 2 files changed, 3487 insertions(+) create mode 100644 docs/api/_images/tutorial_sv_heat_pump_intheatex.svg create mode 100644 docs/api/_images/tutorial_sv_logph.svg diff --git a/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg b/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg new file mode 100644 index 000000000..2dc4af84d --- /dev/null +++ b/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg @@ -0,0 +1,916 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + expansion valve compressor heat sink train heat sourcetrain internal heatexchanger diff --git a/docs/api/_images/tutorial_sv_logph.svg b/docs/api/_images/tutorial_sv_logph.svg new file mode 100644 index 000000000..8c150aad5 --- /dev/null +++ b/docs/api/_images/tutorial_sv_logph.svg @@ -0,0 +1,2571 @@ + + + +image/svg+xml0 +500 +1000 +1500 +2000 +h in +kJkg +10 +0 +10 +1 +10 +2 +p in bar +0.00135739 +m +3 +kg +0.002 +m +3 +kg +0.005 +m +3 +kg +0.01 +m +3 +kg +0.02 +m +3 +kg +0.05 +m +3 +kg +0.1 +m +3 +kg +0.2 +m +3 +kg +0.5 +m +3 +kg +1.0 +m +3 +kg +2.0 +m +3 +kg +-25.0 °C +0.0 °C +25.0 °C +50.0 °C +75.0 °C +100.0 °C +125.0 °C +150.0 °C +175.0 °C +200.0 °C +225.0 °C +250.0 °C +275.0 °C +300.0 °C +325.0 °C +1000.0 +JkgK +1500.0 +JkgK +2000.0 +JkgK +2500.0 +JkgK +3000.0 +JkgK +3500.0 +JkgK +4000.0 +JkgK +4500.0 +JkgK +5000.0 +JkgK +5500.0 +JkgK +6000.0 +JkgK +6500.0 +JkgK +7000.0 +JkgK +7500.0 +JkgK +0.0 - +0.1 - +0.2 - +0.3 - +0.4 - +0.5 - +0.6 - +0.7 - +0.8 - +0.9 - +1.0 - +1 +2 +3 +4 +5 +6 +1 +: Internal Heat Exchanger hot +2 +: Valve +3 +: Evaporator +4 +: Internal Heat Exchanger cold +5 +: Compressor +6 +: Condenser + \ No newline at end of file From 9b5e53e0fe770c0e87eab425015ee68e3cec1492 Mon Sep 17 00:00:00 2001 From: maltefritz Date: Thu, 9 Jun 2022 12:45:24 +0200 Subject: [PATCH 009/120] Add starting value tutorial. --- .../tutorial_starting_values.rst | 297 ++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 docs/tutorials_examples/tutorial_starting_values.rst diff --git a/docs/tutorials_examples/tutorial_starting_values.rst b/docs/tutorials_examples/tutorial_starting_values.rst new file mode 100644 index 000000000..1f3de6e12 --- /dev/null +++ b/docs/tutorials_examples/tutorial_starting_values.rst @@ -0,0 +1,297 @@ +Starting value tutorial +----------------------- + +.. contents:: + :depth: 1 + :local: + :backlinks: top + +Subjekt +^^^^^^^ + +In numerical and iterative methods, a start value is a certain value of a +variable with which a calculation is started. With more complex TESPy models +it can happen that the simulation does not convert. The numerics of the solver +is vulnerable if the specified variables are not primary variables. These are +variables that can be solved after one iteration. For example, pressures, +temperatures and enthalpies are among to them. Because of that it is +recommended to give these parameter for your simulation. + +Task +^^^^ + +After learning to create simple heat pump with TESPy, the goal is to model +more complex systems. After the successful creation of the network, +components, connections and parameterization, it is often the problem that the +simulation does not convert. + +.. error:: + Singularity in jacobian matrix, calculation aborted! Make sure + your network does not have any linear dependencies in the parametrisation. + Other reasons might be + + -> given temperature with given pressure in two phase region, try setting + enthalpy instead or provide accurate starting value for pressure. + + -> given logarithmic temperature differences or kA-values for heat + exchangers. + + -> support better starting values. + + -> bad starting value for fuel mass flow of combustion chamber, provide + small (near to zero, but not zero) starting value. + +To fix this error, it is recommended to create a stable calculation first. +This is used to have suitable starting values for the actual calculation. + +Application +^^^^^^^^^^^ + +Following the first tutorial a heat pumps with internal heat exchangers is +considered. You can see the plant topology in the figure. + +.. figure:: api/_images/tutorial_sv_heat_pump_intheatex.svg + :align: center + + Figure: Topology of heat pump with internal heat exchanger + +It consists of a consumer system, a valve, an evaporator system, a compressor +and additionally of an internal heat exchanger. +In order to simulate this heat pump, the TESPy model has to be built up. +First, the network has to be initialized and the refrigerants used have to be +specified. In this example the heat pump work with ammonia (NH\ :sub:`3`\) and +water (H\ :sub:`2`\O). Furthermore, it is recommended to define the unit +system not to work with variables set to SI-Units. + +.. code-block:: python + + from tespy.networks import Network + + # network + nw = Network( + fluids=['water', 'NH3'], + T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s' + ) + +After that the required components have to be created. + +.. code-block:: python + + from tespy.components import ( + Condenser, Compressor, CycleCloser, HeatExchanger, + HeatExchangerSimple, Pump, Sink, Source, Valve + ) + + # components + cycle_closer = CycleCloser('Refrigerant Cycle Closer') + + # heat source + heatsource_feedflow = Source('Heat Source Feed Flow') + heatsource_pump = Pump('Heat Source Recirculation Pump') + heatsource_evaporator = HeatExchanger('Heat Source Evaporator') + heatsource_backflow = Sink('Heat Source Back Flow') + + # compression + compressor = Compressor('Compressor') + + # heat sink + cons_pump = Pump('Heat Sink Recirculation Pump') + condenser = Condenser('Heat Sink Condenser') + cons_heatsink = HeatExchangerSimple('Heat Consumer') + cons_cycle_closer = CycleCloser('Consumer Feed Flow') + + # internal heat exchange + int_heatex = HeatExchanger('Internal Heat Exchanger') + + # expansion + valve = Valve('Expansion Valve') + +.. note:: + + If the heat pump operates in a supercritical range, the condenser has to + be replaced with a heat exchanger. + +Now the connections according to the topology have to be linked. For a better +overview of the results it is recommended to label the connections. + +.. code-block:: python + + from tespy.connections import Connection + + # connections + # heat source + cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='cc2hs_eva') + hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='hs_feed2hs_pump') + hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='hs_pump2hs_eva') + hs_eva2hs_back = Connection( + heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='hs_eva2hs_back' + ) + + nw.add_conns(cc2hs_eva, hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back) + + # internal heat exchange cold side + hs_eva2int_heatex = Connection( + heatsource_evaporator, 'out2', int_heatex, 'in2', label='hs_eva2int_heatex' + ) + + nw.add_conns(hs_eva2int_heatex) + + # compression + int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='int_heatex2comp') + comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='comp2cond') + + nw.add_conns(int_heatex2comp, comp2cond) + + # heat sink + cons_back2cons_pump = Connection( + cons_cycle_closer, 'out1', cons_pump, 'in1', label='cons_back2cons_pump' + ) + cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='cons_pump2cond') + cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='cond2cons_hs') + cons_hs2cons_feed = Connection( + cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='cons_hs2cons_feed' + ) + + nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed) + + # internal heat exchange hot side + cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='cond2int_heatex') + + nw.add_conns(cond2int_heatex) + + # expansion + int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='int_heatex2valve') + valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='valve2cc') + + nw.add_conns(int_heatex2valve, valve2cc) + +After the initialization of the network and the creation of the components and +connections, a stable parameterization is built up to have suitable initial +values for the actual simulation. + +.. note:: + + To create a stable simulation, it is recommended to set pressure and + enthalpie values instead of temperature values. In this example, fixed + points can be identified with the help of the logph diagram which you can + see in the figure. + + On the one hand the point behind the evaporator is fixed. At this point + the vapor content of the ammonia is at 100% (x=1). Furthermore, it is + recommended to specify the pressure in order to clearly determine the + point. On the other hand the point behind the condenser is fixed, too. + At these point the ammonia has a vapor content of 0% (x=0). As before, the + pressure value has also to be set. + +.. figure:: api/_images/tutorial_sv_logph.svg + :align: center + + Figure: Logph diagram of ammonia + +In addition to the fixed evaporation and condensation points, the fluids to be +used, the feedflow and backflow temperatures of the consumer and heat source +as well as the enthalpy between internal heat exchanger and valve have to be +defined. + +To correctly determine the enthalpies and pressures, CoolProp is to be +imported. It is important to note that the PropertySI function (PropsSI) works +with SI unit. These may differ from the units defined in the network. + +.. code-block:: python + + import CoolProp.CoolProp as CP + + # parametrization connections + # set feedflow and backflow temperature of heat source and consumer + T_hs_bf = 5 + T_hs_ff = 10 + T_cons_bf = 50 + T_cons_ff = 90 + + # evaporation point + h_eva = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273, 'NH3') * 1e-3 + p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273, 'NH3') * 1e-5 + hs_eva2int_heatex.set_attr(x=1, p=p_eva) + + # condensation point + h_cond = CP.PropsSI('H', 'Q', 0, 'T', T_cons_ff + 5 + 273, 'NH3') * 1e-3 + p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273, 'NH3') * 1e-5 + cond2int_heatex.set_attr(p=p_cond) + + # internal heat exchanger to valve + int_heatex2valve.set_attr(h=h_cond * 0.99, fluid={'water': 0, 'NH3': 1}) + + # consumer cycle + cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, 'NH3': 0}) + cons_hs2cons_feed.set_attr(T=T_cons_bf) + + # heat source cycle + hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, 'NH3': 0}) + hs_eva2hs_back.set_attr(T=T_hs_bf, p=1) + +Some components have to be parameterized. For the heat source and heat sink +recirculation pump as well as the conedenser the isentropic efficiency is to +be set. Further we set the pressure ratios on hot and cold side for the +condenser, evaporator and internal heat exchanger. The consumer will have +pressure losses, too. + +.. code-block:: python + + # parametrization components + # isentropic efficiency + cons_pump.set_attr(eta_s=0.8) + heatsource_pump.set_attr(eta_s=0.8) + compressor.set_attr(eta_s=0.85) + + # pressure ratios + condenser.set_attr(pr1=0.99, pr2=0.99) + heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98) + cons_heatsink.set_attr(pr=0.99) + int_heatex.set_attr(pr1=0.99, pr2=0.99) + +The most important parameter is the consumers heat demand setting as +“key parameter”. After that the network can be solved and a stable simulation +can be used for further simulations. + +.. code-block:: python + + # key parameter + cons_heatsink.set_attr(P.val=-1e6) + + # solve the network + nw.solve('design') + nw.print_results() + + # calculate and print COP + cop = abs( + cons_heatsink.P.val + / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val) + ) + print(f'COP = {cop:.4}') + +After that, enthalpies and pressures can be set as "None" and the desired +values for the upper or lower terminal temperature differences, references or +other unstable values can be set for the actual simulation. + +.. code-block:: python + + # parametrization for the actual simulation + hs_eva2int_heatex.set_attr(p=None) + heatsource_evaporator.set_attr(ttd_l=5) + + cond2int_heatex.set_attr(p=None) + condenserset_attr(ttd_u=5) + + int_heatex2valve.set_attr(h=None) + int_heatex2comp.set_attr(T=Ref(hs_eva2int_heatex, 1, deltaT_int_heatex)) + + # solve the actual network + hp.nw.solve('design') + hp.nw.print_results() + + # calculate and print the actual COP + cop = abs( + cons_heatsink.P.val + / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val) + ) + print(f'COP = {cop:.4}') From 3147a28025ce5964b722005679bf566e8d04647e Mon Sep 17 00:00:00 2001 From: maltefritz Date: Thu, 9 Jun 2022 12:50:36 +0200 Subject: [PATCH 010/120] Add starting value tutorial link in tutorials/examples. --- docs/tutorials_examples.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/tutorials_examples.rst b/docs/tutorials_examples.rst index 3ed461421..73b0e7399 100644 --- a/docs/tutorials_examples.rst +++ b/docs/tutorials_examples.rst @@ -69,6 +69,8 @@ with respect to the extraction pressure levels. .. _heat_pump_tutorial_label: .. include:: tutorials_examples/tutorial_heat_pump.rst +.. _starting_values_tutorial_label: +.. include:: tutorials_examples/tutorial_starting_values.rst .. _combustion_chamber_tutorial_label: .. include:: tutorials_examples/tutorial_combustion_chamber.rst .. _pygmo_tutorial_label: From e7463cf71f69d091adc0eeb985d5ac549ae170a8 Mon Sep 17 00:00:00 2001 From: maltefritz Date: Thu, 9 Jun 2022 12:58:29 +0200 Subject: [PATCH 011/120] Change tutorial introduction. --- docs/tutorials_examples.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/tutorials_examples.rst b/docs/tutorials_examples.rst index 73b0e7399..030eddf80 100644 --- a/docs/tutorials_examples.rst +++ b/docs/tutorials_examples.rst @@ -51,12 +51,13 @@ on github. Additional small examples can be found in the API-documentation. Tutorials ========= -We provide two different tutorials for you to better understand how to work +We provide tutorials for you to better understand how to work with TESPy. You will learn how to create basic models and get the idea of designing a plant and simulating the offdesign behavior in the heat pump -tutorial. On top of that, we created a tutorial for the usage of the combustion -chamber: It is an important component for thermal power plants while being a -source for many errors in the calculation. +tutorial. Furthermore, the starting values tutorial will help you to get a +stable simulation and faster solutions. On top of that, we created a tutorial +for the usage of the combustion chamber: It is an important component for +thermal power plants while being a source for many errors in the calculation. The last tutorial is a plant design optimization tutorial. A thermal power plant with two extraction stages is optimized in regard of thermal efficiency From 65d985eb935c8740cea2f921ac98eb65cda6d4e1 Mon Sep 17 00:00:00 2001 From: maltefritz Date: Thu, 23 Jun 2022 18:18:50 +0200 Subject: [PATCH 012/120] Change tutorial. --- docs/tutorials_examples/tutorial_starting_values.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/tutorials_examples/tutorial_starting_values.rst b/docs/tutorials_examples/tutorial_starting_values.rst index 1f3de6e12..56b23c0dc 100644 --- a/docs/tutorials_examples/tutorial_starting_values.rst +++ b/docs/tutorials_examples/tutorial_starting_values.rst @@ -280,14 +280,14 @@ other unstable values can be set for the actual simulation. heatsource_evaporator.set_attr(ttd_l=5) cond2int_heatex.set_attr(p=None) - condenserset_attr(ttd_u=5) + condenser.set_attr(ttd_u=5) int_heatex2valve.set_attr(h=None) - int_heatex2comp.set_attr(T=Ref(hs_eva2int_heatex, 1, deltaT_int_heatex)) + int_heatex2comp.set_attr(T=Ref(hs_eva2int_heatex, 1, 10)) # solve the actual network - hp.nw.solve('design') - hp.nw.print_results() + nw.solve('design') + nw.print_results() # calculate and print the actual COP cop = abs( From a6db47847d12abb0d84cfa7b8b7610b313437437 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Thu, 23 Jun 2022 19:15:42 +0200 Subject: [PATCH 013/120] Make minor reformulations --- .../tutorial_starting_values.rst | 108 ++++++++++-------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/docs/tutorials_examples/tutorial_starting_values.rst b/docs/tutorials_examples/tutorial_starting_values.rst index 56b23c0dc..61c294d3d 100644 --- a/docs/tutorials_examples/tutorial_starting_values.rst +++ b/docs/tutorials_examples/tutorial_starting_values.rst @@ -6,26 +6,31 @@ Starting value tutorial :local: :backlinks: top -Subjekt +Subject ^^^^^^^ - -In numerical and iterative methods, a start value is a certain value of a -variable with which a calculation is started. With more complex TESPy models -it can happen that the simulation does not convert. The numerics of the solver -is vulnerable if the specified variables are not primary variables. These are -variables that can be solved after one iteration. For example, pressures, -temperatures and enthalpies are among to them. Because of that it is -recommended to give these parameter for your simulation. +Applying numerical algorithms and methods, the starting value of a variable +is the value used for the first iteration. With more complex TESPy models +it can happen that the simulation does not converge easily due to a combination +of "bad" starting values. The solver is especially vulnerable if the specified +parameters trigger complex equations with respect to the primary variables. +The primary variables of TESPy are mass flow, pressure, enthalpy and fluid +composition. If such a value is directly specified by the user, the solver has +a solution for this value before starting the first iteration. Therefore, +specifying a set of parameters largely including primary variables will improve +the convergence significantly. Based on the converged solution of a initial +simulation, it is then possible to adjust the parameters, for example, unsetting +pressure values and specifying efficiencies instead. We provide an example for +you to better understand, how this process could look like. Task ^^^^ - After learning to create simple heat pump with TESPy, the goal is to model -more complex systems. After the successful creation of the network, -components, connections and parameterization, it is often the problem that the -simulation does not convert. +more complex systems. After the successful creation of the network, components, +connections and parameterization, it is often the problem that the simulation +does not converge on the first try, you might know the following error message: .. error:: + Singularity in jacobian matrix, calculation aborted! Make sure your network does not have any linear dependencies in the parametrisation. Other reasons might be @@ -46,22 +51,22 @@ This is used to have suitable starting values for the actual calculation. Application ^^^^^^^^^^^ - -Following the first tutorial a heat pumps with internal heat exchangers is -considered. You can see the plant topology in the figure. +Following the first tutorial a heat pump with internal heat exchangers is +considered instead of dumping the heat to the ambient. You can see the plant +topology in the figure below. .. figure:: api/_images/tutorial_sv_heat_pump_intheatex.svg :align: center Figure: Topology of heat pump with internal heat exchanger -It consists of a consumer system, a valve, an evaporator system, a compressor -and additionally of an internal heat exchanger. -In order to simulate this heat pump, the TESPy model has to be built up. -First, the network has to be initialized and the refrigerants used have to be -specified. In this example the heat pump work with ammonia (NH\ :sub:`3`\) and -water (H\ :sub:`2`\O). Furthermore, it is recommended to define the unit -system not to work with variables set to SI-Units. +The system consists of a consumer system, a valve, an evaporator system, a +compressor and additionally an internal heat exchanger. In order to simulate +this heat pump, the TESPy model has to be built up. First, the network has to +be initialized and the refrigerants used have to be specified. In this example +the heat pump works with ammonia (NH\ :sub:`3`\) and water (H\ :sub:`2`\O). + +First, we set up the Network object. .. code-block:: python @@ -73,7 +78,7 @@ system not to work with variables set to SI-Units. T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s' ) -After that the required components have to be created. +After that, the required components are created. .. code-block:: python @@ -109,10 +114,12 @@ After that the required components have to be created. .. note:: If the heat pump operates in a supercritical range, the condenser has to - be replaced with a heat exchanger. + be replaced with a heat exchanger, as the condenser imposes a boundary + condition, which cannot be true for supercritical fluids: The outlet of the + condensing fluid is in saturated state. -Now the connections according to the topology have to be linked. For a better -overview of the results it is recommended to label the connections. +Now the connections are set up. For a better overview of the results we +recommend labeling the connections individually. .. code-block:: python @@ -166,7 +173,7 @@ overview of the results it is recommended to label the connections. nw.add_conns(int_heatex2valve, valve2cc) After the initialization of the network and the creation of the components and -connections, a stable parameterization is built up to have suitable initial +connections, a stable parameterization is set up to have suitable initial values for the actual simulation. .. note:: @@ -181,7 +188,8 @@ values for the actual simulation. recommended to specify the pressure in order to clearly determine the point. On the other hand the point behind the condenser is fixed, too. At these point the ammonia has a vapor content of 0% (x=0). As before, the - pressure value has also to be set. + pressure value has also to be set. Obviously, this should be a higher value + than the evaporation pressure. .. figure:: api/_images/tutorial_sv_logph.svg :align: center @@ -193,8 +201,8 @@ used, the feedflow and backflow temperatures of the consumer and heat source as well as the enthalpy between internal heat exchanger and valve have to be defined. -To correctly determine the enthalpies and pressures, CoolProp is to be -imported. It is important to note that the PropertySI function (PropsSI) works +To correctly determine the enthalpies and pressures, we can import CoolProp +directly. It is important to note that the PropertySI function (PropsSI) uses with SI unit. These may differ from the units defined in the network. .. code-block:: python @@ -229,10 +237,10 @@ with SI unit. These may differ from the units defined in the network. hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, 'NH3': 0}) hs_eva2hs_back.set_attr(T=T_hs_bf, p=1) -Some components have to be parameterized. For the heat source and heat sink -recirculation pump as well as the conedenser the isentropic efficiency is to -be set. Further we set the pressure ratios on hot and cold side for the -condenser, evaporator and internal heat exchanger. The consumer will have +Some components have to be parameterized. For example, the heat source and heat +sink recirculation pump as well as the compressor isentropic efficiency values +are typically set. Further we set the pressure ratios on hot and cold side for +the condenser, evaporator and internal heat exchanger. The consumer will have pressure losses, too. .. code-block:: python @@ -249,9 +257,12 @@ pressure losses, too. cons_heatsink.set_attr(pr=0.99) int_heatex.set_attr(pr1=0.99, pr2=0.99) -The most important parameter is the consumers heat demand setting as -“key parameter”. After that the network can be solved and a stable simulation -can be used for further simulations. +A key design value of a heat pump is of course the heat transferred to the +heat consumer. Especially for more complex systems (e.g. if heat is not +transferred in a single heat exchanger, but by multiple parallel or in line +heat exchangers), instead of setting the total heat provided, we can set the +district heating mass flow. Since the mass flow is a primary variable in TESPy +this improves the convergence significantly. .. code-block:: python @@ -260,18 +271,12 @@ can be used for further simulations. # solve the network nw.solve('design') - nw.print_results() - # calculate and print COP - cop = abs( - cons_heatsink.P.val - / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val) - ) - print(f'COP = {cop:.4}') - -After that, enthalpies and pressures can be set as "None" and the desired -values for the upper or lower terminal temperature differences, references or -other unstable values can be set for the actual simulation. +After having generated a stable solution of the model, parameters which have +been set for convergence support can be unset and replaced by the actual target +parameters. For example, the desired values for the upper or lower terminal +temperature differences of heat exchangers, referenced values or the heat +demand. .. code-block:: python @@ -295,3 +300,8 @@ other unstable values can be set for the actual simulation. / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val) ) print(f'COP = {cop:.4}') + +You can use this strategy as well, in case you solve a network instance +multiple times with changing input parameters: If a simulation does not converge +reload the stable starting values by providing the :code:`init_path` to the +:code:`solve` command. From 67c7ec7d20f890a83d8c0d2445a87b9d2a881c13 Mon Sep 17 00:00:00 2001 From: maltefritz Date: Mon, 27 Jun 2022 15:30:03 +0200 Subject: [PATCH 014/120] Update the figure of internal heat pump and add lables. --- .../tutorial_sv_heat_pump_intheatex.svg | 1229 ++++++----------- 1 file changed, 408 insertions(+), 821 deletions(-) diff --git a/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg b/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg index 2dc4af84d..af9bfc862 100644 --- a/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg +++ b/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg @@ -9,9 +9,9 @@ xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="88.70771mm" - height="130.68996mm" - viewBox="0 0 88.70771 130.68996" + width="88.112389mm" + height="145.33812mm" + viewBox="0 0 88.112388 145.33812" version="1.1" id="svg8" inkscape:version="0.92.4 (5da689c313, 2019-01-14)" @@ -26,20 +26,27 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1.4142136" - inkscape:cx="-179.65255" - inkscape:cy="165.30212" + inkscape:cx="159.14984" + inkscape:cy="291.2912" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="false" - inkscape:window-width="2560" - inkscape:window-height="1369" - inkscape:window-x="2552" - inkscape:window-y="10" + inkscape:window-width="1920" + inkscape:window-height="1009" + inkscape:window-x="1912" + inkscape:window-y="185" inkscape:window-maximized="1" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" - fit-margin-bottom="0" /> + fit-margin-bottom="0" + showguides="true"> + + @@ -48,7 +55,7 @@ image/svg+xml - + @@ -56,861 +63,441 @@ inkscape:label="Ebene 1" inkscape:groupmode="layer" id="layer1" - transform="translate(3.283484,-169.12813)"> - - - - - - + transform="translate(3.9626441,-153.12611)"> + transform="rotate(180,148.6359,23.164291)" + id="g2293-1" + inkscape:export-xdpi="1012" + inkscape:export-ydpi="1012" + style="stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"> - - - + sodipodi:nodetypes="ccccccc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 268.7345,-139.2486 -8.2333,-0.0292 3e-5,-18.00001 -4.5,4 -4.5,-4 -1e-5,18 -7.76672,0.0292" + id="path984-0-9-9-9" /> - - - - - + id="rect986-1-1-0-2" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" + d="m 248.50123,-161.77777 14.99999,1e-5 v 15 h -15 z" + sodipodi:nodetypes="ccccc" /> + + transform="rotate(-90,121.04029,288.00296)" + id="g1624-4-7-0-3-8" + inkscape:export-filename="C:\Users\meinm\Documents\1 Uni\8. Semester SS20\1 Bachelorarbeit\Inhalt\Abbildungen\SEGSvi_Tespy.png" + inkscape:export-xdpi="1012" + inkscape:export-ydpi="1012" + style="stroke-linecap:round;stroke-linejoin:round"> + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 149.5,198.5 -3.6,-7.5 h 7.2 l -3.6,-7.5" + id="path960-8-0-25-4-8-6-6" + sodipodi:nodetypes="cccc" /> + inkscape:connector-curvature="0" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 31.537322,252.04325 H 16.537323 v 15.00002 h 14.999999 z" + id="path1057-2-7-1" + sodipodi:nodetypes="ccccc" /> + + + + + + + + transform="rotate(180,154.83574,52.635129)" + id="g2293-1-2" + inkscape:export-xdpi="1012" + inkscape:export-ydpi="1012" + style="stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"> - - + sodipodi:nodetypes="ccccccc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 308.13418,-115.30693 h -48 l 0.36705,-41.97084 -4.5,4 -4.5,-4 -0.36705,48.97084 h 57" + id="path984-0-9-9-9-74" /> - - - - - - - - - - - - - - - - - - - + id="rect986-1-1-0-2-2" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" + d="m 248.50123,-161.77777 14.99999,1e-5 v 15 h -15 z" + sodipodi:nodetypes="ccccc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 46.053353,259.54326 H 31.514174" + id="path984-0-9-9-9-7-0-1-5" /> + inkscape:connector-curvature="0" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M -3.4626774,242.95219 H 6.5373224 L -1.4626774,227.9522 h 6 z" + id="path1057-2-6-6-9" + sodipodi:nodetypes="ccccc" /> - - - - - - - - - - - - - - - - - - - - - + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" + style="fill:none;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 16.038483,259.54326 H 1.5290226 l 0.0083,-6.96607" + id="path984-0-9-9-9-7-0-1-5-2" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 1.5348226,227.3528 0.0025,-6.7756" + id="path984-0-9-9-9-7-0-1-9" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 1.5373226,213.57719 v -13" + id="path984-0-9-9-9-7-0-1-52" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.49999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 75.932133,200.57719 H 48.541013" + id="path984-0-9-9-9-7-0-1-5-0-8" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 61.372083,259.57719 H 75.911262" + id="path984-0-9-9-9-7-0-1-5-3" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 28.537323,200.57719 H 1.5373226" + id="path984-0-9-9-9-7-0-1-5-0-8-4" /> + - - - - - + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 61.037324,171.57719 -7.500001,7 -7.500001,-7" + id="path979-02-5-4" + sodipodi:nodetypes="ccc" /> - - - - - - + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 53.537323,185.57719 0.005,-6.49288" + id="path984-0-9-9-9-7-0-1-59" /> - - - - - - - - - - - + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.49999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 28.537323,185.57719 0.005,-6.49288" + id="path984-0-9-9-9-7-0-1-59-3" /> + + + + + + + + + + 0 1 2 4 5 6 11 12 13 21 24 22 23 + + + + 3 + transform="translate(-8.3664549,-166.82401)"> - - - - - + transform="translate(16.846111,-210.47783)"> + transform="translate(21.846111,-210.47783)"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - expansion valve compressor heat sink train heat sourcetrain internal heatexchanger + From 72c912b72070748cd3f1dfdaefbb672ab597fb3b Mon Sep 17 00:00:00 2001 From: maltefritz Date: Tue, 28 Jun 2022 09:42:09 +0200 Subject: [PATCH 015/120] Update the labeling of the connections and improve the description. --- .../tutorial_starting_values.rst | 76 +++++++------------ 1 file changed, 29 insertions(+), 47 deletions(-) diff --git a/docs/tutorials_examples/tutorial_starting_values.rst b/docs/tutorials_examples/tutorial_starting_values.rst index 61c294d3d..a0b231d18 100644 --- a/docs/tutorials_examples/tutorial_starting_values.rst +++ b/docs/tutorials_examples/tutorial_starting_values.rst @@ -126,52 +126,35 @@ recommend labeling the connections individually. from tespy.connections import Connection # connections - # heat source - cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='cc2hs_eva') - hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='hs_feed2hs_pump') - hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='hs_pump2hs_eva') - hs_eva2hs_back = Connection( - heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='hs_eva2hs_back' - ) - - nw.add_conns(cc2hs_eva, hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back) - - # internal heat exchange cold side - hs_eva2int_heatex = Connection( - heatsource_evaporator, 'out2', int_heatex, 'in2', label='hs_eva2int_heatex' + # main cycle + cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0') + hs_eva2int_heatex = Connection(heatsource_evaporator, 'out2', int_heatex, 'in2', label='1') + int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='2') + comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='3') + cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='4') + int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='5') + valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='6') + + nw.add_conns( + cc2hs_eva, hs_eva2int_heatex, int_heatex2comp, comp2cond, cond2int_heatex, + int_heatex2valve, valve2cc ) - nw.add_conns(hs_eva2int_heatex) - - # compression - int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='int_heatex2comp') - comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='comp2cond') + # heat source + hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='11') + hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='12') + hs_eva2hs_back = Connection(heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='13') - nw.add_conns(int_heatex2comp, comp2cond) + nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back) # heat sink - cons_back2cons_pump = Connection( - cons_cycle_closer, 'out1', cons_pump, 'in1', label='cons_back2cons_pump' - ) - cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='cons_pump2cond') - cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='cond2cons_hs') - cons_hs2cons_feed = Connection( - cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='cons_hs2cons_feed' - ) + cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='21') + cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='22') + cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='23') + cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='24') nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed) - # internal heat exchange hot side - cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='cond2int_heatex') - - nw.add_conns(cond2int_heatex) - - # expansion - int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='int_heatex2valve') - valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='valve2cc') - - nw.add_conns(int_heatex2valve, valve2cc) - After the initialization of the network and the creation of the components and connections, a stable parameterization is set up to have suitable initial values for the actual simulation. @@ -202,8 +185,8 @@ as well as the enthalpy between internal heat exchanger and valve have to be defined. To correctly determine the enthalpies and pressures, we can import CoolProp -directly. It is important to note that the PropertySI function (PropsSI) uses -with SI unit. These may differ from the units defined in the network. +directly. It is important to note that the PropertySI function (PropsSI) is +used with SI unit. These may differ from the units defined in the network. .. code-block:: python @@ -217,14 +200,13 @@ with SI unit. These may differ from the units defined in the network. T_cons_ff = 90 # evaporation point - h_eva = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273, 'NH3') * 1e-3 p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273, 'NH3') * 1e-5 hs_eva2int_heatex.set_attr(x=1, p=p_eva) # condensation point - h_cond = CP.PropsSI('H', 'Q', 0, 'T', T_cons_ff + 5 + 273, 'NH3') * 1e-3 p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273, 'NH3') * 1e-5 cond2int_heatex.set_attr(p=p_cond) + h_cond = CP.PropsSI('H', 'Q', 0, 'T', T_cons_ff + 5 + 273, 'NH3') * 1e-3 # internal heat exchanger to valve int_heatex2valve.set_attr(h=h_cond * 0.99, fluid={'water': 0, 'NH3': 1}) @@ -252,10 +234,10 @@ pressure losses, too. compressor.set_attr(eta_s=0.85) # pressure ratios - condenser.set_attr(pr1=0.99, pr2=0.99) + condenser.set_attr(pr1=0.98, pr2=0.98) heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98) cons_heatsink.set_attr(pr=0.99) - int_heatex.set_attr(pr1=0.99, pr2=0.99) + int_heatex.set_attr(pr1=0.98, pr2=0.98) A key design value of a heat pump is of course the heat transferred to the heat consumer. Especially for more complex systems (e.g. if heat is not @@ -302,6 +284,6 @@ demand. print(f'COP = {cop:.4}') You can use this strategy as well, in case you solve a network instance -multiple times with changing input parameters: If a simulation does not converge -reload the stable starting values by providing the :code:`init_path` to the -:code:`solve` command. +multiple times with changing input parameters: If a simulation does not +converge reload the stable starting values by providing the +:code:`init_path` to the :code:`solve` command. \ No newline at end of file From 837e79745d8913a9a6235461202448056133c609 Mon Sep 17 00:00:00 2001 From: maltefritz Date: Tue, 28 Jun 2022 15:07:55 +0200 Subject: [PATCH 016/120] Fix a wrong component in figure: replace pump with compressor. --- .../tutorial_sv_heat_pump_intheatex.svg | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg b/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg index af9bfc862..2e40f9199 100644 --- a/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg +++ b/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg @@ -26,15 +26,15 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1.4142136" - inkscape:cx="159.14984" - inkscape:cy="291.2912" + inkscape:cx="628.89809" + inkscape:cy="224.99126" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="false" - inkscape:window-width="1920" - inkscape:window-height="1009" - inkscape:window-x="1912" - inkscape:window-y="185" + inkscape:window-width="3840" + inkscape:window-height="2054" + inkscape:window-x="3829" + inkscape:window-y="7" inkscape:window-maximized="1" fit-margin-top="0" fit-margin-left="0" @@ -55,7 +55,7 @@ image/svg+xml - + @@ -442,20 +442,7 @@ height="15.118111" x="536.12317" y="299.52753" />23 - - 23 3 + id="flowPara1543-9-0">3 + + + Date: Sun, 3 Jul 2022 14:38:17 +0200 Subject: [PATCH 017/120] Add option for custom keywords in variable definitions --- src/tespy/tools/optimization.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index d61f48cd7..c24c2f548 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -143,10 +143,15 @@ def __init__(self, model, variables={}, constraints={}, objective="objective"): self.bounds = [[], []] for obj, data in self.variables.items(): for label, params in data.items(): - for param in params: - self.bounds[0] += [self.variables[obj][label][param]['min']] - self.bounds[1] += [self.variables[obj][label][param]['max']] - self.variable_list += [obj + '-' + label + '-' + param] + if obj in ["Connections", "Components"]: + for param in params: + self.bounds[0] += [self.variables[obj][label][param]['min']] + self.bounds[1] += [self.variables[obj][label][param]['max']] + self.variable_list += [obj + '-' + label + '-' + param] + else: + self.bounds[0] += [self.variables[obj][label]['min']] + self.bounds[1] += [self.variables[obj][label]['max']] + self.variable_list += [obj + '-' + label] self.input_dict = self.variables.copy() @@ -186,8 +191,12 @@ def fitness(self, x): i = 0 for obj, data in self.variables.items(): for label, params in data.items(): - for param in params: - self.input_dict[obj][label][param] = x[i] + if obj in ["Connections", "Components"]: + for param in params: + self.input_dict[obj][label][param] = x[i] + i += 1 + else: + self.input_dict[obj][label] = x[i] i += 1 self.model.solve_model(**self.input_dict) From edd06dc9a5daf69d529c0a1337d1864e62e8ad02 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 3 Jul 2022 18:35:47 +0200 Subject: [PATCH 018/120] Add tutorial notebook to replace rst --- docs/tutorials_examples/starting_values.ipynb | 557 ++++++++++++++++++ 1 file changed, 557 insertions(+) create mode 100644 docs/tutorials_examples/starting_values.ipynb diff --git a/docs/tutorials_examples/starting_values.ipynb b/docs/tutorials_examples/starting_values.ipynb new file mode 100644 index 000000000..a31305b81 --- /dev/null +++ b/docs/tutorials_examples/starting_values.ipynb @@ -0,0 +1,557 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Generating Good Starting Values\n", + "\n", + "Applying numerical algorithms and methods, the starting value of a variable\n", + "is the value used for the first iteration. With more complex TESPy models\n", + "it can happen that the simulation does not converge easily due to a combination\n", + "of \"bad\" starting values. The solver is especially vulnerable if the specified\n", + "parameters trigger complex equations with respect to the primary variables.\n", + "The primary variables of TESPy are mass flow, pressure, enthalpy and fluid\n", + "composition. If such a value is directly specified by the user, the solver has\n", + "a solution for this value before starting the first iteration. Therefore,\n", + "specifying a set of parameters largely including primary variables will improve\n", + "the convergence significantly. Based on the converged solution of a initial\n", + "simulation, it is then possible to adjust the parameters, for example, unsetting\n", + "pressure values and specifying efficiencies instead. We provide an example for\n", + "you to better understand, how this process could look like.\n", + "\n", + "## Topology of the heat pump\n", + "\n", + "Following the first tutorial a slightly different topology for a heat pump with\n", + "internal heat exchangers is considered instead of dumping the heat to the\n", + "ambient. You can see the plant topology in the figure below.\n", + "\n", + "![Topology](api/_images/tutorial_sv_heat_pump_intheatex.svg)\n", + "\n", + "The system consists of a consumer system, a valve, an evaporator system, a\n", + "compressor and additionally an internal heat exchanger. In order to simulate\n", + "this heat pump, the TESPy model has to be built up. First, the network has to\n", + "be initialized and the refrigerants used have to be specified. This example\n", + "shows how to make the heat pump model work with a variety of working fluids with\n", + "water on both the heat source and heat sink side of the system.\n", + "\n", + "As always, we start by importing the necessary TESPy classes." + ] + }, + { + "cell_type": "code", + "execution_count": 144, + "metadata": {}, + "outputs": [], + "source": [ + "from tespy.networks import Network\n", + "\n", + "from tespy.components import (\n", + " Condenser, Compressor, CycleCloser, HeatExchanger,\n", + " HeatExchangerSimple, Pump, Sink, Source, Valve\n", + " )\n", + "\n", + "from tespy.connections import Connection, Ref, Bus" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we can build the network by defining components and connections. The \n", + "working fluid will be set with the variable `wf`, `\"NH3\"` is used in the first\n", + "setup. This way, we will be able to change the working fluid in a flexible way." + ] + }, + { + "cell_type": "code", + "execution_count": 145, + "metadata": {}, + "outputs": [], + "source": [ + "wf = 'R290'\n", + "\n", + "# network\n", + "nw = Network(\n", + " fluids=['water', wf],\n", + " T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s'\n", + " )\n", + "\n", + "# components\n", + "cycle_closer = CycleCloser('Refrigerant Cycle Closer')\n", + "\n", + "# heat source\n", + "heatsource_feedflow = Source('Heat Source Feed Flow')\n", + "heatsource_pump = Pump('Heat Source Recirculation Pump')\n", + "heatsource_evaporator = HeatExchanger('Heat Source Evaporator')\n", + "heatsource_backflow = Sink('Heat Source Back Flow')\n", + "\n", + "# compression\n", + "compressor = Compressor('Compressor')\n", + "\n", + "# heat sink\n", + "cons_pump = Pump('Heat Sink Recirculation Pump')\n", + "condenser = Condenser('Heat Sink Condenser')\n", + "cons_heatsink = HeatExchangerSimple('Heat Consumer')\n", + "cons_cycle_closer = CycleCloser('Consumer Feed Flow')\n", + "\n", + "# internal heat exchange\n", + "int_heatex = HeatExchanger('Internal Heat Exchanger')\n", + "\n", + "# expansion\n", + "valve = Valve('Expansion Valve')\n", + "\n", + "# connections\n", + "# main cycle\n", + "cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0')\n", + "hs_eva2int_heatex = Connection(heatsource_evaporator, 'out2', int_heatex, 'in2', label='1')\n", + "int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='2')\n", + "comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='3')\n", + "cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='4')\n", + "int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='5')\n", + "valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='6')\n", + "\n", + "nw.add_conns(\n", + " cc2hs_eva, hs_eva2int_heatex, int_heatex2comp, comp2cond, cond2int_heatex,\n", + " int_heatex2valve, valve2cc\n", + " )\n", + "\n", + "# heat source\n", + "hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='11')\n", + "hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='12')\n", + "hs_eva2hs_back = Connection(heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='13')\n", + "\n", + "nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back)\n", + "\n", + "# heat sink\n", + "cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='21')\n", + "cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='22')\n", + "cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='23')\n", + "cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='24')\n", + "\n", + "nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After setting up the topology, the system's parameters should be set in the\n", + "following way:\n", + "\n", + "- Heat sink temperature levels (`T` at 23 and 24)\n", + "- Heat source temperature levels (`T` at 11 and 13)\n", + "- Degree of overheating after the internal heat exchanger (`Td_bp` at 2)\n", + "- Pinch point temperature difference at the evaporator (`ttd_l`) to derive \n", + " evaporation pressure\n", + "- Temperature difference at the condenser (`ttd_u`) to derive condensation\n", + " pressure\n", + "- Saturated gaseous state of the working fluid (`x=1`) after leaving the\n", + " evaporator\n", + "- Efficiencies of pumps and the compressor (`eta_s`)\n", + "- Pressure losses in all heat exchangers (`pr1`, `pr2`, `pr`)\n", + "- Consumer heat demand (`Q`)\n", + "\n", + "Please note:\n", + "\n", + "If the heat pump operates in a supercritical range, the condenser has to\n", + "be replaced with a heat exchanger, as the condenser imposes a boundary\n", + "condition, which cannot be true for supercritical fluids: The outlet of\n", + "the condensing fluid is in saturated state." + ] + }, + { + "cell_type": "code", + "execution_count": 146, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:root:Singularity in jacobian matrix, calculation aborted! Make sure your network does not have any linear dependencies in the parametrisation. Other reasons might be\n", + "-> given temperature with given pressure in two phase region, try setting enthalpy instead or provide accurate starting value for pressure.\n", + "-> given logarithmic temperature differences or kA-values for heat exchangers, \n", + "-> support better starting values.\n", + "-> bad starting value for fuel mass flow of combustion chamber, provide small (near to zero, but not zero) starting value.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iter\t| residual | massflow | pressure | enthalpy | fluid\n", + "--------+----------+----------+----------+----------+---------\n", + "1\t| 9.43e+06 | nan | nan | nan | nan\n", + "--------+----------+----------+----------+----------+---------\n", + "Total iterations: 1, Calculation time: 0.0 s, Iterations per second: 95.17\n" + ] + } + ], + "source": [ + "# parametrization connections\n", + "# set feedflow and backflow temperature of heat source and consumer\n", + "T_hs_bf = 5\n", + "T_hs_ff = 10\n", + "T_cons_bf = 50\n", + "T_cons_ff = 90\n", + "\n", + "# consumer cycle\n", + "cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, wf: 0})\n", + "cons_hs2cons_feed.set_attr(T=T_cons_bf)\n", + "\n", + "# heat source cycle\n", + "hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, wf: 0})\n", + "hs_eva2hs_back.set_attr(T=T_hs_bf, p=1)\n", + "\n", + "# evaporation to fully saturated gas\n", + "hs_eva2int_heatex.set_attr(x=1, fluid={'water': 0, wf: 1})\n", + "# degree of overheating after internal heat exchanger (evaporation side)\n", + "int_heatex2comp.set_attr(Td_bp=10)\n", + "\n", + "# parametrization components\n", + "# isentropic efficiency\n", + "cons_pump.set_attr(eta_s=0.8)\n", + "heatsource_pump.set_attr(eta_s=0.8)\n", + "compressor.set_attr(eta_s=0.85)\n", + "\n", + "# pressure ratios\n", + "condenser.set_attr(pr1=0.98, pr2=0.98)\n", + "heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98)\n", + "cons_heatsink.set_attr(pr=0.99)\n", + "int_heatex.set_attr(pr1=0.98, pr2=0.98)\n", + "\n", + "# temperature differences\n", + "heatsource_evaporator.set_attr(ttd_l=5)\n", + "condenser.set_attr(ttd_u=5)\n", + "\n", + "# consumer heat demand\n", + "cons_heatsink.set_attr(Q=-1e6)\n", + "\n", + "nw.solve('design')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The system should be well defined with the parameter settings, however no\n", + "solution can be found. To generate good starting values for the simulation, it\n", + "is recommended to set pressure and enthalpy values instead of temperature\n", + "differences. In this example, fixed points can be identified with the help of\n", + "the logph diagram which you can see in the figure below.\n", + "\n", + "![logph](api/_images/tutorial_sv_logph.svg)\n", + "\n", + "A rough estimation of the evaporation and condensation pressure can be obtained\n", + "and will be used to replace the temperature differences at the evaporator and\n", + "the condenser for the starting value generator. After condensation, the working\n", + "fluid is in saturated liquid state. We can retrieve the condensation pressure\n", + "corresponding to a temperature slightly below the heat sink temperature by using\n", + "the CoolProp `PropsSI` interface with the respective inputs. The same step can\n", + "be carried out on the heat source side. For the internal heat exchanger, an\n", + "enthalpy value is specified instead of the temperature difference to the boiling\n", + "point as well. It is important to note that the PropertySI function (PropsSI) is\n", + "used with SI units, which differ from the units defined in the network.\n", + "\n", + "The temperature difference values are unset and pressure and enthalpy values are\n", + "set instead." + ] + }, + { + "cell_type": "code", + "execution_count": 147, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iter\t| residual | massflow | pressure | enthalpy | fluid\n", + "--------+----------+----------+----------+----------+---------\n", + "1\t| 1.03e+07 | 5.27e+01 | 8.27e+06 | 1.21e+07 | 0.00e+00\n", + "2\t| 1.96e+07 | 1.10e+02 | 3.56e+06 | 9.07e+05 | 0.00e+00\n", + "3\t| 1.38e+07 | 6.67e+01 | 1.41e+06 | 3.52e+05 | 0.00e+00\n", + "4\t| 2.87e+06 | 1.10e+01 | 5.42e+05 | 1.16e+06 | 0.00e+00\n", + "5\t| 1.36e+06 | 1.87e-01 | 2.10e+05 | 3.03e+05 | 0.00e+00\n", + "6\t| 5.37e+04 | 3.58e-05 | 5.42e+04 | 1.77e+03 | 0.00e+00\n", + "7\t| 1.88e-02 | 3.23e-05 | 5.82e-11 | 2.35e-02 | 0.00e+00\n", + "8\t| 4.50e-07 | 4.65e-10 | 1.48e-11 | 2.66e-07 | 0.00e+00\n", + "--------+----------+----------+----------+----------+---------\n", + "Total iterations: 8, Calculation time: 0.1 s, Iterations per second: 96.7\n" + ] + } + ], + "source": [ + "import CoolProp.CoolProp as CP\n", + "\n", + "# evaporation point\n", + "p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273, wf) * 1e-5\n", + "hs_eva2int_heatex.set_attr(p=p_eva)\n", + "heatsource_evaporator.set_attr(ttd_l=None)\n", + "\n", + "# condensation point\n", + "p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273, wf) * 1e-5\n", + "cond2int_heatex.set_attr(p=p_cond)\n", + "condenser.set_attr(ttd_u=None)\n", + "\n", + "# internal heat exchanger to compressor enthalpy\n", + "h_evap = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273, wf) * 1e-3\n", + "int_heatex2comp.set_attr(Td_bp=None, h=h_evap * 1.01)\n", + "\n", + "# solve the network again\n", + "nw.solve('design')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The model was solved successfully and has stored the starting values for any\n", + "follow-up. Therefore, we can undo our recent changes and restart the \n", + "simulation. For example, the COP is then calculated." + ] + }, + { + "cell_type": "code", + "execution_count": 148, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iter\t| residual | massflow | pressure | enthalpy | fluid\n", + "--------+----------+----------+----------+----------+---------\n", + "1\t| 1.67e+00 | 2.89e+00 | 1.26e+05 | 2.07e+04 | 0.00e+00\n", + "2\t| 4.94e+03 | 3.80e-01 | 1.30e+03 | 1.64e+03 | 0.00e+00\n", + "3\t| 4.59e+01 | 1.72e-03 | 1.30e-01 | 1.16e-01 | 0.00e+00\n", + "4\t| 1.37e-05 | 6.84e-10 | 1.77e-09 | 7.80e-07 | 0.00e+00\n", + "5\t| 3.78e-09 | 2.30e-10 | 1.68e-09 | 1.56e-07 | 0.00e+00\n", + "--------+----------+----------+----------+----------+---------\n", + "Total iterations: 5, Calculation time: 0.1 s, Iterations per second: 69.0\n", + "COP = 1.611\n" + ] + } + ], + "source": [ + "# evaporation point\n", + "hs_eva2int_heatex.set_attr(p=None)\n", + "heatsource_evaporator.set_attr(ttd_l=5)\n", + "\n", + "# condensation point\n", + "cond2int_heatex.set_attr(p=None)\n", + "condenser.set_attr(ttd_u=5)\n", + "\n", + "# internal heat exchanger superheating\n", + "int_heatex2comp.set_attr(Td_bp=5, h=None)\n", + "\n", + "# solve the network again\n", + "nw.solve('design')\n", + "\n", + "# calculate and print the actual COP\n", + "cop = abs(\n", + " cons_heatsink.Q.val\n", + " / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val)\n", + " )\n", + "print(f'COP = {cop:.4}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, using this strategy, it is possible to build a generic function,\n", + "building a network, that works with a variety of working fluids." + ] + }, + { + "cell_type": "code", + "execution_count": 149, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "R290:, COP = 1.611\n", + "R134a:, COP = 1.788\n", + "NH3:, COP = 2.5\n" + ] + } + ], + "source": [ + "def generate_starting_values(wf):\n", + "\n", + " # network\n", + " nw = Network(\n", + " fluids=['water', wf],\n", + " T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s',\n", + " iterinfo=False\n", + " )\n", + "\n", + " # components\n", + " cycle_closer = CycleCloser('Refrigerant Cycle Closer')\n", + "\n", + " # heat source\n", + " heatsource_feedflow = Source('Heat Source Feed Flow')\n", + " heatsource_pump = Pump('Heat Source Recirculation Pump')\n", + " heatsource_evaporator = HeatExchanger('Heat Source Evaporator')\n", + " heatsource_backflow = Sink('Heat Source Back Flow')\n", + "\n", + " # compression\n", + " compressor = Compressor('Compressor')\n", + "\n", + " # heat sink\n", + " cons_pump = Pump('Heat Sink Recirculation Pump')\n", + " condenser = Condenser('Heat Sink Condenser')\n", + " cons_heatsink = HeatExchangerSimple('Heat Consumer')\n", + " cons_cycle_closer = CycleCloser('Consumer Feed Flow')\n", + "\n", + " # internal heat exchange\n", + " int_heatex = HeatExchanger('Internal Heat Exchanger')\n", + "\n", + " # expansion\n", + " valve = Valve('Expansion Valve')\n", + "\n", + " # connections\n", + " # main cycle\n", + " cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0')\n", + " hs_eva2int_heatex = Connection(heatsource_evaporator, 'out2', int_heatex, 'in2', label='1')\n", + " int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='2')\n", + " comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='3')\n", + " cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='4')\n", + " int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='5')\n", + " valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='6')\n", + "\n", + " nw.add_conns(\n", + " cc2hs_eva, hs_eva2int_heatex, int_heatex2comp, comp2cond, cond2int_heatex,\n", + " int_heatex2valve, valve2cc\n", + " )\n", + "\n", + " # heat source\n", + " hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='11')\n", + " hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='12')\n", + " hs_eva2hs_back = Connection(heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='13')\n", + "\n", + " nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back)\n", + "\n", + " # heat sink\n", + " cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='21')\n", + " cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='22')\n", + " cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='23')\n", + " cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='24')\n", + "\n", + " nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed)\n", + "\n", + " # set feedflow and backflow temperature of heat source and consumer\n", + " T_hs_bf = 5\n", + " T_hs_ff = 10\n", + " T_cons_bf = 50\n", + " T_cons_ff = 90\n", + "\n", + " # consumer cycle\n", + " cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, wf: 0})\n", + " cons_hs2cons_feed.set_attr(T=T_cons_bf)\n", + "\n", + " # heat source cycle\n", + " hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, wf: 0})\n", + " hs_eva2hs_back.set_attr(T=T_hs_bf, p=1)\n", + "\n", + " # evaporation to fully saturated gas\n", + " hs_eva2int_heatex.set_attr(x=1, fluid={'water': 0, wf: 1})\n", + "\n", + " # parametrization components\n", + " # isentropic efficiency\n", + " cons_pump.set_attr(eta_s=0.8)\n", + " heatsource_pump.set_attr(eta_s=0.8)\n", + " compressor.set_attr(eta_s=0.85)\n", + "\n", + " # pressure ratios\n", + " condenser.set_attr(pr1=0.98, pr2=0.98)\n", + " heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98)\n", + " cons_heatsink.set_attr(pr=0.99)\n", + " int_heatex.set_attr(pr1=0.98, pr2=0.98)\n", + "\n", + " # evaporation point\n", + " p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273, wf) * 1e-5\n", + " hs_eva2int_heatex.set_attr(p=p_eva)\n", + "\n", + " # condensation point\n", + " p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273, wf) * 1e-5\n", + " cond2int_heatex.set_attr(p=p_cond)\n", + "\n", + " # internal heat exchanger to compressor enthalpy\n", + " h_evap = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273, wf) * 1e-3\n", + " int_heatex2comp.set_attr(h=h_evap * 1.01)\n", + "\n", + " # consumer heat demand\n", + " cons_heatsink.set_attr(Q=-1e6)\n", + "\n", + " power_bus = Bus('Total power input')\n", + " heat_bus = Bus('Total heat production')\n", + " power_bus.add_comps(\n", + " {'comp': compressor, 'base': 'bus'},\n", + " {'comp': cons_pump, 'base': 'bus'},\n", + " {'comp': heatsource_pump, 'base': 'bus'},\n", + " )\n", + " heat_bus.add_comps({'comp': cons_heatsink})\n", + "\n", + " nw.add_busses(power_bus, heat_bus)\n", + "\n", + " nw.solve('design')\n", + "\n", + " # evaporation point\n", + " hs_eva2int_heatex.set_attr(p=None)\n", + " heatsource_evaporator.set_attr(ttd_l=5)\n", + "\n", + " # condensation point\n", + " cond2int_heatex.set_attr(p=None)\n", + " condenser.set_attr(ttd_u=5)\n", + "\n", + " # internal heat exchanger superheating\n", + " int_heatex2comp.set_attr(Td_bp=5, h=None)\n", + "\n", + " # solve the network again\n", + " nw.solve('design')\n", + "\n", + " return nw\n", + "\n", + "\n", + "for wf in ['R290', 'R134a', 'NH3']:\n", + " nw = generate_starting_values(wf)\n", + "\n", + " power = nw.busses['Total power input'].P.val\n", + " heat = abs(nw.busses['Total heat production'].P.val)\n", + " print(f'{wf}:, COP = {(heat / power):.4}')\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.13 ('tespy_env')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "44908eb5e87e7bc48e01cf0d18465c2e636786f26841f6d7e2abea66a64385ca" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 92348c43a4e4b038ac4571526bcd2537c1f54a90 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 14 Aug 2022 12:06:40 +0200 Subject: [PATCH 019/120] Add some headings, remove ipynb again --- docs/tutorials_examples/starting_values.ipynb | 557 ------------------ .../tutorial_starting_values.rst | 482 ++++++++++----- 2 files changed, 342 insertions(+), 697 deletions(-) delete mode 100644 docs/tutorials_examples/starting_values.ipynb diff --git a/docs/tutorials_examples/starting_values.ipynb b/docs/tutorials_examples/starting_values.ipynb deleted file mode 100644 index a31305b81..000000000 --- a/docs/tutorials_examples/starting_values.ipynb +++ /dev/null @@ -1,557 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generating Good Starting Values\n", - "\n", - "Applying numerical algorithms and methods, the starting value of a variable\n", - "is the value used for the first iteration. With more complex TESPy models\n", - "it can happen that the simulation does not converge easily due to a combination\n", - "of \"bad\" starting values. The solver is especially vulnerable if the specified\n", - "parameters trigger complex equations with respect to the primary variables.\n", - "The primary variables of TESPy are mass flow, pressure, enthalpy and fluid\n", - "composition. If such a value is directly specified by the user, the solver has\n", - "a solution for this value before starting the first iteration. Therefore,\n", - "specifying a set of parameters largely including primary variables will improve\n", - "the convergence significantly. Based on the converged solution of a initial\n", - "simulation, it is then possible to adjust the parameters, for example, unsetting\n", - "pressure values and specifying efficiencies instead. We provide an example for\n", - "you to better understand, how this process could look like.\n", - "\n", - "## Topology of the heat pump\n", - "\n", - "Following the first tutorial a slightly different topology for a heat pump with\n", - "internal heat exchangers is considered instead of dumping the heat to the\n", - "ambient. You can see the plant topology in the figure below.\n", - "\n", - "![Topology](api/_images/tutorial_sv_heat_pump_intheatex.svg)\n", - "\n", - "The system consists of a consumer system, a valve, an evaporator system, a\n", - "compressor and additionally an internal heat exchanger. In order to simulate\n", - "this heat pump, the TESPy model has to be built up. First, the network has to\n", - "be initialized and the refrigerants used have to be specified. This example\n", - "shows how to make the heat pump model work with a variety of working fluids with\n", - "water on both the heat source and heat sink side of the system.\n", - "\n", - "As always, we start by importing the necessary TESPy classes." - ] - }, - { - "cell_type": "code", - "execution_count": 144, - "metadata": {}, - "outputs": [], - "source": [ - "from tespy.networks import Network\n", - "\n", - "from tespy.components import (\n", - " Condenser, Compressor, CycleCloser, HeatExchanger,\n", - " HeatExchangerSimple, Pump, Sink, Source, Valve\n", - " )\n", - "\n", - "from tespy.connections import Connection, Ref, Bus" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then, we can build the network by defining components and connections. The \n", - "working fluid will be set with the variable `wf`, `\"NH3\"` is used in the first\n", - "setup. This way, we will be able to change the working fluid in a flexible way." - ] - }, - { - "cell_type": "code", - "execution_count": 145, - "metadata": {}, - "outputs": [], - "source": [ - "wf = 'R290'\n", - "\n", - "# network\n", - "nw = Network(\n", - " fluids=['water', wf],\n", - " T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s'\n", - " )\n", - "\n", - "# components\n", - "cycle_closer = CycleCloser('Refrigerant Cycle Closer')\n", - "\n", - "# heat source\n", - "heatsource_feedflow = Source('Heat Source Feed Flow')\n", - "heatsource_pump = Pump('Heat Source Recirculation Pump')\n", - "heatsource_evaporator = HeatExchanger('Heat Source Evaporator')\n", - "heatsource_backflow = Sink('Heat Source Back Flow')\n", - "\n", - "# compression\n", - "compressor = Compressor('Compressor')\n", - "\n", - "# heat sink\n", - "cons_pump = Pump('Heat Sink Recirculation Pump')\n", - "condenser = Condenser('Heat Sink Condenser')\n", - "cons_heatsink = HeatExchangerSimple('Heat Consumer')\n", - "cons_cycle_closer = CycleCloser('Consumer Feed Flow')\n", - "\n", - "# internal heat exchange\n", - "int_heatex = HeatExchanger('Internal Heat Exchanger')\n", - "\n", - "# expansion\n", - "valve = Valve('Expansion Valve')\n", - "\n", - "# connections\n", - "# main cycle\n", - "cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0')\n", - "hs_eva2int_heatex = Connection(heatsource_evaporator, 'out2', int_heatex, 'in2', label='1')\n", - "int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='2')\n", - "comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='3')\n", - "cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='4')\n", - "int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='5')\n", - "valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='6')\n", - "\n", - "nw.add_conns(\n", - " cc2hs_eva, hs_eva2int_heatex, int_heatex2comp, comp2cond, cond2int_heatex,\n", - " int_heatex2valve, valve2cc\n", - " )\n", - "\n", - "# heat source\n", - "hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='11')\n", - "hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='12')\n", - "hs_eva2hs_back = Connection(heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='13')\n", - "\n", - "nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back)\n", - "\n", - "# heat sink\n", - "cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='21')\n", - "cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='22')\n", - "cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='23')\n", - "cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='24')\n", - "\n", - "nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "After setting up the topology, the system's parameters should be set in the\n", - "following way:\n", - "\n", - "- Heat sink temperature levels (`T` at 23 and 24)\n", - "- Heat source temperature levels (`T` at 11 and 13)\n", - "- Degree of overheating after the internal heat exchanger (`Td_bp` at 2)\n", - "- Pinch point temperature difference at the evaporator (`ttd_l`) to derive \n", - " evaporation pressure\n", - "- Temperature difference at the condenser (`ttd_u`) to derive condensation\n", - " pressure\n", - "- Saturated gaseous state of the working fluid (`x=1`) after leaving the\n", - " evaporator\n", - "- Efficiencies of pumps and the compressor (`eta_s`)\n", - "- Pressure losses in all heat exchangers (`pr1`, `pr2`, `pr`)\n", - "- Consumer heat demand (`Q`)\n", - "\n", - "Please note:\n", - "\n", - "If the heat pump operates in a supercritical range, the condenser has to\n", - "be replaced with a heat exchanger, as the condenser imposes a boundary\n", - "condition, which cannot be true for supercritical fluids: The outlet of\n", - "the condensing fluid is in saturated state." - ] - }, - { - "cell_type": "code", - "execution_count": 146, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:root:Singularity in jacobian matrix, calculation aborted! Make sure your network does not have any linear dependencies in the parametrisation. Other reasons might be\n", - "-> given temperature with given pressure in two phase region, try setting enthalpy instead or provide accurate starting value for pressure.\n", - "-> given logarithmic temperature differences or kA-values for heat exchangers, \n", - "-> support better starting values.\n", - "-> bad starting value for fuel mass flow of combustion chamber, provide small (near to zero, but not zero) starting value.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "iter\t| residual | massflow | pressure | enthalpy | fluid\n", - "--------+----------+----------+----------+----------+---------\n", - "1\t| 9.43e+06 | nan | nan | nan | nan\n", - "--------+----------+----------+----------+----------+---------\n", - "Total iterations: 1, Calculation time: 0.0 s, Iterations per second: 95.17\n" - ] - } - ], - "source": [ - "# parametrization connections\n", - "# set feedflow and backflow temperature of heat source and consumer\n", - "T_hs_bf = 5\n", - "T_hs_ff = 10\n", - "T_cons_bf = 50\n", - "T_cons_ff = 90\n", - "\n", - "# consumer cycle\n", - "cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, wf: 0})\n", - "cons_hs2cons_feed.set_attr(T=T_cons_bf)\n", - "\n", - "# heat source cycle\n", - "hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, wf: 0})\n", - "hs_eva2hs_back.set_attr(T=T_hs_bf, p=1)\n", - "\n", - "# evaporation to fully saturated gas\n", - "hs_eva2int_heatex.set_attr(x=1, fluid={'water': 0, wf: 1})\n", - "# degree of overheating after internal heat exchanger (evaporation side)\n", - "int_heatex2comp.set_attr(Td_bp=10)\n", - "\n", - "# parametrization components\n", - "# isentropic efficiency\n", - "cons_pump.set_attr(eta_s=0.8)\n", - "heatsource_pump.set_attr(eta_s=0.8)\n", - "compressor.set_attr(eta_s=0.85)\n", - "\n", - "# pressure ratios\n", - "condenser.set_attr(pr1=0.98, pr2=0.98)\n", - "heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98)\n", - "cons_heatsink.set_attr(pr=0.99)\n", - "int_heatex.set_attr(pr1=0.98, pr2=0.98)\n", - "\n", - "# temperature differences\n", - "heatsource_evaporator.set_attr(ttd_l=5)\n", - "condenser.set_attr(ttd_u=5)\n", - "\n", - "# consumer heat demand\n", - "cons_heatsink.set_attr(Q=-1e6)\n", - "\n", - "nw.solve('design')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The system should be well defined with the parameter settings, however no\n", - "solution can be found. To generate good starting values for the simulation, it\n", - "is recommended to set pressure and enthalpy values instead of temperature\n", - "differences. In this example, fixed points can be identified with the help of\n", - "the logph diagram which you can see in the figure below.\n", - "\n", - "![logph](api/_images/tutorial_sv_logph.svg)\n", - "\n", - "A rough estimation of the evaporation and condensation pressure can be obtained\n", - "and will be used to replace the temperature differences at the evaporator and\n", - "the condenser for the starting value generator. After condensation, the working\n", - "fluid is in saturated liquid state. We can retrieve the condensation pressure\n", - "corresponding to a temperature slightly below the heat sink temperature by using\n", - "the CoolProp `PropsSI` interface with the respective inputs. The same step can\n", - "be carried out on the heat source side. For the internal heat exchanger, an\n", - "enthalpy value is specified instead of the temperature difference to the boiling\n", - "point as well. It is important to note that the PropertySI function (PropsSI) is\n", - "used with SI units, which differ from the units defined in the network.\n", - "\n", - "The temperature difference values are unset and pressure and enthalpy values are\n", - "set instead." - ] - }, - { - "cell_type": "code", - "execution_count": 147, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "iter\t| residual | massflow | pressure | enthalpy | fluid\n", - "--------+----------+----------+----------+----------+---------\n", - "1\t| 1.03e+07 | 5.27e+01 | 8.27e+06 | 1.21e+07 | 0.00e+00\n", - "2\t| 1.96e+07 | 1.10e+02 | 3.56e+06 | 9.07e+05 | 0.00e+00\n", - "3\t| 1.38e+07 | 6.67e+01 | 1.41e+06 | 3.52e+05 | 0.00e+00\n", - "4\t| 2.87e+06 | 1.10e+01 | 5.42e+05 | 1.16e+06 | 0.00e+00\n", - "5\t| 1.36e+06 | 1.87e-01 | 2.10e+05 | 3.03e+05 | 0.00e+00\n", - "6\t| 5.37e+04 | 3.58e-05 | 5.42e+04 | 1.77e+03 | 0.00e+00\n", - "7\t| 1.88e-02 | 3.23e-05 | 5.82e-11 | 2.35e-02 | 0.00e+00\n", - "8\t| 4.50e-07 | 4.65e-10 | 1.48e-11 | 2.66e-07 | 0.00e+00\n", - "--------+----------+----------+----------+----------+---------\n", - "Total iterations: 8, Calculation time: 0.1 s, Iterations per second: 96.7\n" - ] - } - ], - "source": [ - "import CoolProp.CoolProp as CP\n", - "\n", - "# evaporation point\n", - "p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273, wf) * 1e-5\n", - "hs_eva2int_heatex.set_attr(p=p_eva)\n", - "heatsource_evaporator.set_attr(ttd_l=None)\n", - "\n", - "# condensation point\n", - "p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273, wf) * 1e-5\n", - "cond2int_heatex.set_attr(p=p_cond)\n", - "condenser.set_attr(ttd_u=None)\n", - "\n", - "# internal heat exchanger to compressor enthalpy\n", - "h_evap = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273, wf) * 1e-3\n", - "int_heatex2comp.set_attr(Td_bp=None, h=h_evap * 1.01)\n", - "\n", - "# solve the network again\n", - "nw.solve('design')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The model was solved successfully and has stored the starting values for any\n", - "follow-up. Therefore, we can undo our recent changes and restart the \n", - "simulation. For example, the COP is then calculated." - ] - }, - { - "cell_type": "code", - "execution_count": 148, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "iter\t| residual | massflow | pressure | enthalpy | fluid\n", - "--------+----------+----------+----------+----------+---------\n", - "1\t| 1.67e+00 | 2.89e+00 | 1.26e+05 | 2.07e+04 | 0.00e+00\n", - "2\t| 4.94e+03 | 3.80e-01 | 1.30e+03 | 1.64e+03 | 0.00e+00\n", - "3\t| 4.59e+01 | 1.72e-03 | 1.30e-01 | 1.16e-01 | 0.00e+00\n", - "4\t| 1.37e-05 | 6.84e-10 | 1.77e-09 | 7.80e-07 | 0.00e+00\n", - "5\t| 3.78e-09 | 2.30e-10 | 1.68e-09 | 1.56e-07 | 0.00e+00\n", - "--------+----------+----------+----------+----------+---------\n", - "Total iterations: 5, Calculation time: 0.1 s, Iterations per second: 69.0\n", - "COP = 1.611\n" - ] - } - ], - "source": [ - "# evaporation point\n", - "hs_eva2int_heatex.set_attr(p=None)\n", - "heatsource_evaporator.set_attr(ttd_l=5)\n", - "\n", - "# condensation point\n", - "cond2int_heatex.set_attr(p=None)\n", - "condenser.set_attr(ttd_u=5)\n", - "\n", - "# internal heat exchanger superheating\n", - "int_heatex2comp.set_attr(Td_bp=5, h=None)\n", - "\n", - "# solve the network again\n", - "nw.solve('design')\n", - "\n", - "# calculate and print the actual COP\n", - "cop = abs(\n", - " cons_heatsink.Q.val\n", - " / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val)\n", - " )\n", - "print(f'COP = {cop:.4}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, using this strategy, it is possible to build a generic function,\n", - "building a network, that works with a variety of working fluids." - ] - }, - { - "cell_type": "code", - "execution_count": 149, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "R290:, COP = 1.611\n", - "R134a:, COP = 1.788\n", - "NH3:, COP = 2.5\n" - ] - } - ], - "source": [ - "def generate_starting_values(wf):\n", - "\n", - " # network\n", - " nw = Network(\n", - " fluids=['water', wf],\n", - " T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s',\n", - " iterinfo=False\n", - " )\n", - "\n", - " # components\n", - " cycle_closer = CycleCloser('Refrigerant Cycle Closer')\n", - "\n", - " # heat source\n", - " heatsource_feedflow = Source('Heat Source Feed Flow')\n", - " heatsource_pump = Pump('Heat Source Recirculation Pump')\n", - " heatsource_evaporator = HeatExchanger('Heat Source Evaporator')\n", - " heatsource_backflow = Sink('Heat Source Back Flow')\n", - "\n", - " # compression\n", - " compressor = Compressor('Compressor')\n", - "\n", - " # heat sink\n", - " cons_pump = Pump('Heat Sink Recirculation Pump')\n", - " condenser = Condenser('Heat Sink Condenser')\n", - " cons_heatsink = HeatExchangerSimple('Heat Consumer')\n", - " cons_cycle_closer = CycleCloser('Consumer Feed Flow')\n", - "\n", - " # internal heat exchange\n", - " int_heatex = HeatExchanger('Internal Heat Exchanger')\n", - "\n", - " # expansion\n", - " valve = Valve('Expansion Valve')\n", - "\n", - " # connections\n", - " # main cycle\n", - " cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0')\n", - " hs_eva2int_heatex = Connection(heatsource_evaporator, 'out2', int_heatex, 'in2', label='1')\n", - " int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='2')\n", - " comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='3')\n", - " cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='4')\n", - " int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='5')\n", - " valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='6')\n", - "\n", - " nw.add_conns(\n", - " cc2hs_eva, hs_eva2int_heatex, int_heatex2comp, comp2cond, cond2int_heatex,\n", - " int_heatex2valve, valve2cc\n", - " )\n", - "\n", - " # heat source\n", - " hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='11')\n", - " hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='12')\n", - " hs_eva2hs_back = Connection(heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='13')\n", - "\n", - " nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back)\n", - "\n", - " # heat sink\n", - " cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='21')\n", - " cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='22')\n", - " cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='23')\n", - " cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='24')\n", - "\n", - " nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed)\n", - "\n", - " # set feedflow and backflow temperature of heat source and consumer\n", - " T_hs_bf = 5\n", - " T_hs_ff = 10\n", - " T_cons_bf = 50\n", - " T_cons_ff = 90\n", - "\n", - " # consumer cycle\n", - " cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, wf: 0})\n", - " cons_hs2cons_feed.set_attr(T=T_cons_bf)\n", - "\n", - " # heat source cycle\n", - " hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, wf: 0})\n", - " hs_eva2hs_back.set_attr(T=T_hs_bf, p=1)\n", - "\n", - " # evaporation to fully saturated gas\n", - " hs_eva2int_heatex.set_attr(x=1, fluid={'water': 0, wf: 1})\n", - "\n", - " # parametrization components\n", - " # isentropic efficiency\n", - " cons_pump.set_attr(eta_s=0.8)\n", - " heatsource_pump.set_attr(eta_s=0.8)\n", - " compressor.set_attr(eta_s=0.85)\n", - "\n", - " # pressure ratios\n", - " condenser.set_attr(pr1=0.98, pr2=0.98)\n", - " heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98)\n", - " cons_heatsink.set_attr(pr=0.99)\n", - " int_heatex.set_attr(pr1=0.98, pr2=0.98)\n", - "\n", - " # evaporation point\n", - " p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273, wf) * 1e-5\n", - " hs_eva2int_heatex.set_attr(p=p_eva)\n", - "\n", - " # condensation point\n", - " p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273, wf) * 1e-5\n", - " cond2int_heatex.set_attr(p=p_cond)\n", - "\n", - " # internal heat exchanger to compressor enthalpy\n", - " h_evap = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273, wf) * 1e-3\n", - " int_heatex2comp.set_attr(h=h_evap * 1.01)\n", - "\n", - " # consumer heat demand\n", - " cons_heatsink.set_attr(Q=-1e6)\n", - "\n", - " power_bus = Bus('Total power input')\n", - " heat_bus = Bus('Total heat production')\n", - " power_bus.add_comps(\n", - " {'comp': compressor, 'base': 'bus'},\n", - " {'comp': cons_pump, 'base': 'bus'},\n", - " {'comp': heatsource_pump, 'base': 'bus'},\n", - " )\n", - " heat_bus.add_comps({'comp': cons_heatsink})\n", - "\n", - " nw.add_busses(power_bus, heat_bus)\n", - "\n", - " nw.solve('design')\n", - "\n", - " # evaporation point\n", - " hs_eva2int_heatex.set_attr(p=None)\n", - " heatsource_evaporator.set_attr(ttd_l=5)\n", - "\n", - " # condensation point\n", - " cond2int_heatex.set_attr(p=None)\n", - " condenser.set_attr(ttd_u=5)\n", - "\n", - " # internal heat exchanger superheating\n", - " int_heatex2comp.set_attr(Td_bp=5, h=None)\n", - "\n", - " # solve the network again\n", - " nw.solve('design')\n", - "\n", - " return nw\n", - "\n", - "\n", - "for wf in ['R290', 'R134a', 'NH3']:\n", - " nw = generate_starting_values(wf)\n", - "\n", - " power = nw.busses['Total power input'].P.val\n", - " heat = abs(nw.busses['Total heat production'].P.val)\n", - " print(f'{wf}:, COP = {(heat / power):.4}')\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.8.13 ('tespy_env')", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.13" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "44908eb5e87e7bc48e01cf0d18465c2e636786f26841f6d7e2abea66a64385ca" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/docs/tutorials_examples/tutorial_starting_values.rst b/docs/tutorials_examples/tutorial_starting_values.rst index a0b231d18..af3285f94 100644 --- a/docs/tutorials_examples/tutorial_starting_values.rst +++ b/docs/tutorials_examples/tutorial_starting_values.rst @@ -1,59 +1,41 @@ -Starting value tutorial ------------------------ +Stable starting values for subcritical heat pumps +------------------------------------------------- .. contents:: :depth: 1 :local: :backlinks: top -Subject -^^^^^^^ Applying numerical algorithms and methods, the starting value of a variable is the value used for the first iteration. With more complex TESPy models it can happen that the simulation does not converge easily due to a combination of "bad" starting values. The solver is especially vulnerable if the specified parameters trigger complex equations with respect to the primary variables. + The primary variables of TESPy are mass flow, pressure, enthalpy and fluid composition. If such a value is directly specified by the user, the solver has a solution for this value before starting the first iteration. Therefore, specifying a set of parameters largely including primary variables will improve the convergence significantly. Based on the converged solution of a initial simulation, it is then possible to adjust the parameters, for example, unsetting -pressure values and specifying efficiencies instead. We provide an example for -you to better understand, how this process could look like. - -Task -^^^^ -After learning to create simple heat pump with TESPy, the goal is to model -more complex systems. After the successful creation of the network, components, -connections and parameterization, it is often the problem that the simulation -does not converge on the first try, you might know the following error message: - -.. error:: - - Singularity in jacobian matrix, calculation aborted! Make sure - your network does not have any linear dependencies in the parametrisation. - Other reasons might be - - -> given temperature with given pressure in two phase region, try setting - enthalpy instead or provide accurate starting value for pressure. +pressure values and specifying efficiencies instead. - -> given logarithmic temperature differences or kA-values for heat - exchangers. +Here we provide a short tutorial for you to better understand, how this process +could look like at the example of a subcritical heat pump with different working +fluids. - -> support better starting values. +.. info:: - -> bad starting value for fuel mass flow of combustion chamber, provide - small (near to zero, but not zero) starting value. + If the heat pump operates in trans- or supercritical range, some + modifications have to be made on this setup. We plan to include respective + examples here in the future. -To fix this error, it is recommended to create a stable calculation first. -This is used to have suitable starting values for the actual calculation. +Topology of the heat pump +^^^^^^^^^^^^^^^^^^^^^^^^^ -Application -^^^^^^^^^^^ -Following the first tutorial a heat pump with internal heat exchangers is -considered instead of dumping the heat to the ambient. You can see the plant -topology in the figure below. +Following the first tutorial a slightly different topology for a heat pump with +internal heat exchangers is considered instead of dumping the heat to the +ambient. You can see the plant topology in the figure below. .. figure:: api/_images/tutorial_sv_heat_pump_intheatex.svg :align: center @@ -63,28 +45,38 @@ topology in the figure below. The system consists of a consumer system, a valve, an evaporator system, a compressor and additionally an internal heat exchanger. In order to simulate this heat pump, the TESPy model has to be built up. First, the network has to -be initialized and the refrigerants used have to be specified. In this example -the heat pump works with ammonia (NH\ :sub:`3`\) and water (H\ :sub:`2`\O). +be initialized and the refrigerants used have to be specified. This example +shows how to make the heat pump model work with a variety of working fluids with +water on both the heat source and heat sink side of the system. -First, we set up the Network object. +Running into errors +^^^^^^^^^^^^^^^^^^^ + +As always, we start by importing the necessary TESPy classes. .. code-block:: python from tespy.networks import Network - # network - nw = Network( - fluids=['water', 'NH3'], - T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s' + from tespy.components import ( + Condenser, Compressor, CycleCloser, HeatExchanger, + HeatExchangerSimple, Pump, Sink, Source, Valve ) -After that, the required components are created. + from tespy.connections import Connection, Ref, Bus + +Then, we can build the network by defining components and connections. The +working fluid will be set with the variable `wf`, `"NH3"` is used in the first +setup. This way, we will be able to change the working fluid in a flexible way. .. code-block:: python - from tespy.components import ( - Condenser, Compressor, CycleCloser, HeatExchanger, - HeatExchangerSimple, Pump, Sink, Source, Valve + wf = 'NH3' + + # network + nw = Network( + fluids=['water', wf], + T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s' ) # components @@ -111,20 +103,6 @@ After that, the required components are created. # expansion valve = Valve('Expansion Valve') -.. note:: - - If the heat pump operates in a supercritical range, the condenser has to - be replaced with a heat exchanger, as the condenser imposes a boundary - condition, which cannot be true for supercritical fluids: The outlet of the - condensing fluid is in saturated state. - -Now the connections are set up. For a better overview of the results we -recommend labeling the connections individually. - -.. code-block:: python - - from tespy.connections import Connection - # connections # main cycle cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0') @@ -155,77 +133,43 @@ recommend labeling the connections individually. nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed) -After the initialization of the network and the creation of the components and -connections, a stable parameterization is set up to have suitable initial -values for the actual simulation. - -.. note:: - - To create a stable simulation, it is recommended to set pressure and - enthalpie values instead of temperature values. In this example, fixed - points can be identified with the help of the logph diagram which you can - see in the figure. - - On the one hand the point behind the evaporator is fixed. At this point - the vapor content of the ammonia is at 100% (x=1). Furthermore, it is - recommended to specify the pressure in order to clearly determine the - point. On the other hand the point behind the condenser is fixed, too. - At these point the ammonia has a vapor content of 0% (x=0). As before, the - pressure value has also to be set. Obviously, this should be a higher value - than the evaporation pressure. - -.. figure:: api/_images/tutorial_sv_logph.svg - :align: center - - Figure: Logph diagram of ammonia - -In addition to the fixed evaporation and condensation points, the fluids to be -used, the feedflow and backflow temperatures of the consumer and heat source -as well as the enthalpy between internal heat exchanger and valve have to be -defined. - -To correctly determine the enthalpies and pressures, we can import CoolProp -directly. It is important to note that the PropertySI function (PropsSI) is -used with SI unit. These may differ from the units defined in the network. +After setting up the topology, the system's parameters should be set in the +following way: + +- Heat sink temperature levels (`T` at 23 and 24) +- Heat source temperature levels (`T` at 11 and 13) +- Degree of overheating after the internal heat exchanger (`Td_bp` at 2) +- Pinch point temperature difference at the evaporator (`ttd_l`) to derive + evaporation pressure +- Temperature difference at the condenser (`ttd_u`) to derive condensation + pressure +- Saturated gaseous state of the working fluid (`x=1`) after leaving the + evaporator +- Efficiencies of pumps and the compressor (`eta_s`) +- Pressure losses in all heat exchangers (`pr1`, `pr2`, `pr`) +- Consumer heat demand (`Q`) .. code-block:: python - import CoolProp.CoolProp as CP - # parametrization connections # set feedflow and backflow temperature of heat source and consumer - T_hs_bf = 5 - T_hs_ff = 10 + T_hs_bf = 10 + T_hs_ff = 15 T_cons_bf = 50 T_cons_ff = 90 - # evaporation point - p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273, 'NH3') * 1e-5 - hs_eva2int_heatex.set_attr(x=1, p=p_eva) - - # condensation point - p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273, 'NH3') * 1e-5 - cond2int_heatex.set_attr(p=p_cond) - h_cond = CP.PropsSI('H', 'Q', 0, 'T', T_cons_ff + 5 + 273, 'NH3') * 1e-3 - - # internal heat exchanger to valve - int_heatex2valve.set_attr(h=h_cond * 0.99, fluid={'water': 0, 'NH3': 1}) - # consumer cycle - cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, 'NH3': 0}) + cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, wf: 0}) cons_hs2cons_feed.set_attr(T=T_cons_bf) # heat source cycle - hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, 'NH3': 0}) + hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, wf: 0}) hs_eva2hs_back.set_attr(T=T_hs_bf, p=1) -Some components have to be parameterized. For example, the heat source and heat -sink recirculation pump as well as the compressor isentropic efficiency values -are typically set. Further we set the pressure ratios on hot and cold side for -the condenser, evaporator and internal heat exchanger. The consumer will have -pressure losses, too. - -.. code-block:: python + # evaporation to fully saturated gas + hs_eva2int_heatex.set_attr(x=1, fluid={'water': 0, wf: 1}) + # degree of overheating after internal heat exchanger (evaporation side) + int_heatex2comp.set_attr(Td_bp=10) # parametrization components # isentropic efficiency @@ -239,51 +183,309 @@ pressure losses, too. cons_heatsink.set_attr(pr=0.99) int_heatex.set_attr(pr1=0.98, pr2=0.98) -A key design value of a heat pump is of course the heat transferred to the -heat consumer. Especially for more complex systems (e.g. if heat is not -transferred in a single heat exchanger, but by multiple parallel or in line -heat exchangers), instead of setting the total heat provided, we can set the -district heating mass flow. Since the mass flow is a primary variable in TESPy -this improves the convergence significantly. + # temperature differences + heatsource_evaporator.set_attr(ttd_l=5) + condenser.set_attr(ttd_u=5) + + # consumer heat demand + cons_heatsink.set_attr(Q=-1e6) + + nw.solve('design') + +The system should be well defined with the parameter settings, however no +solution can be found. We might run in some error, like + +.. error:: + + ERROR:root:Singularity in jacobian matrix, calculation aborted! Make sure + your network does not have any linear dependencies in the parametrisation. + Other reasons might be + + -> given temperature with given pressure in two phase region, try setting + enthalpy instead or provide accurate starting value for pressure. + + -> given logarithmic temperature differences or kA-values for heat + exchangers, + + -> support better starting values. + + -> bad starting value for fuel mass flow of combustion chamber, provide + small (near to zero, but not zero) starting value. + +or simply not making progress in the convergence + +.. error:: + + WARNING:root:The solver does not seem to make any progress, aborting + calculation. Residual value is 7.43e+05. This frequently happens, if the + solver pushes the fluid properties out of their feasible range. + +Fixing the errors +^^^^^^^^^^^^^^^^^ + +To generate good starting values for the simulation, it is recommended to set +pressure and enthalpy values instead of temperature differences. In this +example, fixed points can be identified with the help of the logph diagram +which you can see in the figure below. + +.. figure:: api/_images/tutorial_sv_logph.svg + :align: center + + Figure: Logph diagram of ammonia + +A rough estimation of the evaporation and condensation pressure can be obtained +and will be used to replace the temperature differences at the evaporator and +the condenser for the starting value generator. After condensation, the working +fluid is in saturated liquid state. We can retrieve the condensation pressure +corresponding to a temperature slightly below the heat sink temperature by using +the CoolProp `PropsSI` interface with the respective inputs. The same step can +be carried out on the heat source side. For the internal heat exchanger, an +enthalpy value is specified instead of the temperature difference to the boiling +point as well. It is important to note that the PropertySI function (PropsSI) is +used with SI units, which differ from the units defined in the network. + +The temperature difference values are unset and pressure and enthalpy values are +set instead. .. code-block:: python - # key parameter - cons_heatsink.set_attr(P.val=-1e6) + import CoolProp.CoolProp as CP + + # evaporation point + p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-5 + hs_eva2int_heatex.set_attr(p=p_eva) + heatsource_evaporator.set_attr(ttd_l=None) - # solve the network + # condensation point + p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273.15, wf) * 1e-5 + cond2int_heatex.set_attr(p=p_cond) + condenser.set_attr(ttd_u=None) + + # internal heat exchanger to compressor enthalpy + h_evap = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-3 + int_heatex2comp.set_attr(Td_bp=None, h=h_evap * 1.01) + + # solve the network again nw.solve('design') -After having generated a stable solution of the model, parameters which have -been set for convergence support can be unset and replaced by the actual target -parameters. For example, the desired values for the upper or lower terminal -temperature differences of heat exchangers, referenced values or the heat -demand. + +The model was solved successfully and has stored the starting values for any +follow-up. Therefore, we can undo our recent changes and restart the +simulation. For example, the COP is then calculated. .. code-block:: python - # parametrization for the actual simulation + # evaporation point hs_eva2int_heatex.set_attr(p=None) heatsource_evaporator.set_attr(ttd_l=5) + # condensation point cond2int_heatex.set_attr(p=None) condenser.set_attr(ttd_u=5) - int_heatex2valve.set_attr(h=None) - int_heatex2comp.set_attr(T=Ref(hs_eva2int_heatex, 1, 10)) + # internal heat exchanger superheating + int_heatex2comp.set_attr(Td_bp=5, h=None) - # solve the actual network + # solve the network again nw.solve('design') - nw.print_results() # calculate and print the actual COP cop = abs( - cons_heatsink.P.val + cons_heatsink.Q.val / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val) ) print(f'COP = {cop:.4}') -You can use this strategy as well, in case you solve a network instance -multiple times with changing input parameters: If a simulation does not -converge reload the stable starting values by providing the -:code:`init_path` to the :code:`solve` command. \ No newline at end of file + +.. code-block:: bash + + COP = 2.584 + +Expand fix to any working fluids +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Finally, using this strategy, it is possible to build a generic function, +building a network, that works with a variety of working fluids. + +.. code-block:: python + + import matplotlib.pyplot as plt + import pandas as pd + + from tespy.networks import Network + from tespy.components import ( + Condenser, Compressor, CycleCloser, HeatExchanger, + HeatExchangerSimple, Pump, Sink, Source, Valve + ) + from tespy.connections import Connection, Ref, Bus + import CoolProp.CoolProp as CP + + + def generate_starting_values(wf): + + # network + nw = Network( + fluids=['water', wf], + T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s', + iterinfo=False + ) + + # components + cycle_closer = CycleCloser('Refrigerant Cycle Closer') + + # heat source + heatsource_feedflow = Source('Heat Source Feed Flow') + heatsource_pump = Pump('Heat Source Recirculation Pump') + heatsource_evaporator = HeatExchanger('Heat Source Evaporator') + heatsource_backflow = Sink('Heat Source Back Flow') + + # compression + compressor = Compressor('Compressor') + + # heat sink + cons_pump = Pump('Heat Sink Recirculation Pump') + condenser = Condenser('Heat Sink Condenser') + cons_heatsink = HeatExchangerSimple('Heat Consumer') + cons_cycle_closer = CycleCloser('Consumer Feed Flow') + + # internal heat exchange + int_heatex = HeatExchanger('Internal Heat Exchanger') + + # expansion + valve = Valve('Expansion Valve') + + # connections + # main cycle + cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0') + hs_eva2int_heatex = Connection(heatsource_evaporator, 'out2', int_heatex, 'in2', label='1') + int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='2') + comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='3') + cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='4') + int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='5') + valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='6') + + nw.add_conns( + cc2hs_eva, hs_eva2int_heatex, int_heatex2comp, comp2cond, cond2int_heatex, + int_heatex2valve, valve2cc + ) + + # heat source + hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='11') + hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='12') + hs_eva2hs_back = Connection(heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='13') + + nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back) + + # heat sink + cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='21') + cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='22') + cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='23') + cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='24') + + nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed) + + # set feedflow and backflow temperature of heat source and consumer + T_hs_bf = 10 + T_hs_ff = 15 + T_cons_bf = 50 + T_cons_ff = 90 + + # consumer cycle + cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, wf: 0}) + cons_hs2cons_feed.set_attr(T=T_cons_bf) + + # heat source cycle + hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, wf: 0}) + hs_eva2hs_back.set_attr(T=T_hs_bf, p=1) + + # evaporation to fully saturated gas + hs_eva2int_heatex.set_attr(x=1, fluid={'water': 0, wf: 1}) + + # parametrization components + # isentropic efficiency + cons_pump.set_attr(eta_s=0.8) + heatsource_pump.set_attr(eta_s=0.8) + compressor.set_attr(eta_s=0.85) + + # pressure ratios + condenser.set_attr(pr1=0.98, pr2=0.98) + heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98) + cons_heatsink.set_attr(pr=0.99) + int_heatex.set_attr(pr1=0.98, pr2=0.98) + + # evaporation point + p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-5 + hs_eva2int_heatex.set_attr(p=p_eva) + + # condensation point + p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273.15, wf) * 1e-5 + cond2int_heatex.set_attr(p=p_cond) + + # internal heat exchanger to compressor enthalpy + h_evap = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-3 + int_heatex2comp.set_attr(h=h_evap * 1.01) + + # consumer heat demand + cons_heatsink.set_attr(Q=-1e6) + + power_bus = Bus('Total power input') + heat_bus = Bus('Total heat production') + power_bus.add_comps( + {'comp': compressor, 'base': 'bus'}, + {'comp': cons_pump, 'base': 'bus'}, + {'comp': heatsource_pump, 'base': 'bus'}, + ) + heat_bus.add_comps({'comp': cons_heatsink}) + + nw.add_busses(power_bus, heat_bus) + + nw.solve('design') + + # evaporation point + hs_eva2int_heatex.set_attr(p=None) + heatsource_evaporator.set_attr(ttd_l=5) + + # condensation point + cond2int_heatex.set_attr(p=None) + condenser.set_attr(ttd_u=5) + + # internal heat exchanger superheating + int_heatex2comp.set_attr(Td_bp=5, h=None) + + # solve the network again + nw.solve('design') + + return nw + + + cop = pd.DataFrame(columns=["COP"]) + + for wf in ['NH3', 'R22', 'R134a', 'R152a', 'R290', 'R718']: + nw = generate_starting_values(wf) + + power = nw.busses['Total power input'].P.val + heat = abs(nw.busses['Total heat production'].P.val) + cop.loc[wf] = heat / power + + + fig, ax = plt.subplots(1) + + cop.plot.bar(ax=ax, legend=False) + + ax.set_axisbelow(True) + ax.yaxis.grid(linestyle='dashed') + ax.set_xlabel('Name of working fluid') + ax.set_ylabel('Coefficicent of performance') + ax.set_title('Coefficicent of performance for different working fluids') + plt.tight_layout() + + fig.savefig('tutorial_sv_COP_by_wf.svg') + + +.. figure:: api/_images/tutorial_sv_COP_by_wf.svg + :align: center + + Figure: Topology of heat pump with internal heat exchanger + +Of course, there are different strategies, which include building the plant +step by step and successively adding more and more components. From 5eb0eaddc3f669f4302955a62e6f4640ccb725f7 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 14 Aug 2022 12:32:20 +0200 Subject: [PATCH 020/120] Fix broken links and add COP results figure --- docs/api/_images/tutorial_sv_COP_by_wf.svg | 1181 +++++++++++++++++ .../tutorial_sv_heat_pump_intheatex.svg | 945 +++++++------ docs/api/tespy.data.rst | 2 + docs/tespy_modules/characteristics.rst | 2 +- docs/tespy_modules/components.rst | 2 +- docs/tespy_modules/networks.rst | 2 +- docs/tutorials_examples/combustion_engine.rst | 2 +- .../tutorials_examples/tutorial_heat_pump.rst | 2 +- .../tutorial_starting_values.rst | 51 +- docs/whats_new/v0-2-0.rst | 2 +- 10 files changed, 1727 insertions(+), 464 deletions(-) create mode 100644 docs/api/_images/tutorial_sv_COP_by_wf.svg diff --git a/docs/api/_images/tutorial_sv_COP_by_wf.svg b/docs/api/_images/tutorial_sv_COP_by_wf.svg new file mode 100644 index 000000000..143865cc4 --- /dev/null +++ b/docs/api/_images/tutorial_sv_COP_by_wf.svg @@ -0,0 +1,1181 @@ + + + + + + + + 2022-08-14T11:47:38.613328 + image/svg+xml + + + Matplotlib v3.5.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg b/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg index 2e40f9199..476358ddb 100644 --- a/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg +++ b/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg @@ -1,51 +1,99 @@ - - + version="1.1" + viewBox="0 0 156.89704 119.13103" + height="119.13103mm" + width="156.89703mm"> + id="defs2"> + + + + + + + + inkscape:window-y="-8" + inkscape:window-x="-8" + inkscape:window-height="1137" + inkscape:window-width="1920" + inkscape:snap-to-guides="false" + inkscape:guide-bbox="true" + showguides="true" + inkscape:bbox-nodes="false" + inkscape:snap-grids="true" + inkscape:snap-bbox="true" + inkscape:snap-nodes="true" + inkscape:object-paths="true" + inkscape:snap-center="true" + showgrid="true" + inkscape:document-rotation="0" + inkscape:current-layer="layer1" + inkscape:document-units="mm" + inkscape:cy="263.51829" + inkscape:cx="232.77713" + inkscape:zoom="0.70710678" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" + fit-margin-top="5" + fit-margin-left="5" + fit-margin-right="5" + fit-margin-bottom="5" + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false"> + originx="-67.750045" + originy="-38.118973" /> @@ -55,454 +103,487 @@ image/svg+xml - + + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-67.750036,-38.118978)"> + + + + + + + + + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 68.50123,-156.77773 h 15.00001 v 15.00002 H 68.50123 Z" + id="path1057-2-7-1" + sodipodi:nodetypes="ccccc" /> - - + d="m 46.00122,-182.01322 v -17.26454 h 22.733265" + id="path984-0-9-9-9-7-0-1-5-0-8" /> + + + + + + + - - - - - - - - - - + d="m 46.002201,-166.54231 c -0.0033,1.66488 -0.0022,13.75094 -9.81e-4,17.26455 h 22" + id="path984-0-9-9-9-7-6" /> + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + compressor + heat sink + expansion valve + heat source - + 0 0 + 1 1 + 2 2 + 4 3 + 5 4 + 6 5 + 11 6 + 12 11 + 13 12 + 21 13 + 24 20 + 22 21 + 23 - - 22 + 3 - - - - - - - - - - - + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="76.82637" + y="101.8328" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-33-5-0-3-1">23 diff --git a/docs/api/tespy.data.rst b/docs/api/tespy.data.rst index a2a5ad0b7..bb28de9cf 100644 --- a/docs/api/tespy.data.rst +++ b/docs/api/tespy.data.rst @@ -1,3 +1,5 @@ +.. _tespy_data_label: + tespy.data module ================= diff --git a/docs/tespy_modules/characteristics.rst b/docs/tespy_modules/characteristics.rst index 3e1d8f8f8..8c9c7e62e 100644 --- a/docs/tespy_modules/characteristics.rst +++ b/docs/tespy_modules/characteristics.rst @@ -6,7 +6,7 @@ implementation. There two different types of characteristics available in TESPy: lines (:py:class:`CharLine `) and maps (:py:class:`CharMap `). The default characteristics available are to be found in the -:py:mod:`tespy.data` module documentation. +:ref:`tespy_data_label` module documentation. Characteristic lines -------------------- diff --git a/docs/tespy_modules/components.rst b/docs/tespy_modules/components.rst index 78d675c9b..f44da404d 100644 --- a/docs/tespy_modules/components.rst +++ b/docs/tespy_modules/components.rst @@ -195,7 +195,7 @@ Component characteristics Several components integrate parameters using a characteristic function. These parameters come with default characteristics. The default characteristics -available can be found in the :py:mod:`` module. Of course, it is +available can be found in the :ref:`tespy_data_label`. Of course, it is possible to specify your own characteristic functions. .. note:: diff --git a/docs/tespy_modules/networks.rst b/docs/tespy_modules/networks.rst index e0f6bcf18..4fbf2173b 100644 --- a/docs/tespy_modules/networks.rst +++ b/docs/tespy_modules/networks.rst @@ -219,7 +219,7 @@ with zeta values. is calculated as function of the actual mass flow to design mass flow ratio. You can provide your own (measured) data or use the already existing data from TESPy. All standard characteristic functions are available at - :py:mod:`tespy.data`. + :ref:`tespy_data_label`. For connections it works in the same way, e.g. write diff --git a/docs/tutorials_examples/combustion_engine.rst b/docs/tutorials_examples/combustion_engine.rst index 2b27d62a3..975ec94ad 100644 --- a/docs/tutorials_examples/combustion_engine.rst +++ b/docs/tutorials_examples/combustion_engine.rst @@ -7,7 +7,7 @@ as well as two heating outlets and heat losses can be taken into account, too. Power output, heat production and heat losses are all linked to the thermal input of the combustion engine by characteristic lines, which usually are provided by the manufacturer. TESPy provides a set of predefined -characteristics (documented in the :py:class:`` module). +characteristics (documented in the :ref:`tespy_data_label`). .. figure:: /api/_images/CombustionEngine.svg :align: center diff --git a/docs/tutorials_examples/tutorial_heat_pump.rst b/docs/tutorials_examples/tutorial_heat_pump.rst index e91f2da45..e3fc85e56 100644 --- a/docs/tutorials_examples/tutorial_heat_pump.rst +++ b/docs/tutorials_examples/tutorial_heat_pump.rst @@ -298,7 +298,7 @@ heat transfer coefficient as its offdesign parameters. On top of that, the characteristic function of the evaporator should follow the default characteristic line of 'EVAPORATING FLUID' on the cold side and the default line 'DEFAULT' on the hot side. These lines are defined in the -:py:mod:`tespy.data` module. If you want to learn more about handling +:ref:`tespy_data_label`. If you want to learn more about handling characteristic functions you should have a glance at the :ref:`TESPy components section `. The superheater will also use the pressure ratios on hot and cold side. Further we set a value diff --git a/docs/tutorials_examples/tutorial_starting_values.rst b/docs/tutorials_examples/tutorial_starting_values.rst index af3285f94..b4ec4fe5b 100644 --- a/docs/tutorials_examples/tutorial_starting_values.rst +++ b/docs/tutorials_examples/tutorial_starting_values.rst @@ -24,7 +24,7 @@ Here we provide a short tutorial for you to better understand, how this process could look like at the example of a subcritical heat pump with different working fluids. -.. info:: +.. note:: If the heat pump operates in trans- or supercritical range, some modifications have to be made on this setup. We plan to include respective @@ -197,28 +197,33 @@ solution can be found. We might run in some error, like .. error:: - ERROR:root:Singularity in jacobian matrix, calculation aborted! Make sure - your network does not have any linear dependencies in the parametrisation. - Other reasons might be + .. code-block:: bash - -> given temperature with given pressure in two phase region, try setting - enthalpy instead or provide accurate starting value for pressure. + ERROR:root:Singularity in jacobian matrix, calculation aborted! Make + sure your network does not have any linear dependencies in the + parametrisation. Other reasons might be - -> given logarithmic temperature differences or kA-values for heat - exchangers, + -> given temperature with given pressure in two phase region, try + setting enthalpy instead or provide accurate starting value for + pressure. - -> support better starting values. + -> given logarithmic temperature differences or kA-values for heat + exchangers, - -> bad starting value for fuel mass flow of combustion chamber, provide - small (near to zero, but not zero) starting value. + -> support better starting values. + + -> bad starting value for fuel mass flow of combustion chamber, provide + small (near to zero, but not zero) starting value. or simply not making progress in the convergence .. error:: - WARNING:root:The solver does not seem to make any progress, aborting - calculation. Residual value is 7.43e+05. This frequently happens, if the - solver pushes the fluid properties out of their feasible range. + .. code-block:: bash + + WARNING:root:The solver does not seem to make any progress, aborting + calculation. Residual value is 7.43e+05. This frequently happens, if + the solver pushes the fluid properties out of their feasible range. Fixing the errors ^^^^^^^^^^^^^^^^^ @@ -289,17 +294,11 @@ simulation. For example, the COP is then calculated. # solve the network again nw.solve('design') - # calculate and print the actual COP + # calculate the COP cop = abs( cons_heatsink.Q.val / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val) - ) - print(f'COP = {cop:.4}') - - -.. code-block:: bash - - COP = 2.584 + ) Expand fix to any working fluids ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -377,10 +376,10 @@ building a network, that works with a variety of working fluids. nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back) # heat sink - cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='21') - cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='22') - cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='23') - cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='24') + cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='20') + cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='21') + cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='22') + cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='23') nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed) diff --git a/docs/whats_new/v0-2-0.rst b/docs/whats_new/v0-2-0.rst index 2e8b39c8f..f42cb9d46 100644 --- a/docs/whats_new/v0-2-0.rst +++ b/docs/whats_new/v0-2-0.rst @@ -74,7 +74,7 @@ Other changes case of subsystems, have a look at the :ref:`district heating example `. - Change the specification of set value for :py:class:`dc_simple ` class from :code:`val_set` to :code:`is_set` (`PR #138 `_). -- Move the default characteristic function plots to the :py:mod:`tespy.data ` module documentation +- Move the default characteristic function plots to the :ref:`tespy_data_label` documentation (`PR #138 `_). Contributors From 164b9a31b429e11a337e659a1da9fdb5773e486a Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 14 Aug 2022 12:35:54 +0200 Subject: [PATCH 021/120] Update What's New --- docs/whats_new/v0-6-1.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/whats_new/v0-6-1.rst b/docs/whats_new/v0-6-1.rst index f76abf5c5..47754de7d 100644 --- a/docs/whats_new/v0-6-1.rst +++ b/docs/whats_new/v0-6-1.rst @@ -15,9 +15,12 @@ Documentation ############# - Fix some typos in the online documentation (`PR #342 `_). +- New tutorial on starting values for a subcritical heat pump setup + (`PR #346 `_). Contributors ############ - Francesco Witte (`@fwitte `_) - `@NicholasFry `_ - Matthias Bock (`@matbock `_) +- `@maltefritz `_ From 572af7d613092f9eebae6c708d9e5382c21a8245 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 14 Aug 2022 20:33:23 +0200 Subject: [PATCH 022/120] Remove example code --- src/tespy/tools/_optimization_example.py | 163 ----------------------- 1 file changed, 163 deletions(-) delete mode 100644 src/tespy/tools/_optimization_example.py diff --git a/src/tespy/tools/_optimization_example.py b/src/tespy/tools/_optimization_example.py deleted file mode 100644 index dd8f1c422..000000000 --- a/src/tespy/tools/_optimization_example.py +++ /dev/null @@ -1,163 +0,0 @@ -import numpy as np - -from tespy.components.basics.cycle_closer import CycleCloser -from tespy.components.heat_exchangers.condenser import Condenser -from tespy.components.heat_exchangers.heat_exchanger_simple import HeatExchangerSimple -from tespy.components.nodes.merge import Merge -from tespy.components.nodes.splitter import Splitter -from tespy.components.piping.valve import Valve -from tespy.components.turbomachinery.pump import Pump -from tespy.components.turbomachinery.turbine import Turbine -from tespy.connections.bus import Bus -from tespy.connections.connection import Connection -from tespy.networks.network import Network - - -class SamplePlant: - """Class template for TESPy model usage in optimization module.""" - def __init__(self): - - self.nw = Network(fluids=['water']) - self.nw.set_attr(p_unit="bar", T_unit="C", h_unit="kJ / kg", iterinfo=False) - - # main cycle components cycle closer - steam_generator = HeatExchangerSimple("steam generator") - close_cycle = CycleCloser("cycle closer") - - turbine_hp = Turbine("turbine high pressure") - turbine_lp = Turbine("turbine low pressure") - extraction = Splitter("steam extraction splitter", num_out=2) - preheater = Condenser("feed water preheater") - valve = Valve("preheater condensate valve") - waste_steam_merge = Merge("waste steam merge") - - condenser = HeatExchangerSimple("main condenser") - feed_pump = Pump("feed water pump") - - # Connections - - # main cycle - c0 = Connection(steam_generator, "out1", close_cycle, "in1", label="0") - c1 = Connection(close_cycle, "out1", turbine_hp, "in1", label="1") - c2 = Connection(turbine_hp, "out1", extraction, "in1", label="2") - c3 = Connection(extraction, "out1", turbine_lp, "in1", label="3") - c4 = Connection(turbine_lp, "out1", waste_steam_merge, "in1", label="4") - c5 = Connection(waste_steam_merge, "out1", condenser, "in1", label="5") - c6 = Connection(condenser, "out1", feed_pump, "in1", label="6") - c7 = Connection(feed_pump, "out1", preheater, "in2", label="7") - c8 = Connection(preheater, "out2", steam_generator, "in1", label="8") - - # steam extraction - c11 = Connection(extraction, "out2", preheater, "in1", label="11") - c12 = Connection(preheater, "out1", valve, "in1", label="12") - c13 = Connection(valve, "out1", waste_steam_merge, "in2", label="13") - - self.nw.add_conns(c0, c1, c2, c3, c4, c5, c6, c7, c8, c11, c12, c13) - - # component specifications - steam_generator.set_attr(pr=0.92) - turbine_hp.set_attr(eta_s=0.9) - turbine_lp.set_attr(eta_s=0.9) - condenser.set_attr(pr=1) - feed_pump.set_attr(eta_s=0.75) - preheater.set_attr(ttd_u=5, pr1=1, pr2=0.98) - - # connection specifications - c1.set_attr(fluid={'water': 1}, p=100, T=600, m=10) - # pressure at connection 2 will be the parameter to optimize - c2.set_attr(p=10) - c6.set_attr(x=0, p=0.1) - # set liquid state to provide good starting values - c8.set_attr(state='l') - - power_bus = Bus('power output') - power_bus.add_comps( - {'comp': turbine_hp, 'char': 0.97}, - {'comp': turbine_lp, 'char': 0.97}, - {'comp': feed_pump, 'char': 0.97, 'base': 'bus'} - ) - heat_bus = Bus('heat input') - heat_bus.add_comps({'comp': steam_generator}) - self.nw.add_busses(power_bus, heat_bus) - - self.nw.solve("design") - self.stable = "_stable" - self.nw.save(self.stable) - - def get_param(self, obj, label, parameter): - """Get the value of a parameter in the network's unit system. - - Parameters - ---------- - obj : str - Object to get parameter for (Components/Connections). - - label : str - Label of the object in the TESPy model. - - parameter : str - Name of the parameter of the object. - - Returns - ------- - value : float - Value of the parameter. - """ - if obj == 'Components': - return self.nw.get_comp(label).get_attr(parameter).val - elif obj == 'Connections': - return self.nw.get_conn(label).get_attr(parameter).val - - def set_params(self, **kwargs): - - if "Connections" in kwargs: - for c, params in kwargs["Connections"].items(): - self.nw.get_conn(c).set_attr(**params) - - if "Components" in kwargs: - for c, params in kwargs["Components"].items(): - self.nw.get_comp(c).set_attr(**params) - - def solve_model(self, **kwargs): - """ - Solve the TESPy model given the - """ - - self.set_params(**kwargs) - - self.solved = False - try: - self.nw.solve("design") - if self.nw.res[-1] >= 1e-3 or self.nw.lin_dep: - self.nw.solve("design", init_only=True, init_path=self.stable) - else: - # might need more checks here! - if any(self.nw.results['Condenser']['Q'] > 0): - self.solved = False - else: - self.solved = True - except ValueError as e: - self.nw.lin_dep = True - self.nw.solve("design", init_only=True, init_path=self.stable) - - def get_objective(self, objective): - """ - Get the current objective function evaluation. - - Parameters - ---------- - objective : str - Name of the objective function. - - Returns - ------- - objective_value : float - Evaluation of the objective function. - """ - if self.solved: - return -1 / ( - self.nw.busses['power output'].P.val / - self.nw.busses['heat input'].P.val - ) - else: - return np.nan From edb6b66658c0677015d5e5425bb0ac62c9700f54 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 14 Aug 2022 20:48:09 +0200 Subject: [PATCH 023/120] Update optimization documentation --- docs/whats_new/v0-6-1.rst | 3 ++ src/tespy/tools/optimization.py | 87 +++++++++++++++++++++------------ 2 files changed, 59 insertions(+), 31 deletions(-) diff --git a/docs/whats_new/v0-6-1.rst b/docs/whats_new/v0-6-1.rst index 47754de7d..d4602506c 100644 --- a/docs/whats_new/v0-6-1.rst +++ b/docs/whats_new/v0-6-1.rst @@ -10,6 +10,9 @@ New Features defined to the WaterElectrolyzer :py:class:`tespy.components.reactors.water_electrolyzer.WaterElectrolyzer` (`PR #329 `_). +- Integration of an optimization suite using pygmo :cite:`Biscani2020` to apply + a variety of state of the art optimization algorithms to your TESPy model + (`PR #296 `_). Documentation ############# diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index c24c2f548..a7024cfc0 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -5,7 +5,8 @@ import pandas as pd -from tespy.tools.helpers import merge_dicts, nested_OrderedDict +from tespy.tools.helpers import merge_dicts +from tespy.tools.helpers import nested_OrderedDict class OptimizationProblem: @@ -51,31 +52,38 @@ class OptimizationProblem: ------- This example shows the optimization of the thermal efficiency of the `SamplePlant` with respect to the pressure value at the intermediate - extration of the turbine. - - >>> from tespy.tools.optimization import OptimizationProblem - >>> from tespy.tools._optimization_example import SamplePlant - >>> import pygmo as pg - - Create an instance of your plant class, i.e. :code:`plant = SamplePlant()` - and the instance of :code:`OptimizationProblem` by passing the plant - instance, the variables, the constraints and the objective. - - As the optimization problem can be formulated as unconstrained problem by - defining the lower and the upper limits for the variable values, the - constraints parameter can be left to its default value. The objective - function (:py:meth:`tespy.tools.optimzite.SamplePlant.get_objective`), which - returns the same evaluation for any kind of objective (there is only the - thermal efficiency in this case), the :code:`objective` keyword does not - need to be defined in this example (you could think of defining several - objectives here and returning them according to the selected objective). - - As described, the variable in this example is the extraction pressure at the + extration of the turbine. You can find the example code on the GitHub page + of TESPy: . + + To use the API, you need to define a class holding a TESPy network. You + create an instance of your plant class, i.e. :code:`plant = SamplePlant()`. + Then create an instance of the class + :py:class:`tespy.tools.optimize.OptimizationProblem` and pass + + - the plant instance, + - the variables, + - the constraints and + - the objective function name. + + For the optimization problem in this example, it can be formulated as + unconstrained problem by defining the lower and the upper limits for the + variable values, the constraints parameter can be left out. The objective + function of your plant (:code:`get_objective`), should return the + evaluation of the objective function. You can define multiple objective + functions, which can be accessed by the name of the objective. In the + example code only the thermal efficiency is defined, therefore the + :code:`objective` keyword does not need to be defined. The keywod is mainly + of use, if you want to quickly change the evaluation. + + The only variable in this example is the extraction pressure at the turbine. The upper limit is 50 bar and the lower limit 0.4 bar. Of course, it is possible to use multiple variables and component parameters as variables as well. Just provide them in the same structure as in this example. + >>> from tespy.tools.optimization import OptimizationProblem + >>> # import your SamplePlant and pygmo here + >>> plant = SamplePlant() >>> variables = {"Connections": {"2": {"p": {"min": 0.4, "max": 50}}}} >>> optimize = OptimizationProblem(plant, variables) @@ -83,15 +91,15 @@ class OptimizationProblem: .. note:: Please note, that the sense of optimization is always minimization, - therefore you need to define your objective functions in the appropriate - way. + therefore you need to define your objective functions in the + appropriate way. After selection of an appropriate algorithm (differential evolution is a good fit for this application) we can start the optimization run. For more information on algorithms available in the PyGMO framework and their individual specifications please refer to the respective section in their online documentation: - `list of algorithms `_. + `list of algorithms `__. Specify the number of individuals (10), the number of generations (15) and call the :py:meth:`tespy.tools.optimize.OptimizationProblem.run` method of your :code:`OptimizationProblem` instance passing the algorithm and the @@ -105,7 +113,9 @@ class OptimizationProblem: (...) In our sample run, we found an optimal value for the extraction pressure of - about 4.45 bar. + about 4.45 bar. The results for every individual in each generation are + stored in the :code:`individuals` attribute of the + :code:`OptimizationProblem`. """ def __init__(self, model, variables={}, constraints={}, objective="objective"): @@ -113,8 +123,7 @@ def __init__(self, model, variables={}, constraints={}, objective="objective"): msg = ( "For this function of TESPy pygmo has to be installed. Either use " "pip (Linux users only) or conda to install the latest pygmo " - "version. It is also possible to install tespy using the [opt] " - "option: pip install tespy[opt]." + "version." ) raise ImportError(msg) @@ -296,9 +305,17 @@ def run(self, algo, num_ind, num_gen): print('Evolution: {}'.format(gen)) for i in range(len(self.objective_list)): - print(self.objective_list[i] + ': {}'.format(round(pop.champion_f[i], 4))) + print( + self.objective_list[i] + ': {}'.format( + round(pop.champion_f[i], 4) + ) + ) for i in range(len(self.variable_list)): - print(self.variable_list[i] + ': {}'.format(round(pop.champion_x[i], 4))) + print( + self.variable_list[i] + ': {}'.format( + round(pop.champion_x[i], 4) + ) + ) pop = algo.evolve(pop) gen += 1 @@ -306,6 +323,14 @@ def run(self, algo, num_ind, num_gen): print('Final evolution: {}'.format(gen)) for i in range(len(self.objective_list)): - print(self.objective_list[i] + ': {}'.format(round(pop.champion_f[i], 4))) + print( + self.objective_list[i] + ': {}'.format( + round(pop.champion_f[i], 4) + ) + ) for i in range(len(self.variable_list)): - print(self.variable_list[i] + ': {}'.format(round(pop.champion_x[i], 4))) + print( + self.variable_list[i] + ': {}'.format( + round(pop.champion_x[i], 4) + ) + ) From 2da3e0d407a08911a3fbac6840d7b337f4f0e2df Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 14 Aug 2022 20:58:37 +0200 Subject: [PATCH 024/120] Include optimization in api docs, add downloadable example --- docs/api/tespy.tools.rst | 8 ++ src/tespy/tools/optimization.py | 37 +++---- tutorial/optimization_example.py | 177 +++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+), 25 deletions(-) create mode 100644 tutorial/optimization_example.py diff --git a/docs/api/tespy.tools.rst b/docs/api/tespy.tools.rst index 17543b064..f76f92c95 100644 --- a/docs/api/tespy.tools.rst +++ b/docs/api/tespy.tools.rst @@ -61,3 +61,11 @@ tespy.tools.logger module :members: :undoc-members: :show-inheritance: + +tespy.tools.optimization module +------------------------------- + +.. automodule:: tespy.tools.optimization + :members: + :undoc-members: + :show-inheritance: diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index a7024cfc0..8cc9e7309 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -25,8 +25,8 @@ class OptimizationProblem: ---------- model : custom class Object of some class, which provides all the methods required by the - optimization suite, see the - :py:class:`tespy.tools.optimization.SamplePlant` for a template. + optimization suite, see the Example section for a downloadable + template of the implementation. variables : dict Dictionary containing the decision variables and their respective @@ -53,12 +53,13 @@ class OptimizationProblem: This example shows the optimization of the thermal efficiency of the `SamplePlant` with respect to the pressure value at the intermediate extration of the turbine. You can find the example code on the GitHub page - of TESPy: . + of TESPy: + :download:`example implementation `. To use the API, you need to define a class holding a TESPy network. You create an instance of your plant class, i.e. :code:`plant = SamplePlant()`. Then create an instance of the class - :py:class:`tespy.tools.optimize.OptimizationProblem` and pass + :py:class:`tespy.tools.optimization.OptimizationProblem` and pass - the plant instance, - the variables, @@ -81,13 +82,6 @@ class OptimizationProblem: variables as well. Just provide them in the same structure as in this example. - >>> from tespy.tools.optimization import OptimizationProblem - >>> # import your SamplePlant and pygmo here - - >>> plant = SamplePlant() - >>> variables = {"Connections": {"2": {"p": {"min": 0.4, "max": 50}}}} - >>> optimize = OptimizationProblem(plant, variables) - .. note:: Please note, that the sense of optimization is always minimization, @@ -100,22 +94,15 @@ class OptimizationProblem: individual specifications please refer to the respective section in their online documentation: `list of algorithms `__. - Specify the number of individuals (10), the number of generations (15) and - call the :py:meth:`tespy.tools.optimize.OptimizationProblem.run` method of - your :code:`OptimizationProblem` instance passing the algorithm and the - number of individials and generations. - - >>> num_ind = 10 - >>> num_gen = 15 - - >>> algo = pg.de() - >>> ();optimize.run(algo, num_ind, num_gen);() # doctest: +ELLIPSIS - (...) + Specify the number of individuals, the number of generations and call the + :py:meth:`tespy.tools.optimization.OptimizationProblem.run` method of your + :code:`OptimizationProblem` instance passing the algorithm and the number + of individials and generations. In our sample run, we found an optimal value for the extraction pressure of - about 4.45 bar. The results for every individual in each generation are - stored in the :code:`individuals` attribute of the - :code:`OptimizationProblem`. + about 4.45 bar for a thermal efficiency of 38.7 %. The results for every + individual in each generation are stored in the :code:`individuals` + attribute of the :code:`OptimizationProblem`. """ def __init__(self, model, variables={}, constraints={}, objective="objective"): diff --git a/tutorial/optimization_example.py b/tutorial/optimization_example.py new file mode 100644 index 000000000..721824711 --- /dev/null +++ b/tutorial/optimization_example.py @@ -0,0 +1,177 @@ +import numpy as np + +from tespy.components.basics.cycle_closer import CycleCloser +from tespy.components.heat_exchangers.condenser import Condenser +from tespy.components.heat_exchangers.simple import HeatExchangerSimple +from tespy.components.nodes.merge import Merge +from tespy.components.nodes.splitter import Splitter +from tespy.components.piping.valve import Valve +from tespy.components.turbomachinery.pump import Pump +from tespy.components.turbomachinery.turbine import Turbine +from tespy.connections.bus import Bus +from tespy.connections.connection import Connection +from tespy.networks.network import Network + + +class SamplePlant: + """Class template for TESPy model usage in optimization module.""" + def __init__(self): + + self.nw = Network(fluids=['water']) + self.nw.set_attr(p_unit="bar", T_unit="C", h_unit="kJ / kg", iterinfo=False) + + # main cycle components cycle closer + steam_generator = HeatExchangerSimple("steam generator") + close_cycle = CycleCloser("cycle closer") + + turbine_hp = Turbine("turbine high pressure") + turbine_lp = Turbine("turbine low pressure") + extraction = Splitter("steam extraction splitter", num_out=2) + preheater = Condenser("feed water preheater") + valve = Valve("preheater condensate valve") + waste_steam_merge = Merge("waste steam merge") + + condenser = HeatExchangerSimple("main condenser") + feed_pump = Pump("feed water pump") + + # Connections + + # main cycle + c0 = Connection(steam_generator, "out1", close_cycle, "in1", label="0") + c1 = Connection(close_cycle, "out1", turbine_hp, "in1", label="1") + c2 = Connection(turbine_hp, "out1", extraction, "in1", label="2") + c3 = Connection(extraction, "out1", turbine_lp, "in1", label="3") + c4 = Connection(turbine_lp, "out1", waste_steam_merge, "in1", label="4") + c5 = Connection(waste_steam_merge, "out1", condenser, "in1", label="5") + c6 = Connection(condenser, "out1", feed_pump, "in1", label="6") + c7 = Connection(feed_pump, "out1", preheater, "in2", label="7") + c8 = Connection(preheater, "out2", steam_generator, "in1", label="8") + + # steam extraction + c11 = Connection(extraction, "out2", preheater, "in1", label="11") + c12 = Connection(preheater, "out1", valve, "in1", label="12") + c13 = Connection(valve, "out1", waste_steam_merge, "in2", label="13") + + self.nw.add_conns(c0, c1, c2, c3, c4, c5, c6, c7, c8, c11, c12, c13) + + # component specifications + steam_generator.set_attr(pr=0.92) + turbine_hp.set_attr(eta_s=0.9) + turbine_lp.set_attr(eta_s=0.9) + condenser.set_attr(pr=1) + feed_pump.set_attr(eta_s=0.75) + preheater.set_attr(ttd_u=5, pr1=1, pr2=0.98) + + # connection specifications + c1.set_attr(fluid={'water': 1}, p=100, T=600, m=10) + # pressure at connection 2 will be the parameter to optimize + c2.set_attr(p=10) + c6.set_attr(x=0, p=0.1) + # set liquid state to provide good starting values + c8.set_attr(state='l') + + power_bus = Bus('power output') + power_bus.add_comps( + {'comp': turbine_hp, 'char': 0.97}, + {'comp': turbine_lp, 'char': 0.97}, + {'comp': feed_pump, 'char': 0.97, 'base': 'bus'} + ) + heat_bus = Bus('heat input') + heat_bus.add_comps({'comp': steam_generator}) + self.nw.add_busses(power_bus, heat_bus) + + self.nw.solve("design") + self.stable = "_stable" + self.nw.save(self.stable) + + def get_param(self, obj, label, parameter): + """Get the value of a parameter in the network's unit system. + + Parameters + ---------- + obj : str + Object to get parameter for (Components/Connections). + + label : str + Label of the object in the TESPy model. + + parameter : str + Name of the parameter of the object. + + Returns + ------- + value : float + Value of the parameter. + """ + if obj == 'Components': + return self.nw.get_comp(label).get_attr(parameter).val + elif obj == 'Connections': + return self.nw.get_conn(label).get_attr(parameter).val + + def set_params(self, **kwargs): + + if "Connections" in kwargs: + for c, params in kwargs["Connections"].items(): + self.nw.get_conn(c).set_attr(**params) + + if "Components" in kwargs: + for c, params in kwargs["Components"].items(): + self.nw.get_comp(c).set_attr(**params) + + def solve_model(self, **kwargs): + """ + Solve the TESPy model given the + """ + + self.set_params(**kwargs) + + self.solved = False + try: + self.nw.solve("design") + if self.nw.res[-1] >= 1e-3 or self.nw.lin_dep: + self.nw.solve("design", init_only=True, init_path=self.stable) + else: + # might need more checks here! + if any(self.nw.results['Condenser']['Q'] > 0): + self.solved = False + else: + self.solved = True + except ValueError as e: + self.nw.lin_dep = True + self.nw.solve("design", init_only=True, init_path=self.stable) + + def get_objective(self, objective): + """ + Get the current objective function evaluation. + + Parameters + ---------- + objective : str + Name of the objective function. + + Returns + ------- + objective_value : float + Evaluation of the objective function. + """ + if self.solved: + return -1 / ( + self.nw.busses['power output'].P.val / + self.nw.busses['heat input'].P.val + ) + else: + return np.nan + + +from tespy.tools.optimization import OptimizationProblem +import pygmo as pg + +plant = SamplePlant() +variables = {"Connections": {"2": {"p": {"min": 0.4, "max": 50}}}} +optimize = OptimizationProblem(plant, variables) + +num_ind = 10 +num_gen = 15 + +algo = pg.de() +optimize.run(algo, num_ind, num_gen) # doctest: +ELLIPSIS From a644c113442e8a3f9f17845441efbbef6bf921ad Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 14 Aug 2022 20:59:35 +0200 Subject: [PATCH 025/120] Remove one more outdated reference --- src/tespy/tools/optimization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index 8cc9e7309..3cfc65b05 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -42,7 +42,7 @@ class OptimizationProblem: Note ---- For the required structure of the input dictionaries see the example in - the :py:class:`tespy.tools.optimization.SamplePlant`. + below. Installation of pygmo via pip is not available for Windows and OSX users currently. Please use conda instead or refer to their From 777965a0330b4dd75248d2338332cac08558cfe0 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 14 Aug 2022 21:06:52 +0200 Subject: [PATCH 026/120] Some styling --- src/tespy/tools/helpers.py | 4 ---- src/tespy/tools/optimization.py | 16 ++++++++++------ tutorial/optimization_example.py | 7 +++---- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/tespy/tools/helpers.py b/src/tespy/tools/helpers.py index 8ff4f7946..d16858297 100644 --- a/src/tespy/tools/helpers.py +++ b/src/tespy/tools/helpers.py @@ -17,10 +17,6 @@ import CoolProp as CP import numpy as np -from collections import OrderedDict -from collections.abc import Mapping -from copy import deepcopy - from tespy.tools.global_vars import err from tespy.tools.global_vars import fluid_property_data from tespy.tools.global_vars import molar_masses diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index 3cfc65b05..d78a789db 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -108,9 +108,9 @@ class OptimizationProblem: def __init__(self, model, variables={}, constraints={}, objective="objective"): if pg is None: msg = ( - "For this function of TESPy pygmo has to be installed. Either use " - "pip (Linux users only) or conda to install the latest pygmo " - "version." + "For this function of TESPy pygmo has to be installed. Either" + " use pip (Linux users only) or conda to install the latest" + " pygmo version." ) raise ImportError(msg) @@ -118,7 +118,7 @@ def __init__(self, model, variables={}, constraints={}, objective="objective"): default_variables = {"Connections": {}, "Components": {}} default_constraints = { "lower limits": {"Connections": {}, "Components": {}}, - "upper limits": { "Connections": {}, "Components": {}} + "upper limits": {"Connections": {}, "Components": {}} } # merge the passed values into the default dictionary structure variables = merge_dicts(variables, default_variables) @@ -141,8 +141,12 @@ def __init__(self, model, variables={}, constraints={}, objective="objective"): for label, params in data.items(): if obj in ["Connections", "Components"]: for param in params: - self.bounds[0] += [self.variables[obj][label][param]['min']] - self.bounds[1] += [self.variables[obj][label][param]['max']] + self.bounds[0] += [ + self.variables[obj][label][param]['min'] + ] + self.bounds[1] += [ + self.variables[obj][label][param]['max'] + ] self.variable_list += [obj + '-' + label + '-' + param] else: self.bounds[0] += [self.variables[obj][label]['min']] diff --git a/tutorial/optimization_example.py b/tutorial/optimization_example.py index 721824711..292a62aba 100644 --- a/tutorial/optimization_example.py +++ b/tutorial/optimization_example.py @@ -1,4 +1,5 @@ import numpy as np +import pygmo as pg from tespy.components.basics.cycle_closer import CycleCloser from tespy.components.heat_exchangers.condenser import Condenser @@ -11,6 +12,7 @@ from tespy.connections.bus import Bus from tespy.connections.connection import Connection from tespy.networks.network import Network +from tespy.tools.optimization import OptimizationProblem class SamplePlant: @@ -163,9 +165,6 @@ def get_objective(self, objective): return np.nan -from tespy.tools.optimization import OptimizationProblem -import pygmo as pg - plant = SamplePlant() variables = {"Connections": {"2": {"p": {"min": 0.4, "max": 50}}}} optimize = OptimizationProblem(plant, variables) @@ -174,4 +173,4 @@ def get_objective(self, objective): num_gen = 15 algo = pg.de() -optimize.run(algo, num_ind, num_gen) # doctest: +ELLIPSIS +optimize.run(algo, num_ind, num_gen) From b49e95cd8754f4b4649f1c3b766638ed7b01c06b Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 16 Aug 2022 18:56:49 +0200 Subject: [PATCH 027/120] Update year --- LICENSE | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/LICENSE b/LICENSE index 928c7b731..67fb8fdb0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2017-2021, oemof developer group - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2017-2022, oemof developer group + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 085edc0e8329a96c91c34af7f8c806b47c4dd654 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 16 Aug 2022 19:22:38 +0200 Subject: [PATCH 028/120] Move around a bunch of stuff to get coarse structure A lot of links are still broken, images incompatible with dark mode, images missing, new sections missing, fine tuning style, etc.. --- README.rst | 2 +- docs/{_build => }/_static/css/custom.css | 0 .../_images => _static/images}/NH3_logph.svg | 0 .../images}/Ts_diagram_states.svg | 10012 +++++++------- .../images/advanced/exergy/flowsheet.svg} | 6732 +++++----- .../images/advanced/exergy/sankey.png} | Bin docs/{api/_images => _static/images}/dhs.svg | 1490 +-- .../_images => _static/images}/dhs_closed.svg | 814 +- .../_images => _static/images}/dhs_forks.svg | 578 +- .../_images => _static/images}/dhs_open.svg | 874 +- .../_images => _static/images}/heat_pump.svg | 1222 +- .../images}/heat_pump_COP_air.svg | 2468 ++-- .../images}/heat_pump_COP_water.svg | 2452 ++-- .../images}/heat_pump_example.svg | 1282 +- .../images}/intro_connections.svg | 652 +- .../images}/intro_district_heating_scheme.svg | 572 +- .../images}/logo_tespy_big.svg | 26 +- .../images/logo_tespy_big_darkmode.svg | 623 + .../images}/logo_tespy_big_editable_font.svg | 954 +- .../images}/logo_tespy_mid.svg | 968 +- .../images/logo_tespy_mid_darkmode.svg | 484 + .../images}/logo_tespy_mid_editable_font.svg | 872 +- .../images}/logo_tespy_small.svg | 794 +- .../images}/logph_diagram_states.svg | 10870 ++++++++-------- .../images}/power_plant_two_extractions.svg | 2744 ++-- .../scatterplot_efficiency_optimization.svg | 3674 +++--- .../subsystem_waste_heat_generator.svg | 2114 +-- .../images}/tutorial_heat_pump.svg | 1178 +- .../heat_pump_exergy}/NH3_sankey.svg | 0 .../heat_pump_exergy}/diagram_E_D.svg | 0 .../diagram_cop_eps_Tgeo_Q.svg | 0 .../diagram_cop_eps_Tgeo_Ths.svg | 0 .../diagram_eps_Tamb_Tgeo.svg | 0 .../tutorials/heat_pump_exergy/flowsheet.svg} | 0 .../heat_pump_starting_values/COP_by_wf.svg} | 0 .../heat_pump_starting_values/flowsheet.svg} | 0 .../heat_pump_starting_values/logph.svg} | 0 docs/_templates/index.html | 0 docs/{analyses => advanced}/exergy.rst | 65 +- docs/advanced/optimization.rst | 4 + docs/api/_images/NH3_sankey.html | 67 - docs/api/_images/basic.svg | 916 -- docs/api/_images/basic_efficiency.svg | 1043 -- docs/api/_images/cc_bp.svg | 1218 -- docs/api/_images/chp.svg | 1089 -- docs/api/_images/chp_PQ.svg | 1579 --- .../{tespy.components.rst => components.rst} | 0 ...{tespy.connections.rst => connections.rst} | 46 +- docs/api/{tespy.data.rst => data.rst} | 0 docs/api/{tespy.networks.rst => networks.rst} | 46 +- docs/api/{tespy.tools.rst => tools.rst} | 0 docs/basics.rst | 16 + docs/basics/district_heating.rst | 16 + docs/basics/gas_turbine.rst | 16 + docs/basics/heat_pump.rst | 16 + docs/basics/rankine_cycle.rst | 16 + docs/benchmarks.rst | 4 + docs/conf.py | 208 +- docs/contents.rst | 54 + .../how.rst} | 87 +- docs/development/what.rst | 56 + docs/examples.rst | 36 + docs/first_steps.rst | 4 +- docs/index.rst | 29 - docs/installation.rst | 127 +- docs/introduction.rst | 39 +- docs/modules.rst | 24 + docs/regular_meeting.rst | 11 +- docs/requirements.txt | 4 +- docs/tespy_analyses.rst | 19 - docs/tespy_modules.rst | 31 - docs/tespy_modules/characteristics.rst | 4 +- docs/tespy_modules/components.rst | 10 +- docs/tespy_modules/connections.rst | 698 +- docs/tespy_modules/fluid_properties.rst | 6 +- docs/tespy_modules/networks.rst | 4 +- docs/tespy_modules/other.rst | 587 +- docs/tutorials.rst | 27 + .../clausius_rankine.rst | 0 .../clausius_rankine_chp.rst | 0 .../combined_cycle_chp.rst | 0 .../combustion_engine.rst | 0 .../district_heating.rst | 0 .../heat_pump.rst | 0 .../solar_collector.rst | 0 .../tutorial_combustion_chamber.rst | 7 +- .../tutorial_heat_pump.rst | 13 +- .../tutorial_heat_pump_exergy.rst | 32 +- .../tutorial_pygmo_optimization.rst | 12 +- .../tutorial_starting_values.rst | 15 +- docs/tutorials_examples.rst | 80 - docs/whats_new.rst | 5 - docs/whats_new/v0-1-3.rst | 86 +- docs/whats_new/v0-2-2.rst | 130 +- docs/whats_new/v0-4-3-003.rst | 38 +- docs/whats_new/v0-4-3.rst | 2 +- docs/zliterature.rst | 1 + setup.py | 14 +- .../components/basics/subsystem_interface.py | 8 +- 99 files changed, 29120 insertions(+), 33996 deletions(-) rename docs/{_build => }/_static/css/custom.css (100%) rename docs/{api/_images => _static/images}/NH3_logph.svg (100%) rename docs/{api/_images => _static/images}/Ts_diagram_states.svg (96%) rename docs/{api/_images/SEGS_flowsheet.svg => _static/images/advanced/exergy/flowsheet.svg} (97%) rename docs/{api/_images/SEGS_sankey.png => _static/images/advanced/exergy/sankey.png} (100%) rename docs/{api/_images => _static/images}/dhs.svg (97%) rename docs/{api/_images => _static/images}/dhs_closed.svg (97%) rename docs/{api/_images => _static/images}/dhs_forks.svg (97%) rename docs/{api/_images => _static/images}/dhs_open.svg (97%) rename docs/{api/_images => _static/images}/heat_pump.svg (98%) rename docs/{api/_images => _static/images}/heat_pump_COP_air.svg (97%) rename docs/{api/_images => _static/images}/heat_pump_COP_water.svg (97%) rename docs/{api/_images => _static/images}/heat_pump_example.svg (98%) rename docs/{api/_images => _static/images}/intro_connections.svg (98%) rename docs/{api/_images => _static/images}/intro_district_heating_scheme.svg (97%) rename docs/{api/_images => _static/images}/logo_tespy_big.svg (98%) create mode 100644 docs/_static/images/logo_tespy_big_darkmode.svg rename docs/{api/_images => _static/images}/logo_tespy_big_editable_font.svg (97%) rename docs/{api/_images => _static/images}/logo_tespy_mid.svg (97%) create mode 100644 docs/_static/images/logo_tespy_mid_darkmode.svg rename docs/{api/_images => _static/images}/logo_tespy_mid_editable_font.svg (97%) rename docs/{api/_images => _static/images}/logo_tespy_small.svg (97%) rename docs/{api/_images => _static/images}/logph_diagram_states.svg (96%) rename docs/{api/_images => _static/images}/power_plant_two_extractions.svg (97%) rename docs/{api/_images => _static/images}/scatterplot_efficiency_optimization.svg (97%) rename docs/{api/_images => _static/images}/subsystem_waste_heat_generator.svg (97%) rename docs/{api/_images => _static/images}/tutorial_heat_pump.svg (98%) rename docs/{api/_images => _static/images/tutorials/heat_pump_exergy}/NH3_sankey.svg (100%) rename docs/{api/_images => _static/images/tutorials/heat_pump_exergy}/diagram_E_D.svg (100%) rename docs/{api/_images => _static/images/tutorials/heat_pump_exergy}/diagram_cop_eps_Tgeo_Q.svg (100%) rename docs/{api/_images => _static/images/tutorials/heat_pump_exergy}/diagram_cop_eps_Tgeo_Ths.svg (100%) rename docs/{api/_images => _static/images/tutorials/heat_pump_exergy}/diagram_eps_Tamb_Tgeo.svg (100%) rename docs/{api/_images/heat_pump_exergy_flowsheet.svg => _static/images/tutorials/heat_pump_exergy/flowsheet.svg} (100%) rename docs/{api/_images/tutorial_sv_COP_by_wf.svg => _static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg} (100%) rename docs/{api/_images/tutorial_sv_heat_pump_intheatex.svg => _static/images/tutorials/heat_pump_starting_values/flowsheet.svg} (100%) rename docs/{api/_images/tutorial_sv_logph.svg => _static/images/tutorials/heat_pump_starting_values/logph.svg} (100%) create mode 100644 docs/_templates/index.html rename docs/{analyses => advanced}/exergy.rst (93%) create mode 100644 docs/advanced/optimization.rst delete mode 100644 docs/api/_images/NH3_sankey.html delete mode 100644 docs/api/_images/basic.svg delete mode 100644 docs/api/_images/basic_efficiency.svg delete mode 100644 docs/api/_images/cc_bp.svg delete mode 100644 docs/api/_images/chp.svg delete mode 100644 docs/api/_images/chp_PQ.svg rename docs/api/{tespy.components.rst => components.rst} (100%) rename docs/api/{tespy.connections.rst => connections.rst} (95%) rename docs/api/{tespy.data.rst => data.rst} (100%) rename docs/api/{tespy.networks.rst => networks.rst} (95%) rename docs/api/{tespy.tools.rst => tools.rst} (100%) create mode 100644 docs/basics.rst create mode 100644 docs/basics/district_heating.rst create mode 100644 docs/basics/gas_turbine.rst create mode 100644 docs/basics/heat_pump.rst create mode 100644 docs/basics/rankine_cycle.rst create mode 100644 docs/benchmarks.rst create mode 100644 docs/contents.rst rename docs/{developing_tespy.rst => development/how.rst} (66%) create mode 100644 docs/development/what.rst create mode 100644 docs/examples.rst delete mode 100644 docs/index.rst create mode 100644 docs/modules.rst delete mode 100644 docs/tespy_analyses.rst delete mode 100644 docs/tespy_modules.rst create mode 100644 docs/tutorials.rst rename docs/{tutorials_examples => tutorials}/clausius_rankine.rst (100%) rename docs/{tutorials_examples => tutorials}/clausius_rankine_chp.rst (100%) rename docs/{tutorials_examples => tutorials}/combined_cycle_chp.rst (100%) rename docs/{tutorials_examples => tutorials}/combustion_engine.rst (100%) rename docs/{tutorials_examples => tutorials}/district_heating.rst (100%) rename docs/{tutorials_examples => tutorials}/heat_pump.rst (100%) rename docs/{tutorials_examples => tutorials}/solar_collector.rst (100%) rename docs/{tutorials_examples => tutorials}/tutorial_combustion_chamber.rst (96%) rename docs/{tutorials_examples => tutorials}/tutorial_heat_pump.rst (98%) rename docs/{tutorials_examples => tutorials}/tutorial_heat_pump_exergy.rst (97%) rename docs/{tutorials_examples => tutorials}/tutorial_pygmo_optimization.rst (99%) rename docs/{tutorials_examples => tutorials}/tutorial_starting_values.rst (98%) delete mode 100644 docs/tutorials_examples.rst diff --git a/README.rst b/README.rst index 999bc0daf..5d1e70b7c 100644 --- a/README.rst +++ b/README.rst @@ -116,7 +116,7 @@ tespy version: If you want to use the latest features, you might want to install the **developer version**. See section -`Developing TESPy `_ +`Developing TESPy `_ for more information. The developer version is not recommended for productive use. diff --git a/docs/_build/_static/css/custom.css b/docs/_static/css/custom.css similarity index 100% rename from docs/_build/_static/css/custom.css rename to docs/_static/css/custom.css diff --git a/docs/api/_images/NH3_logph.svg b/docs/_static/images/NH3_logph.svg similarity index 100% rename from docs/api/_images/NH3_logph.svg rename to docs/_static/images/NH3_logph.svg diff --git a/docs/api/_images/Ts_diagram_states.svg b/docs/_static/images/Ts_diagram_states.svg similarity index 96% rename from docs/api/_images/Ts_diagram_states.svg rename to docs/_static/images/Ts_diagram_states.svg index d3b76a4e1..c33043f75 100644 --- a/docs/api/_images/Ts_diagram_states.svg +++ b/docs/_static/images/Ts_diagram_states.svg @@ -1,5006 +1,5006 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/SEGS_flowsheet.svg b/docs/_static/images/advanced/exergy/flowsheet.svg similarity index 97% rename from docs/api/_images/SEGS_flowsheet.svg rename to docs/_static/images/advanced/exergy/flowsheet.svg index e2f7df148..8fdb0e9f4 100644 --- a/docs/api/_images/SEGS_flowsheet.svg +++ b/docs/_static/images/advanced/exergy/flowsheet.svg @@ -1,3366 +1,3366 @@ - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HP1 - HP2 - LP1 - LP2 - LP3 - LP4 - LP5 - G - SolarField - FWT - CON - CP - FWP - EV - RH - FP - - - SH - ECO - DR - PCC - PTCC - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 23 - 24 - 32 - 33 - 34 - 35 - 36 - 37 - 45 - 46 - 47 - 58 - 70 - 71 - 72 - 75 - 76 - 77 - 78 - 79 - - - 62 - 63 - 2 - - - - - - - - - 17 - 18 - 19 - 22 - 26 - 40 - 42 - 44 - 50 - 55 - - - - 61 - LPP1 - LPP2 - LPP3 - HPP1 - HPP2 - 1 - 3 - 4 - 5 - 1 - 7 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 5 - CWP - - M - - - M - - - M - - - M - - - - 2 - - 3 - - - - 4 - - - - - - - - - 60 - - - - - - - 20 - 21 - 25 - 64 - 65 - CT - 38 - 41 - 48 - 51 - 52 - 53 - 59 - - - - - 66 - - - - Fan - - M - - - - 73 - 74 - CWCC - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 27 - 28 - 29 - 30 - 31 - LPsub1 - LPsub2 - LPsub3 - HPsub1 - HPsub2 - 39 - 43 - 49 - 54 - 57 - 56 - - + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HP1 + HP2 + LP1 + LP2 + LP3 + LP4 + LP5 + G + SolarField + FWT + CON + CP + FWP + EV + RH + FP + + + SH + ECO + DR + PCC + PTCC + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 23 + 24 + 32 + 33 + 34 + 35 + 36 + 37 + 45 + 46 + 47 + 58 + 70 + 71 + 72 + 75 + 76 + 77 + 78 + 79 + + + 62 + 63 + 2 + + + + + + + + + 17 + 18 + 19 + 22 + 26 + 40 + 42 + 44 + 50 + 55 + + + + 61 + LPP1 + LPP2 + LPP3 + HPP1 + HPP2 + 1 + 3 + 4 + 5 + 1 + 7 + + 1 + + 2 + + 3 + + 4 + + 5 + + 6 + + 5 + CWP + + M + + + M + + + M + + + M + + + + 2 + + 3 + + + + 4 + + + + + + + + + 60 + + + + + + + 20 + 21 + 25 + 64 + 65 + CT + 38 + 41 + 48 + 51 + 52 + 53 + 59 + + + + + 66 + + + + Fan + + M + + + + 73 + 74 + CWCC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 27 + 28 + 29 + 30 + 31 + LPsub1 + LPsub2 + LPsub3 + HPsub1 + HPsub2 + 39 + 43 + 49 + 54 + 57 + 56 + + diff --git a/docs/api/_images/SEGS_sankey.png b/docs/_static/images/advanced/exergy/sankey.png similarity index 100% rename from docs/api/_images/SEGS_sankey.png rename to docs/_static/images/advanced/exergy/sankey.png diff --git a/docs/api/_images/dhs.svg b/docs/_static/images/dhs.svg similarity index 97% rename from docs/api/_images/dhs.svg rename to docs/_static/images/dhs.svg index 230fe0ae9..17391b4e5 100644 --- a/docs/api/_images/dhs.svg +++ b/docs/_static/images/dhs.svg @@ -1,745 +1,745 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - heatgeneration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - industrialarea - housingarea 1 - - - sportscentre - - housingarea 2 - - housingarea 3 - - housingarea 4 - - pipes - - fork - - K1 - K2 - K3 - K4 - - + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + heatgeneration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + industrialarea + housingarea 1 + + + sportscentre + + housingarea 2 + + housingarea 3 + + housingarea 4 + + pipes + + fork + + K1 + K2 + K3 + K4 + + diff --git a/docs/api/_images/dhs_closed.svg b/docs/_static/images/dhs_closed.svg similarity index 97% rename from docs/api/_images/dhs_closed.svg rename to docs/_static/images/dhs_closed.svg index a507fbb44..fd9fb38d5 100644 --- a/docs/api/_images/dhs_closed.svg +++ b/docs/_static/images/dhs_closed.svg @@ -1,407 +1,407 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - connectingpipes - - - - - - - - - - - - - consumer - - - controlvalve - Subsystem 0 - - - - - - - - - - - - Subsystem 1, 2, ... - - Subsystem n - inlet 1 - outlet 1 - - - - - - + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + connectingpipes + + + + + + + + + + + + + consumer + + + controlvalve + Subsystem 0 + + + + + + + + + + + + Subsystem 1, 2, ... + + Subsystem n + inlet 1 + outlet 1 + + + + + + diff --git a/docs/api/_images/dhs_forks.svg b/docs/_static/images/dhs_forks.svg similarity index 97% rename from docs/api/_images/dhs_forks.svg rename to docs/_static/images/dhs_forks.svg index 087c33a75..b86805c00 100644 --- a/docs/api/_images/dhs_forks.svg +++ b/docs/_static/images/dhs_forks.svg @@ -1,289 +1,289 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - controlvalves - - - - - - - - feed flow - back flow - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + controlvalves + + + + + + + + feed flow + back flow + + + + + + + + diff --git a/docs/api/_images/dhs_open.svg b/docs/_static/images/dhs_open.svg similarity index 97% rename from docs/api/_images/dhs_open.svg rename to docs/_static/images/dhs_open.svg index b8511772f..03f85e0ca 100644 --- a/docs/api/_images/dhs_open.svg +++ b/docs/_static/images/dhs_open.svg @@ -1,437 +1,437 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - connectingpipes - - - - - - - - - - - - - consumer - - - controlvalve - Subsystem 0 - - - - - - - - - - - - - - - Subsystem 1, 2, ... - - Subsystem n - inlet 1 - outlet 1 - outlet 2 - inlet 2 - - - - - + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + connectingpipes + + + + + + + + + + + + + consumer + + + controlvalve + Subsystem 0 + + + + + + + + + + + + + + + Subsystem 1, 2, ... + + Subsystem n + inlet 1 + outlet 1 + outlet 2 + inlet 2 + + + + + diff --git a/docs/api/_images/heat_pump.svg b/docs/_static/images/heat_pump.svg similarity index 98% rename from docs/api/_images/heat_pump.svg rename to docs/_static/images/heat_pump.svg index 0d35bd4e5..2403df095 100644 --- a/docs/api/_images/heat_pump.svg +++ b/docs/_static/images/heat_pump.svg @@ -1,611 +1,611 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - source intercool - sink intercool - consumerback flow - consumerfeed flow - sink ambient - source ambient - - - - - coolant in - coolant out - condenser - expansion valve - drum withevaporator - superheater - compressor train - - + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + source intercool + sink intercool + consumerback flow + consumerfeed flow + sink ambient + source ambient + + + + + coolant in + coolant out + condenser + expansion valve + drum withevaporator + superheater + compressor train + + diff --git a/docs/api/_images/heat_pump_COP_air.svg b/docs/_static/images/heat_pump_COP_air.svg similarity index 97% rename from docs/api/_images/heat_pump_COP_air.svg rename to docs/_static/images/heat_pump_COP_air.svg index f279064bc..948571e5e 100644 --- a/docs/api/_images/heat_pump_COP_air.svg +++ b/docs/_static/images/heat_pump_COP_air.svg @@ -1,1234 +1,1234 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/heat_pump_COP_water.svg b/docs/_static/images/heat_pump_COP_water.svg similarity index 97% rename from docs/api/_images/heat_pump_COP_water.svg rename to docs/_static/images/heat_pump_COP_water.svg index 3e0444580..b4ee344d7 100644 --- a/docs/api/_images/heat_pump_COP_water.svg +++ b/docs/_static/images/heat_pump_COP_water.svg @@ -1,1226 +1,1226 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/heat_pump_example.svg b/docs/_static/images/heat_pump_example.svg similarity index 98% rename from docs/api/_images/heat_pump_example.svg rename to docs/_static/images/heat_pump_example.svg index 52b3f8160..a7deb192a 100644 --- a/docs/api/_images/heat_pump_example.svg +++ b/docs/_static/images/heat_pump_example.svg @@ -1,641 +1,641 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sink ambient - consumerback flow - consumerfeed flow - sink ambient - sourceambient - - - - - coolant in - coolant out - condenser - expansion valve - drum withevaporator - superheater - compressor train - - - - - - fan/pump - - - + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sink ambient + consumerback flow + consumerfeed flow + sink ambient + sourceambient + + + + + coolant in + coolant out + condenser + expansion valve + drum withevaporator + superheater + compressor train + + + + + + fan/pump + + + diff --git a/docs/api/_images/intro_connections.svg b/docs/_static/images/intro_connections.svg similarity index 98% rename from docs/api/_images/intro_connections.svg rename to docs/_static/images/intro_connections.svg index 46ec2c102..1a1437059 100644 --- a/docs/api/_images/intro_connections.svg +++ b/docs/_static/images/intro_connections.svg @@ -1,326 +1,326 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - waste steam - flue gas - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + waste steam + flue gas + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/intro_district_heating_scheme.svg b/docs/_static/images/intro_district_heating_scheme.svg similarity index 97% rename from docs/api/_images/intro_district_heating_scheme.svg rename to docs/_static/images/intro_district_heating_scheme.svg index 420f5a4f7..868186429 100644 --- a/docs/api/_images/intro_district_heating_scheme.svg +++ b/docs/_static/images/intro_district_heating_scheme.svg @@ -1,286 +1,286 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - source - sink - - - pipe feed - pipe back - - - - - heat exchanger - - - central heating plant - consumer - - Q - - - valve - - - - - - + + + + + + + + + + image/svg+xml + + + + + + + + + source + sink + + + pipe feed + pipe back + + + + + heat exchanger + + + central heating plant + consumer + + Q + + + valve + + + + + + diff --git a/docs/api/_images/logo_tespy_big.svg b/docs/_static/images/logo_tespy_big.svg similarity index 98% rename from docs/api/_images/logo_tespy_big.svg rename to docs/_static/images/logo_tespy_big.svg index c19f8fed1..c9dcd0391 100644 --- a/docs/api/_images/logo_tespy_big.svg +++ b/docs/_static/images/logo_tespy_big.svg @@ -12,8 +12,8 @@ height="285" id="svg2" version="1.1" - inkscape:version="1.0.2 (1.0.2+r75+1)" - sodipodi:docname="logo_tespy_big_editable_font.svg" + inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" + sodipodi:docname="logo_tespy_big.svg" inkscape:export-filename="/home/leppi/Dokumente/ZNES/Oemof/oemof_logo/done/logo_oemof_vec_inkscape_big_300DPI.png" inkscape:export-xdpi="300" inkscape:export-ydpi="300"> @@ -298,10 +298,10 @@ inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" - inkscape:window-width="1863" - inkscape:window-height="1025" - inkscape:window-x="57" - inkscape:window-y="27" + inkscape:window-width="1920" + inkscape:window-height="1017" + inkscape:window-x="-8" + inkscape:window-y="-8" inkscape:window-maximized="1" showguides="true" inkscape:guide-bbox="true" @@ -316,7 +316,10 @@ inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox-edge-midpoints="true" - inkscape:snap-smooth-nodes="true"> + inkscape:snap-smooth-nodes="true" + inkscape:snap-grids="false" + inkscape:snap-to-guides="false" + inkscape:snap-page="true"> image/svg+xml - + @@ -379,6 +382,13 @@ id="layer1" transform="translate(0,-767.3622)" style="display:inline"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/logo_tespy_big_editable_font.svg b/docs/_static/images/logo_tespy_big_editable_font.svg similarity index 97% rename from docs/api/_images/logo_tespy_big_editable_font.svg rename to docs/_static/images/logo_tespy_big_editable_font.svg index 10f66e93c..60aa7da8c 100644 --- a/docs/api/_images/logo_tespy_big_editable_font.svg +++ b/docs/_static/images/logo_tespy_big_editable_font.svg @@ -1,477 +1,477 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - -   - - ['tɛs.paɪ] - open energy modelling framework - - - - - - - - tespy - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + +   + + ['tɛs.paɪ] + open energy modelling framework + + + + + + + + tespy + + diff --git a/docs/api/_images/logo_tespy_mid.svg b/docs/_static/images/logo_tespy_mid.svg similarity index 97% rename from docs/api/_images/logo_tespy_mid.svg rename to docs/_static/images/logo_tespy_mid.svg index 8cae5d46b..355f609ca 100644 --- a/docs/api/_images/logo_tespy_mid.svg +++ b/docs/_static/images/logo_tespy_mid.svg @@ -1,484 +1,484 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - -   - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/logo_tespy_mid_darkmode.svg b/docs/_static/images/logo_tespy_mid_darkmode.svg new file mode 100644 index 000000000..8f739a121 --- /dev/null +++ b/docs/_static/images/logo_tespy_mid_darkmode.svg @@ -0,0 +1,484 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/logo_tespy_mid_editable_font.svg b/docs/_static/images/logo_tespy_mid_editable_font.svg similarity index 97% rename from docs/api/_images/logo_tespy_mid_editable_font.svg rename to docs/_static/images/logo_tespy_mid_editable_font.svg index 2c11e569d..0bd667e24 100644 --- a/docs/api/_images/logo_tespy_mid_editable_font.svg +++ b/docs/_static/images/logo_tespy_mid_editable_font.svg @@ -1,436 +1,436 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - -   - - ['tɛs.paɪ] - tespy - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + +   + + ['tɛs.paɪ] + tespy + + + + + + + diff --git a/docs/api/_images/logo_tespy_small.svg b/docs/_static/images/logo_tespy_small.svg similarity index 97% rename from docs/api/_images/logo_tespy_small.svg rename to docs/_static/images/logo_tespy_small.svg index f2f4f9689..211cb99cc 100644 --- a/docs/api/_images/logo_tespy_small.svg +++ b/docs/_static/images/logo_tespy_small.svg @@ -1,397 +1,397 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/logph_diagram_states.svg b/docs/_static/images/logph_diagram_states.svg similarity index 96% rename from docs/api/_images/logph_diagram_states.svg rename to docs/_static/images/logph_diagram_states.svg index a8cda0ddd..61125267d 100644 --- a/docs/api/_images/logph_diagram_states.svg +++ b/docs/_static/images/logph_diagram_states.svg @@ -1,5435 +1,5435 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/power_plant_two_extractions.svg b/docs/_static/images/power_plant_two_extractions.svg similarity index 97% rename from docs/api/_images/power_plant_two_extractions.svg rename to docs/_static/images/power_plant_two_extractions.svg index 19039462d..7070448ee 100644 --- a/docs/api/_images/power_plant_two_extractions.svg +++ b/docs/_static/images/power_plant_two_extractions.svg @@ -1,1372 +1,1372 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - G - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + G + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/scatterplot_efficiency_optimization.svg b/docs/_static/images/scatterplot_efficiency_optimization.svg similarity index 97% rename from docs/api/_images/scatterplot_efficiency_optimization.svg rename to docs/_static/images/scatterplot_efficiency_optimization.svg index 8f81d8085..7024547b7 100644 --- a/docs/api/_images/scatterplot_efficiency_optimization.svg +++ b/docs/_static/images/scatterplot_efficiency_optimization.svg @@ -1,1837 +1,1837 @@ - - - - - - - - - 2021-02-11T10:41:05.717444 - image/svg+xml - - - Matplotlib v3.3.3, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + 2021-02-11T10:41:05.717444 + image/svg+xml + + + Matplotlib v3.3.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/subsystem_waste_heat_generator.svg b/docs/_static/images/subsystem_waste_heat_generator.svg similarity index 97% rename from docs/api/_images/subsystem_waste_heat_generator.svg rename to docs/_static/images/subsystem_waste_heat_generator.svg index 5c103a5db..12fd93f52 100644 --- a/docs/api/_images/subsystem_waste_heat_generator.svg +++ b/docs/_static/images/subsystem_waste_heat_generator.svg @@ -1,1057 +1,1057 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - superheater - evaporator - economizer - drum - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + superheater + evaporator + economizer + drum + + diff --git a/docs/api/_images/tutorial_heat_pump.svg b/docs/_static/images/tutorial_heat_pump.svg similarity index 98% rename from docs/api/_images/tutorial_heat_pump.svg rename to docs/_static/images/tutorial_heat_pump.svg index cff5f1431..178fe9f1c 100644 --- a/docs/api/_images/tutorial_heat_pump.svg +++ b/docs/_static/images/tutorial_heat_pump.svg @@ -1,589 +1,589 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - source intercool - sink intercool - sink ambient - source ambient - - - - condenser - expansion valve - drum withevaporator - superheater - compressor train - coolant cycle closer(coolant in) - - consumer cycle closer - - - + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + source intercool + sink intercool + sink ambient + source ambient + + + + condenser + expansion valve + drum withevaporator + superheater + compressor train + coolant cycle closer(coolant in) + + consumer cycle closer + + + diff --git a/docs/api/_images/NH3_sankey.svg b/docs/_static/images/tutorials/heat_pump_exergy/NH3_sankey.svg similarity index 100% rename from docs/api/_images/NH3_sankey.svg rename to docs/_static/images/tutorials/heat_pump_exergy/NH3_sankey.svg diff --git a/docs/api/_images/diagram_E_D.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_E_D.svg similarity index 100% rename from docs/api/_images/diagram_E_D.svg rename to docs/_static/images/tutorials/heat_pump_exergy/diagram_E_D.svg diff --git a/docs/api/_images/diagram_cop_eps_Tgeo_Q.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q.svg similarity index 100% rename from docs/api/_images/diagram_cop_eps_Tgeo_Q.svg rename to docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q.svg diff --git a/docs/api/_images/diagram_cop_eps_Tgeo_Ths.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths.svg similarity index 100% rename from docs/api/_images/diagram_cop_eps_Tgeo_Ths.svg rename to docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths.svg diff --git a/docs/api/_images/diagram_eps_Tamb_Tgeo.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo.svg similarity index 100% rename from docs/api/_images/diagram_eps_Tamb_Tgeo.svg rename to docs/_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo.svg diff --git a/docs/api/_images/heat_pump_exergy_flowsheet.svg b/docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg similarity index 100% rename from docs/api/_images/heat_pump_exergy_flowsheet.svg rename to docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg diff --git a/docs/api/_images/tutorial_sv_COP_by_wf.svg b/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg similarity index 100% rename from docs/api/_images/tutorial_sv_COP_by_wf.svg rename to docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg diff --git a/docs/api/_images/tutorial_sv_heat_pump_intheatex.svg b/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet.svg similarity index 100% rename from docs/api/_images/tutorial_sv_heat_pump_intheatex.svg rename to docs/_static/images/tutorials/heat_pump_starting_values/flowsheet.svg diff --git a/docs/api/_images/tutorial_sv_logph.svg b/docs/_static/images/tutorials/heat_pump_starting_values/logph.svg similarity index 100% rename from docs/api/_images/tutorial_sv_logph.svg rename to docs/_static/images/tutorials/heat_pump_starting_values/logph.svg diff --git a/docs/_templates/index.html b/docs/_templates/index.html new file mode 100644 index 000000000..e69de29bb diff --git a/docs/analyses/exergy.rst b/docs/advanced/exergy.rst similarity index 93% rename from docs/analyses/exergy.rst rename to docs/advanced/exergy.rst index 733cba6d9..bdd5d53b3 100644 --- a/docs/analyses/exergy.rst +++ b/docs/advanced/exergy.rst @@ -1,11 +1,20 @@ +.. _tespy_advanced_exergy_label: + +~~~~~~~~~~~~~~~ Exergy analysis -=============== +~~~~~~~~~~~~~~~ + +Performing thermodynamic cycle analyses making use of the second law of +thermodynamics provides further process information and uncovers potentials for +improvement in power plant engineering. Therefore, TESPy's analyses module +provides you with an inbuilt and fully automatic exergy analysis. + We have published a paper with the features described in this section. The publication is licensed under an open-access license, download the pdf at https://doi.org/10.3390/en15114087, also see :cite:`Witte2022`. Fundamentals of exergy analysis -------------------------------- +=============================== Energy is a concept of the first law of thermodynamics. It cannot be destroyed. But regarding the design and analysis of thermal systems, the idea that something can be destroyed is useful. According to the second law of @@ -31,7 +40,7 @@ In literature, exergy is defined as follows: :cite:`Bejan1996` Terminology ------------ +=========== The definitions and nomenclature of the exergy analysis in TESPy are based on :cite:`Tsatsaronis2007`. The exergy destruction ratios are described in more detail in :cite:`Bejan1996`. Since the current version of the exergy analysis @@ -105,7 +114,7 @@ potential exergy are neglected and therefore not considered as well. temperature are implemented as well, but are not yet fully tested. Tutorial --------- +======== In this short tutorial, an exergy analysis is carried out for the so called "Solar Energy Generating System" (SEGS). The full python script is available on GitHub in an individual repository: https://github.com/fwitte/SEGS_exergy. @@ -125,7 +134,7 @@ exctracted for preheating. Finally, the main condenser of the steam cycle is connected to an air cooling tower. The figure below shows the topology of the model. -.. figure:: /api/_images/SEGS_flowsheet.svg +.. figure:: /_static/images/advanced/exergy/flowsheet.svg :align: center :alt: Topology of the Solar Energy Generating System (SEGS) @@ -136,7 +145,7 @@ pressure turbine's last stage outlet than at its inlet :cite:`Lippke1995`. As mentioned, you can find all data in the respective GitHub repository. TESPy model -^^^^^^^^^^^ +----------- The TESPy model consists of 53 components. The feed water tank serves as mixing preheater, thus can be modeled using a merge. All other components are modeled highlighted in the flowsheet. The preheaters and the main condenser are modeled @@ -184,7 +193,7 @@ subcoolers, the missing connections and components are added in a second step and the model is again solved. Analysis setup -^^^^^^^^^^^^^^ +-------------- After the simulation of the plant, the exergy analysis can be carried out. To perform it, all exergy streams leaving or entering the network's system boundaries have to be defined by the user. These are: @@ -206,18 +215,20 @@ loss. .. code-block:: python power = Bus('total output power') - power.add_comps({'comp': hpt1, 'char': 0.97, 'base': 'component'}, - {'comp': hpt2, 'char': 0.97, 'base': 'component'}, - {'comp': lpt1, 'char': 0.97, 'base': 'component'}, - {'comp': lpt2, 'char': 0.97, 'base': 'component'}, - {'comp': lpt3, 'char': 0.97, 'base': 'component'}, - {'comp': lpt4, 'char': 0.97, 'base': 'component'}, - {'comp': lpt5, 'char': 0.97, 'base': 'component'}, - {'comp': fwp, 'char': 0.95, 'base': 'bus'}, - {'comp': condpump, 'char': 0.95, 'base': 'bus'}, - {'comp': ptpump, 'char': 0.95, 'base': 'bus'}, - {'comp': cwp, 'char': 0.95, 'base': 'bus'}, - {'comp': fan, 'char': 0.95, 'base': 'bus'}) + power.add_comps( + {'comp': hpt1, 'char': 0.97, 'base': 'component'}, + {'comp': hpt2, 'char': 0.97, 'base': 'component'}, + {'comp': lpt1, 'char': 0.97, 'base': 'component'}, + {'comp': lpt2, 'char': 0.97, 'base': 'component'}, + {'comp': lpt3, 'char': 0.97, 'base': 'component'}, + {'comp': lpt4, 'char': 0.97, 'base': 'component'}, + {'comp': lpt5, 'char': 0.97, 'base': 'component'}, + {'comp': fwp, 'char': 0.95, 'base': 'bus'}, + {'comp': condpump, 'char': 0.95, 'base': 'bus'}, + {'comp': ptpump, 'char': 0.95, 'base': 'bus'}, + {'comp': cwp, 'char': 0.95, 'base': 'bus'}, + {'comp': fan, 'char': 0.95, 'base': 'bus'} + ) heat_input_bus = Bus('heat input') heat_input_bus.add_comps({'comp': pt, 'base': 'bus'}) @@ -267,7 +278,7 @@ state temperature value to 15 °C. :code:`ExergyAnalysis` class needs to be defined. Checking consistency -^^^^^^^^^^^^^^^^^^^^ +-------------------- An automatic check of consistency is performed by the analysis. The sum of all exergy destruction values of the network's components and the exergy destruction on the respective busses is calculated. On top of that, fuel and @@ -343,7 +354,7 @@ exergy, while the product is the electrical energy. in the form of a Grassmann diagram. Accessing the data -^^^^^^^^^^^^^^^^^^ +------------------ The underlying data for the tabular printouts are stored in `pandas DataFrames `_. Therefore, you can easily access and process these data. To access these use @@ -362,7 +373,7 @@ Lastly, the analysis also provides an input data generator for plotly's `sankey diagram `_. Plotting -^^^^^^^^ +-------- To use the plotly library, you'll need to install it first. Please check the respective documentation on plotly's documentation. Generating a sankey diagram is then easily done: @@ -378,11 +389,13 @@ diagram is then easily done: node={ 'label': nodes, 'pad':11, - 'color': 'orange'}, - link=links)) + 'color': 'orange' + }, + link=links + )) fig.show() -.. figure:: /api/_images/SEGS_sankey.png +.. figure:: /_static/images/advanced/exergy/sankey.png :align: center :alt: Sankey diagram of the Soler Energy Generating System (SEGS) @@ -445,7 +458,7 @@ handle the data by yourself. Conclusion ----------- +========== An additional example is available in the API documentation of the :py:class:`tespy.tools.analyses.ExergyAnalysis` class. Full testing of exergy analysis at temperature levels below the ambient temperature will be diff --git a/docs/advanced/optimization.rst b/docs/advanced/optimization.rst new file mode 100644 index 000000000..dfee0e25d --- /dev/null +++ b/docs/advanced/optimization.rst @@ -0,0 +1,4 @@ +.. _tespy_advanced_optimization_label: + +Optimization with pygmo +======================= diff --git a/docs/api/_images/NH3_sankey.html b/docs/api/_images/NH3_sankey.html deleted file mode 100644 index 88c2f26f3..000000000 --- a/docs/api/_images/NH3_sankey.html +++ /dev/null @@ -1,67 +0,0 @@ - - - -
-
- - \ No newline at end of file diff --git a/docs/api/_images/basic.svg b/docs/api/_images/basic.svg deleted file mode 100644 index d0e2192c2..000000000 --- a/docs/api/_images/basic.svg +++ /dev/null @@ -1,916 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - G - - - - - - - - - - - - - - diff --git a/docs/api/_images/basic_efficiency.svg b/docs/api/_images/basic_efficiency.svg deleted file mode 100644 index 081cd4e24..000000000 --- a/docs/api/_images/basic_efficiency.svg +++ /dev/null @@ -1,1043 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/api/_images/cc_bp.svg b/docs/api/_images/cc_bp.svg deleted file mode 100644 index 4e2047d09..000000000 --- a/docs/api/_images/cc_bp.svg +++ /dev/null @@ -1,1218 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - G - - - - - - - - - - - - - - - - - - - - - G - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/api/_images/chp.svg b/docs/api/_images/chp.svg deleted file mode 100644 index a8c397868..000000000 --- a/docs/api/_images/chp.svg +++ /dev/null @@ -1,1089 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - G - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/api/_images/chp_PQ.svg b/docs/api/_images/chp_PQ.svg deleted file mode 100644 index 1107b49ad..000000000 --- a/docs/api/_images/chp_PQ.svg +++ /dev/null @@ -1,1579 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/api/tespy.components.rst b/docs/api/components.rst similarity index 100% rename from docs/api/tespy.components.rst rename to docs/api/components.rst diff --git a/docs/api/tespy.connections.rst b/docs/api/connections.rst similarity index 95% rename from docs/api/tespy.connections.rst rename to docs/api/connections.rst index 9f7be091a..0cea7a70e 100644 --- a/docs/api/tespy.connections.rst +++ b/docs/api/connections.rst @@ -1,23 +1,23 @@ -tespy.connections module -======================== - -.. automodule:: tespy.connections - :members: - :undoc-members: - :show-inheritance: - -tespy.connections.bus module ----------------------------- - -.. automodule:: tespy.connections.bus - :members: - :undoc-members: - :show-inheritance: - -tespy.connections.connection module ------------------------------------ - -.. automodule:: tespy.connections.connection - :members: - :undoc-members: - :show-inheritance: +tespy.connections module +======================== + +.. automodule:: tespy.connections + :members: + :undoc-members: + :show-inheritance: + +tespy.connections.bus module +---------------------------- + +.. automodule:: tespy.connections.bus + :members: + :undoc-members: + :show-inheritance: + +tespy.connections.connection module +----------------------------------- + +.. automodule:: tespy.connections.connection + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/tespy.data.rst b/docs/api/data.rst similarity index 100% rename from docs/api/tespy.data.rst rename to docs/api/data.rst diff --git a/docs/api/tespy.networks.rst b/docs/api/networks.rst similarity index 95% rename from docs/api/tespy.networks.rst rename to docs/api/networks.rst index 2592e2903..5f9217788 100644 --- a/docs/api/tespy.networks.rst +++ b/docs/api/networks.rst @@ -1,23 +1,23 @@ -tespy.networks module -===================== - -.. automodule:: tespy.networks - :members: - :undoc-members: - :show-inheritance: - -tespy.networks.network module ------------------------------ - -.. automodule:: tespy.networks.network - :members: - :undoc-members: - :show-inheritance: - -tespy.networks.network_reader module ------------------------------------- - -.. automodule:: tespy.networks.network_reader - :members: - :undoc-members: - :show-inheritance: +tespy.networks module +===================== + +.. automodule:: tespy.networks + :members: + :undoc-members: + :show-inheritance: + +tespy.networks.network module +----------------------------- + +.. automodule:: tespy.networks.network + :members: + :undoc-members: + :show-inheritance: + +tespy.networks.network_reader module +------------------------------------ + +.. automodule:: tespy.networks.network_reader + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/tespy.tools.rst b/docs/api/tools.rst similarity index 100% rename from docs/api/tespy.tools.rst rename to docs/api/tools.rst diff --git a/docs/basics.rst b/docs/basics.rst new file mode 100644 index 000000000..55190a273 --- /dev/null +++ b/docs/basics.rst @@ -0,0 +1,16 @@ +Basics +~~~~~~ + +* :py:mod:`Components ` +* :py:mod:`Connections and Busses ` +* :py:mod:`Networks ` +* :py:mod:`Importing Networks ` + +.. toctree:: + :maxdepth: 1 + :glob: + + basics/heat_pump.rst + basics/rankine_cycle.rst + basics/gas_turbine.rst + basics/district_heating.rst diff --git a/docs/basics/district_heating.rst b/docs/basics/district_heating.rst new file mode 100644 index 000000000..da0f4eb67 --- /dev/null +++ b/docs/basics/district_heating.rst @@ -0,0 +1,16 @@ +.. _tespy_basics_district_heating: + +District Heating Network +======================== + +.. figure:: /_static/images/basics/district_heating.svg + :align: center + :class: only-light + + Figure: Topology of the district heating network + +.. figure:: /_static/images/basics/district_heating_darkmode.svg + :align: center + :class: only-dark + + Figure: Topology of the district heating network diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst new file mode 100644 index 000000000..3afbb2e79 --- /dev/null +++ b/docs/basics/gas_turbine.rst @@ -0,0 +1,16 @@ +.. _tespy_basics_gas_turbine: + +Gas Turbine +=========== + +.. figure:: /_static/images/basics/gas_turbine.svg + :align: center + :class: only-light + + Figure: Topology of the gas turbine + +.. figure:: /_static/images/basics/gas_turbine_darkmode.svg + :align: center + :class: only-dark + + Figure: Topology of the gas turbine diff --git a/docs/basics/heat_pump.rst b/docs/basics/heat_pump.rst new file mode 100644 index 000000000..7aab59dc7 --- /dev/null +++ b/docs/basics/heat_pump.rst @@ -0,0 +1,16 @@ +.. _tespy_basics_heat_pump: + +Heat Pump +========= + +.. figure:: /_static/images/basics/heat_pump.svg + :align: center + :class: only-light + + Figure: Topology of the basic heat pump + +.. figure:: /_static/images/basics/heat_pump_darkmode.svg + :align: center + :class: only-dark + + Figure: Topology of the basic heat pump diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst new file mode 100644 index 000000000..968f16b99 --- /dev/null +++ b/docs/basics/rankine_cycle.rst @@ -0,0 +1,16 @@ +.. _tespy_basics_rankine_cycle: + +Rankine Cycle +============= + +.. figure:: /_static/images/basics/rankine_cycle.svg + :align: center + :class: only-light + + Figure: Topology of the basic rankine cycle + +.. figure:: /_static/images/basics/rankine_cycle_darkmode.svg + :align: center + :class: only-dark + + Figure: Topology of the basic rankine cycle diff --git a/docs/benchmarks.rst b/docs/benchmarks.rst new file mode 100644 index 000000000..40919da2f --- /dev/null +++ b/docs/benchmarks.rst @@ -0,0 +1,4 @@ +Benchmarks +========== + + diff --git a/docs/conf.py b/docs/conf.py index 8d2d1336d..39749f058 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,20 +1,7 @@ # -*- coding: utf-8 -*- -# -# oemof documentation build configuration file, created by -# sphinx-quickstart on Thu Dec 18 16:57:35 2014. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. import os import sys -import sphinx_rtd_theme import tespy @@ -25,125 +12,79 @@ # -- General configuration ------------------------------------------------ -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', + 'sphinx.ext.coverage', + 'sphinx.ext.doctest', + 'sphinx.ext.extlinks', + 'sphinx.ext.ifconfig', 'sphinx.ext.imgmath', 'sphinx.ext.napoleon', + 'sphinx.ext.todo', 'sphinx.ext.viewcode', - 'sphinxcontrib.bibtex' + 'sphinx_copybutton', + 'sphinx_inline_tabs', + 'sphinxcontrib.bibtex', ] -bibtex_bibfiles = ['references.bib'] - -numpydoc_show_class_members = False - -# -autoclass_content = 'both' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' +# landing page +master_doc = 'contents' +# names, years, etc +project = 'TESPy' +year = '2022' +author = 'Francesco Witte' +copyright = '{0}, {1}'.format(year, author) -# General information about the project. -project = u'tespy' -copyright = u'2018-2020, Francesco Witte' -author = u'Francesco Witte' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# # The short X.Y version. version = tespy.__version__.split(' ')[0] # The full version, including alpha/beta/rc tags. release = tespy.__version__ -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# The suffix of source filenames. +source_suffix = '.rst' +# folder for templates +templates_path = ['_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build', 'whatsnew/*'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False +exclude_patterns = ['_build'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' +pygments_style = 'trac' -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# show all class members +# numpydoc_show_class_members = False -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False +# place for bibtex references +bibtex_bibfiles = ['references.bib'] +# links to github +extlinks = { + 'issue': ('https://github.com/oemof/tespy/issues/%s', '#'), + 'pr': ('https://github.com/oemof/tespy/pull/%s', 'PR #'), +} # -- Options for HTML output ---------------------------------------------- -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -#html_theme = 'bizstyle' - -html_theme = "sphinx_rtd_theme" - -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = { -# "sidebarwidth": "25em", -# "documentwidth":"50em", -# "pagewidth": "75em", -# } - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# The theme to use for HTML and HTML Help pages. +html_theme = 'furo' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None + # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +html_short_title = '%s-%s' % (project, version) -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None -html_logo = './api/_images/logo_tespy_mid.svg' +# Some more stuff +html_use_smartypants = True +html_last_updated_fmt = '%b %d, %Y' +html_split_index = False # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 @@ -153,55 +94,38 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['./_build/_static'] - -html_css_files = ['css/custom.css', ] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +html_static_path = ['_static'] +html_css_files = [ + 'css/custom.css', +] +html_additional_pages = { + "index": "index.html" +} -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +html_sidebars = { + '**': [ + 'sidebar/brand.html', + 'sidebar/search.html', + 'sidebar/scroll-start.html', + 'sidebar/navigation.html', + 'sidebar/ethical-ads.html', + 'sidebar/scroll-end.html', + 'sidebar/variant-selector.html', + ], +} -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +html_theme_options = { + "light_logo": "./images/logo_tespy_mid.svg", + "dark_logo": "./images/logo_tespy_mid_darkmode.svg", +} -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' +napoleon_use_ivar = True +napoleon_use_rtype = False +napoleon_use_param = False -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# copybutton configuration +copybutton_prompt_text = r'>>> |\.\.\. ' +copybutton_prompt_is_regexp = True # Output file base name for HTML help builder. htmlhelp_basename = 'tespy_doc' diff --git a/docs/contents.rst b/docs/contents.rst new file mode 100644 index 000000000..7b0459787 --- /dev/null +++ b/docs/contents.rst @@ -0,0 +1,54 @@ +.. _tespy_label: + +.. include:: introduction.rst + + +Contents +======== + +.. toctree:: + :maxdepth: 2 + :caption: Quickstart + + introduction + +.. toctree:: + :maxdepth: 2 + :caption: User Guide + + installation + basics + tutorials + examples + regular_meeting + +.. toctree:: + :maxdepth: 2 + :caption: Documentation + + modules + benchmarks + api + whats_new + zliterature + +.. toctree:: + :maxdepth: 2 + :caption: Advanced Features + + advanced/exergy + advanced/optimization + +.. toctree:: + :maxdepth: 2 + :caption: Contribute to TESPy + + development/what + development/how + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/developing_tespy.rst b/docs/development/how.rst similarity index 66% rename from docs/developing_tespy.rst rename to docs/development/how.rst index ed7fb1990..fb690e4b6 100644 --- a/docs/developing_tespy.rst +++ b/docs/development/how.rst @@ -1,42 +1,11 @@ -.. _developing_tespy_label: +.. _tespy_development_how_label: -Developing TESPy -================ - -TESPy has been developed mainly by Francesco Witte at the University of Applied -Sciences Flensburg. We hope that many people can make use of this project and -that it will be a community driven project in the future, as users might demand -special components or flexible implementations of characteristics, custom -equations, basically what ever you can think of. - -We want to invite you to join the developing process and share your ideas. Your -solutions may help other users as well. Contributing to the development of -TESPy may help other people and it improves the quality of your code as it will -be reviewed by other developers. - -The easiest way of joining the developing process is by improving the -documentation. If you spot mistakes or think, the documentation could be more -precise or clear in some sections, feel free to fix it and create a pull -request on the github repository. - -Another simple first step is to program your own custom subsystems and share -them in the community. For a good start just look into our tutorial -:ref:`How do I create custom subsystems `. - -A third, highly appreciated way for you to contribute is the provision of new -and/or improved equations, maybe even whole characteristics for single -components, such as compressor maps, characteristics for turbine efficiency or -heat transfer coefficients etc.. +How to contribute +================= You will find the most important information concerning the development process in the following sections. If you have any further questions feel free to -contact us, we are looking forward to hearing -from you! - -.. contents:: - :depth: 1 - :local: - :backlinks: top +contact us, we are looking forward to hearing from you! Install the developer version ----------------------------- @@ -48,7 +17,7 @@ repository and install development requirements with pip. .. code:: bash - git clone https://github.com/YOUR_GITHUB_USERNAME/tespy.git + git clone https://github.com/YOUR_GITHUB_USERNAME/tespy.git cd tespy pip install -e .[dev] @@ -60,55 +29,15 @@ the example below). .. code:: bash - git remote add upstream https://github.com/oemof/tespy.git - git fetch upstream - git pull upstream dev --rebase + git remote add upstream https://github.com/oemof/tespy.git + git fetch upstream + git pull upstream dev --rebase Use the :code:`--rebase` comand to avoid merge commits fo every upstream pull. If you want to make changes to tespy, checkout a new branch from your local dev branch. Make your changes, commit them and create a PR on the oemof/tespy dev branch. -Your contribution ------------------ - -There are different ways you can contribute - -Contribute to the documentation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If you come across typos or grammatical mistakes or want to improve -comprehensibility of the documentation, make your adjustments or suggestions -and create a pull request for the dev branch. We appreciate your contribution! - -Improve or add new equations -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The components equations represent the behavior of each component. Are we -missing any equations? Or do you see possibilities to improve the formulation? -Add them to your code and create a pull request on the dev branch. - -Share your subsystems -^^^^^^^^^^^^^^^^^^^^^ - -You have encountered component groups that are frequently required? Create a -subsystem to simplify your own work and share your subsystem by adding it to -the tespy.components.subsystems file. - -For both, **the equations and the subsystems**, please provide the docstring -and maybe inline comments, if you want to make the code more comprehensible. In -general, your code should fit to the :ref:`style_guidlines_label`, a complete -documentation is only required, if the code will be added to TESPy permanently. - -Add component characteristics -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The component characteristics represent large added value for your calculation. -If you have detailed information on components offdesign behavior - even for -specific cases - it will improve the results. Every user can benefit from this -knowlegde and thus we are very happy to discuss about the implementation of new -characteristics. - Collaboration with pull requests -------------------------------- diff --git a/docs/development/what.rst b/docs/development/what.rst new file mode 100644 index 000000000..796a58a0c --- /dev/null +++ b/docs/development/what.rst @@ -0,0 +1,56 @@ +.. __tespy_development_what_label: + +What can I contribute +===================== +TESPy has been developed mainly by Francesco Witte at the University of Applied +Sciences Flensburg - and a lot of free time. We hope that many people can make +use of this project and that it will be a community driven project in the +future, as users might demand special components or flexible implementations of +characteristics, custom equations, basically what ever you can think of. + +Therefore we would like to invite you to contribute in this process, share your +ideas and experience and maybe start developing the software. Your solutions +may help other users as well. Contributing to the development of TESPy is easy +and will help the development team and all other users of the software. If you +start to develop features it may also improve the quality of your code as it +will be reviewed by other developers. + +There are a variety of different ways you can contribute to the development, +amongst others, these may be: + +Contribute to the documentation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The easiest way of joining the developing process is by improving the +documentation. If you spot mistakes or think, the documentation could be more +precise or clear in some sections, feel free to fix it and create a pull +request on the github repository. + +If you come across typos or grammatical mistakes or want to improve +comprehensibility of the documentation, make your adjustments or suggestions +and create a pull request for the dev branch. We appreciate your contribution! + +Share your projects +^^^^^^^^^^^^^^^^^^^ +You have used the software in your research paper or project, maybe even in a +real world application? We would love to feature your project on our +:ref:`Real World Application ` page. Please reach out to +us by opening a new issue on our github page. + +Add new component equations +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The components equations represent the behavior of each component. Do you miss +equations? Open a discussion on the github discussions page or add them to your +fork of TESPy and create a pull request on the dev branch. + +Add component characteristics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Another highly appreciated way for you to contribute is the provision of new +and/or improved characteristics for single components, such as compressor +efficiency maps, characteristics for turbine efficiency or heat transfer +coefficients etc.. + +The component characteristics represent large added value for your calculation. +If you have detailed information on components offdesign behavior - even for +specific cases - it will improve the results. Every user can benefit from this +knowlegde and thus we are very happy to discuss about the implementation of new +characteristics. diff --git a/docs/examples.rst b/docs/examples.rst new file mode 100644 index 000000000..944890f4c --- /dev/null +++ b/docs/examples.rst @@ -0,0 +1,36 @@ +.. _tespy_examples_label: + +~~~~~~~~~~~~~~~~~~~~~~~ +Real World Applications +~~~~~~~~~~~~~~~~~~~~~~~ + +In the example section we provide a variety of TESPy applications, among +others: + +* a very basic model of the clausius rankine process, +* the calculation of backpressure lines of a combined heat and power cycle at + different loads and feed flow temperature levels, +* modeling approach for a district heating system with various consumers and + system infrastructure as well as +* the COP of a heat pump dependent on load, ambient temperature and heat + delivering fluid (air vs. water). + +You can find all examples in the TESPy +`examples repository `__ +on github. Additional small examples can be found in the API-documentation. + +.. _basic_example_label: +.. include:: tutorials_examples/clausius_rankine.rst +.. _combined_cycle_example_label: +.. include:: tutorials_examples/combined_cycle_chp.rst +.. _chp_example_label: +.. include:: tutorials_examples/clausius_rankine_chp.rst +.. _combustion_engine_label: +.. include:: tutorials_examples/combustion_engine.rst +.. _dh_example_label: +.. include:: tutorials_examples/district_heating.rst +.. _heat_pump_cop_label: +.. include:: tutorials_examples/heat_pump.rst +.. _solar_collector_example_label: +.. include:: tutorials_examples/solar_collector.rst +.. _tespy_tutorial_label: diff --git a/docs/first_steps.rst b/docs/first_steps.rst index 119f546a9..f7d01412e 100644 --- a/docs/first_steps.rst +++ b/docs/first_steps.rst @@ -46,7 +46,7 @@ Set up components ----------------- The list of components available can be found -:ref:`here `. If you set up a component you have +:ref:`here `. If you set up a component you have to specify a (within one network) unique label. Moreover, it is possible to specify parameters for the component, for example power :math:`P` for a turbine or upper terminal temperature difference :math:`ttd_\mathrm{u}` of a heat @@ -119,7 +119,7 @@ way as parameters are set for components. The basic specification options are: .. note:: There are more specification options available. Please refer to - the :ref:`connections section ` in the TESPy + the :ref:`connections section ` in the TESPy modules chapter for detailed information. The specification options are stated in the connection class documentation, too: diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 68c46cc0a..000000000 --- a/docs/index.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _tespy_label: - -.. include:: introduction.rst - - -Contents -======== - -.. toctree:: - :maxdepth: 2 - - introduction - installation - first_steps - regular_meeting - tutorials_examples - tespy_modules - tespy_analyses - developing_tespy - whats_new - zliterature - api - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/installation.rst b/docs/installation.rst index b7e2976fa..84d9adad3 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -4,109 +4,66 @@ Installation and setup ###################### -.. contents:: - :depth: 1 - :local: - :backlinks: top +Following you find guidelines for the installation process for linux and +windows. TESPy is a Python package, thus it requires you to have Python 3 +installed. +.. tab:: Linux -Following you find guidelines for the installation process for different -operation systems. + **Installing Python 3** -Linux -===== + Most Linux distributions will have Python 3 in their repository. Use the + specific software management to install it, if it is not yet installed. If + you are using Ubuntu/Debian try executing the following code in your + terminal: -Installing Python 3 -------------------- + .. code:: console -TESPy is a Python package, thus it requires you to have Python 3 installed. -Most Linux distributions will have Python 3 in their repository. Use the -specific software management to install it. If you are using Ubuntu/Debian try -executing the following code in your terminal: + sudo apt-get install python3 -.. code:: console + You can also download different versions of Python via + https://www.python.org/downloads/. - sudo apt-get install python3 + **Having Python 3 installed** -You can also download different versions of Python via -https://www.python.org/downloads/. + We recommend installting TESPy within a virtual Python enviroment an not + into the base, system wide Python installation. On Linux you can use + virtualenv to do so. -Having Python 3 installed -------------------------- + 1. Install virtualenv using the package management of your Linux distribution, + pip install or install it from source + (`see virtualenv documentation `_) + 2. Open terminal to create and activate a virtual environment by typing: -.. code:: console + .. code-block:: console - pip install tespy + virtualenv -p /usr/bin/python3 your_env_name + source your_env_name/bin/activate -To use pip you have to install the pypi package. Normally pypi is part of your -virtual environment. + 3. In terminal type: :code:`pip install tespy` -.. _virtualenv_label: + Warning: If you have an older version of virtualenv you should update pip + :code:`pip install --upgrade pip`. -Using virtualenv instead of system wide Python ----------------------------------------------- + **Using Conda** -Instead of installing TESPy with pip to your system Python, you can instead -install TESPy to a virtual Python environment. + Alternatively you can use conda for enviroment and package management. You + can follow the installation instructions for windows users. - 1. Install virtualenv using the package management of your Linux distribution, - pip install or install it from source - (`see virtualenv documentation `_) - 2. Open terminal to create and activate a virtual environment by typing: +.. tab:: Windows - .. code-block:: console + For windows we recommend using conda as package manager. You can download a + light weight open source variant of conda: "miniforge3". - virtualenv -p /usr/bin/python3 your_env_name - source your_env_name/bin/activate + 1. Download latest `miniforge3 `__ + for Python 3.x (64 or 32 bit). + 2. Install miniforge3 + 3. Open "miniforge prompt" to manage your virtual environments. You can + create a new environment and acivate it by - 3. In terminal type: :code:`pip install tespy` + .. code-block:: console -Warning: If you have an older version of virtualenv you should update pip -:code:`pip install --upgrade pip`. + conda create -n tespy-env python=3.9 + activate tespy-env -.. _tespy_installation_windows_label: - -Windows -======= - -Having Python 3 installed -------------------------- - -If you already have a working Python 3 environment you can install TESPy by -using pip. We recommend you installing the package in a virtual environment. -You can use virtualenv (:ref:`see here for instructions `) -or a virtual environment e.g. in :ref:`Anaconda `. - -.. code:: console - - pip install tespy - -If you encounter any errors within the installation of the package, please let -us know by opening an issue on our GitHub repository. Also, if pip is not part -of your python environment, you have to install the pypi package. - -.. _anaconda_label: - -Using Anaconda --------------- - - 1. Download latest `Anaconda `_ - for Python 3.x (64 or 32 bit). - 2. Install Anaconda - 3. Open 'Anaconda Prompt' to create and activate a virtual environment by - typing: - - .. code-block:: console - - conda create -n yourenvname python=3.x - activate yourenvname - - 4. In the active Anaconda Prompt type: :code:`pip install tespy` - - -Mac OSX -======= - -Installation instructions for Mac OSX are not available, yet. If you want to -share your knowledge on the installation and fill this gap, feel free to -contact us. + 4. In the active prompt type: :code:`pip install tespy` diff --git a/docs/introduction.rst b/docs/introduction.rst index 40d9ddfc7..a24898962 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -8,8 +8,14 @@ plants, district heating systems or heat pumps. It is an external extension module within the `Open Energy Modeling Framework `_ and can be used as a standalone package. -.. figure:: /api/_images/logo_tespy_big.svg - :align: center +.. image:: /_static/images/logo_tespy_big.svg + :align: center + :class: only-light + + +.. image:: /_static/images/logo_tespy_big_darkmode.svg + :align: center + :class: only-dark With the TESPy package you are able to calculate stationary operation in order to design the process of your plant. From that point it is possible to @@ -36,11 +42,6 @@ Key Features component groups * **Postprocessing** features like exergy analysis and fluid property plotting -.. contents:: - :depth: 1 - :local: - :backlinks: top - Quick installation ================== @@ -79,7 +80,9 @@ As TESPy is a free software, we kindly ask that you add a reference to TESPy if you use the software for your scientific work. Please cite the article with the BibTeX citation below. -BibTeX citation:: +BibTeX citation + +.. code:: @article{Witte2020, doi = {10.21105/joss.02178}, @@ -100,22 +103,4 @@ zenodo. Find your version here: https://doi.org/10.5281/zenodo.2555866. License ======= -Copyright (c) 2017-2021 oemof developer group - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +.. include:: ../LICENSE diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 000000000..4d5eb27df --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,24 @@ +.. _tespy_modules_label: + +~~~~~~~~~~~~~ +TESPy modules +~~~~~~~~~~~~~ + +The following sections give a detailed overview on the modules of TESPy. This +includes all important settings of networks, components and connections as well +as the underlying functionalities of the software. + +At the end of this page, we provide an example on how to couple energy system +simulation with TESPy. + +.. toctree:: + :maxdepth: 1 + :glob: + + tespy_modules/networks.rst + tespy_modules/components.rst + tespy_modules/subsystems.rst + tespy_modules/connections.rst + tespy_modules/characteristics.rst + tespy_modules/fluid_properties.rst + tespy_modules/other.rst diff --git a/docs/regular_meeting.rst b/docs/regular_meeting.rst index cbe2b817f..8867f35e9 100644 --- a/docs/regular_meeting.rst +++ b/docs/regular_meeting.rst @@ -1,13 +1,8 @@ .. _installation_and_setup_label: -############################### -Get in touch with the community -############################### - -.. contents:: - :depth: 1 - :local: - :backlinks: top +############### +TESPy community +############### Online "Stammtisch" =================== diff --git a/docs/requirements.txt b/docs/requirements.txt index b20b9fffe..0e8ec6137 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,5 @@ +furo sphinx>=1.3 -sphinx-rtd-theme sphinxcontrib-bibtex +sphinx-copybutton +sphinx-inline-tabs diff --git a/docs/tespy_analyses.rst b/docs/tespy_analyses.rst deleted file mode 100644 index ffe757640..000000000 --- a/docs/tespy_analyses.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _tespy_analyses_label: - -~~~~~~~~~~~~~~~~~~~~~~ -Thermodynamic analyses -~~~~~~~~~~~~~~~~~~~~~~ - -Performing thermodynamic cycle analyses making use of the second law of -thermodynamics provides further process information and uncovers potentials for -improvement in power plant engineering. Therefore, TESPy's analyses module -provides you with an inbuilt and fully automatic exergy analysis. Adding -entropy analysis is planned for the future. - -.. contents:: `Contents` - :depth: 1 - :local: - :backlinks: top - -.. _tespy_analyses_exergy_label: -.. include:: analyses/exergy.rst diff --git a/docs/tespy_modules.rst b/docs/tespy_modules.rst deleted file mode 100644 index b0cae9c53..000000000 --- a/docs/tespy_modules.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. _tespy_modules_label: - -~~~~~~~~~~~~~ -TESPy modules -~~~~~~~~~~~~~ - -The following sections give a detailed overview on the modules of TESPy. This -includes all important settings of networks, components and connections as well -as the underlying functionalities of the software. - -At the end of this page, we provide an example on how to couple energy system -simulation with TESPy. - -.. contents:: `Contents` - :depth: 1 - :local: - :backlinks: top - -.. _tespy_modules_network_label: -.. include:: tespy_modules/networks.rst -.. _using_tespy_components_label: -.. include:: tespy_modules/components.rst -.. include:: tespy_modules/subsystems.rst -.. _using_tespy_connections_label: -.. include:: tespy_modules/connections.rst -.. _using_tespy_characteristics_label: -.. include:: tespy_modules/characteristics.rst -.. _tespy_fluid_properties_label: -.. include:: tespy_modules/fluid_properties.rst -.. _tespy_other_label: -.. include:: tespy_modules/other.rst diff --git a/docs/tespy_modules/characteristics.rst b/docs/tespy_modules/characteristics.rst index 8c9c7e62e..22130803b 100644 --- a/docs/tespy_modules/characteristics.rst +++ b/docs/tespy_modules/characteristics.rst @@ -1,3 +1,5 @@ +.. _tespy_modules_characteristics_label: + Characteristics =============== @@ -6,7 +8,7 @@ implementation. There two different types of characteristics available in TESPy: lines (:py:class:`CharLine `) and maps (:py:class:`CharMap `). The default characteristics available are to be found in the -:ref:`tespy_data_label` module documentation. +:ref:`tespy_data_label` documentation. Characteristic lines -------------------- diff --git a/docs/tespy_modules/components.rst b/docs/tespy_modules/components.rst index f44da404d..1075ad3d2 100644 --- a/docs/tespy_modules/components.rst +++ b/docs/tespy_modules/components.rst @@ -1,3 +1,5 @@ +.. _tespy_modules_components_label: + Components ========== @@ -65,7 +67,7 @@ Here we list the components integrated in the customs module. - :py:class:`Evaporator for two-phase geothermal organic rankine cycle ` -.. _using_tespy_components_parametrisation_label: +.. _tespy_modules_components_parametrisation_label: Component parametrisation ------------------------- @@ -310,7 +312,7 @@ Instead of writing your custom characteristic line information directly into your Python script, TESPy provides a second method of implementation: It is possible to store your data in the :code:`HOME/.tespy/data` folder and import from there. For additional information on formatting and usage, look into -:ref:`this part `. +:ref:`this part `. .. code-block:: python @@ -376,7 +378,7 @@ Characteristics are available for the following components and parameters: * :py:meth:`eta_char `: efficiency vs. load ratio. For more information on how the characteristic functions work -:ref:`click here `. +:ref:`click here `. Extend components with new equations ------------------------------------ @@ -523,7 +525,7 @@ characteristic lines or characteristic maps are loaded automatically by the component initialisation method of class :py:class:`tespy.components.component.Component`. For more information on the default characteristics consider this -:ref:`chapter `. +:ref:`chapter `. The structure is very similar to the mandatory constraints, using DataContainers instead of dictionaries, e.g. for the Valve: diff --git a/docs/tespy_modules/connections.rst b/docs/tespy_modules/connections.rst index 566570ce3..da043de1d 100644 --- a/docs/tespy_modules/connections.rst +++ b/docs/tespy_modules/connections.rst @@ -1,348 +1,350 @@ -Connections -=========== - -This section provides an overview of the parametrisation of connections, the -usage of references and busses (connections for energy flow). - -Parametrisation ---------------- - -As mentioned in the introduction, for each connection you can specify the -following parameters: - - * mass flow* (m), - * volumetric flow (v), - * pressure* (p), - * enthalpy* (h), - * temperature* (T), - * vapor mass fraction for pure fluids (x), - * a fluid vector (fluid) and - * a balance closer for the fluid vector (fluid_balance). - -It is possible to specify values, starting values, references and data -containers. The data containers for connections are dc_prop for fluid -properties (mass flow, pressure, enthalpy, temperature and vapor mass -fraction) and dc_flu for fluid composition. If you want to specify -data_containers, you need to import them from the :py:mod:`tespy.tools` module. - -In order to create the connections we create the components to connect first. - -.. code-block:: python - - from tespy.tools import FluidProperties as dc_prop - from tespy.connections import Connection, Ref - from tespy.components import Sink, Source - - # create components - source1 = Source('source 1') - source2 = Source('source 2') - sink1 = Sink('sink 1') - sink2 = Sink('sink 2') - - # create connections - myconn = Connection(source1, 'out1', sink1, 'in1') - myotherconn = Connection(source2, 'out1', sink2, 'in1') - - # set pressure and vapor mass fraction by value, temperature and enthalpy - # analogously - myconn.set_attr(p=7, x=0.5) - - # set starting values for mass flow, pressure and enthalpy (has no effect - # on temperature and vapor mass fraction!) - myconn.set_attr(m0=10, p0=15, h0=100) - - # do the same with a data container - myconn.set_attr(p=dc_prop(val=7, val_set=True), - x=dc_prop(val=0.5, val_set=True)) - myconn.set_attr(m=dc_prop(val0=10), p=dc_prop(val0=15), - h=dc_prop(val0=100)) - - # specify a referenced value: pressure of myconn is 1.2 times pressure at - # myotherconn minus 5 (unit is the network's corresponding unit) - myconn.set_attr(p=Ref(myotherconn, 1.2, -5)) - - # specify value and reference at the same time - myconn.set_attr(p=dc_prop(val=7, val_set=True, - ref=Ref(myotherconn, 1.2, -5), ref_set=True)) - - # possibilities to unset values - myconn.set_attr(p=np.nan) - myconn.set_attr(p=None) - myconn.p.set_attr(val_set=False, ref_set=False) - -If you want to specify the fluid vector you can do it in the following way. - -.. note:: - - If you specify a fluid, use the fluid's name and do not include the fluid - property back end. - -.. code-block:: python - - from tespy.tools import FluidComposition as dc_flu - - # set both elements of the fluid vector - myconn.set_attr(fluid={'water': 1, 'air': 0}) - # same thing, but using data container - myconn.set_attr(fluid=dc_flu(val={'water': 1, 'air': 0}, - val_set={'water': True, 'air': True})) - - # set starting values - myconn.set_attr(fluid0={'water': 1, 'air': 0}) - # same thing, but using data container - myconn.set_attr(fluid=dc_flu(val0={'water': 1, 'air': 0})) - - # unset full fluid vector - myconn.set_attr(fluid={}) - # unset part of fluid vector - myconn.fluid.set_attr(val_set={'water': False}) - -.. note:: - - References can not be used for fluid composition at the moment! - -You may want to access the network's connections other than using the variable -names, for example in an imported network or connections from a subsystem. It -is possible to access these using the connection's label. By default, the label -is generated by this logic: - -:code:`source:source_id_target:target_id`, where - -- :code:`source` and :code:`target` are the labels of the components that are - connected. -- :code:`source_id` and :code:`target_id` are e.g. :code:`out1` and - :code:`in2` respectively. - -.. code-block:: python - - myconn = Connection(source1, 'out1', sink1, 'in1', label='myconnlabel') - mynetwork.add_conns(myconn) - mynetwork.get_conn('myconnlabel').set_attr(p=1e5) - -.. note:: - - The label can only be specified on creation of the connection. Changing the - label after might break this access method. - -.. _tespy_busses_label: - -Busses ------- - -Busses are energy flow connectors. You can sum the energy flow of different -components and create relations between components regarding mass independent -energy transport. - -Different use-cases for busses could be: - -- post-processing -- introduce motor or generator efficiencies -- create relations of different components - -The handling of busses is very similar to connections and components. You need -to add components to your busses as a dictionary containing at least the -instance of your component. Additionally you may provide a characteristic line, -linking the ratio of actual value to a referenced value (design case value) to -an efficiency factor the component value of the bus is multiplied with. For -instance, you can provide a characteristic line of an electrical generator or -motor for a variable conversion efficiency. The referenced value is retrieved -by the design point of your system. Offdesign calculations use the referenced -value from your system's design point for the characteristic line. In design -case, the ratio will always be 1. - -After a simulation, it is possible to output the efficiency of a component on -a bus and to output the bus value of the component using - -- :code:`mycomponent.calc_bus_efficiency(mybus)` -- :code:`mycomponent.calc_bus_value(mybus)` - -These data are also available in the network's results dictionary and contain - -- the bus value, -- the component value, -- the efficiency value and -- the design value of the bus. - -.. code-block:: python - - bus_results = mynetwork.results['power output'] - -.. note:: - - The available keywords for the dictionary are: - - - 'comp' for the component instance. - - 'param' for the parameter (e.g. the combustion engine has various - parameters, have a look at the - :ref:`combustion engine example `) - - 'char' for the characteristic line - - 'base' the base for efficiency definition - - 'P_ref' for the reference value of the component - - There are different specification possibilities: - - - If you specify the component only, the parameter will be default and the - efficiency factor of the characteristic line will be 1 independent of - the load. - - If you specify a numeric value for char, the efficiency factor will be - equal to that value independent of the load. - - If you want to specify a characteristic line, provide - a :py:class:`CharLine ` - object. - - Specify :code:`'base': 'bus'` if you want to change from the default base - to the bus as base. This means, that the definition of the efficiency - factor will change according to your specification. - - .. math :: - - \eta = \begin{cases} - \frac{\dot{E}_\mathrm{component}}{\dot{E}_\mathrm{bus}} & - \text{'base': 'bus'}\\ - \frac{\dot{E}_\mathrm{bus}}{\dot{E}_\mathrm{component}} & - \text{'base': 'component'} - \end{cases} - - This applies to the calculation of the bus value analogously. - - .. math:: - - \dot{E}_\mathrm{bus} = \begin{cases} - \frac{\dot{E}_\mathrm{component}}{f\left( - \frac{\dot{E}_\mathrm{bus}}{\dot{E}_\mathrm{bus,design}}\right)} & - \text{'base': 'bus'}\\ - \dot{E}_\mathrm{component} \cdot f\left( - \frac{\dot{E}_\mathrm{component}} - {\dot{E}_\mathrm{component,design}}\right) & - \text{'base': 'component'} - \end{cases} - -The examples below show the implementation of busses in your TESPy simulation. - -Create a pump that is powered by a turbine. The turbine's :code:`turbine_fwp` -power output must therefore be equal to the pump's :code:`fwp` power -consumption. - -.. code-block:: python - - from tespy.networks import Network - from tespy.components import Pump, Turbine, CombustionEngine - from tespy.connections import Bus - - # the total power on this bus must be zero - # this way we can make sure the power of the turbine has the same value as - # the pump's power but with negative sign - fwp_bus = Bus('feed water pump bus', P=0) - fwp_bus.add_comps({'comp': turbine_fwp}, {'comp': fwp}) - my_network.add_busses(fwp_bus) - -Create two turbines :code:`turbine1` and :code:`turbine2` which have the same -power output. - -.. code:: python - - # the total power on this bus must be zero, too - # we make sure the two turbines yield the same power output by adding the char - # parameter for the second turbine and using -1 as char - turbine_bus = Bus('turbines', P=0) - turbine_bus.add_comps({'comp': turbine_1}, {'comp': turbine_2, 'char': -1}) - my_network.add_busses(turbine_bus) - -Create a bus for post-processing purpose only. Include a characteristic line -for a generator and add two turbines :code:`turbine_hp` and :code:`turbine_lp` -to the bus. - -.. code:: python - - # bus for postprocessing, no power (or heat flow) specified but with variable - # conversion efficiency - power_bus = Bus('power output') - x = np.array([0.2, 0.4, 0.6, 0.8, 1.0, 1.1]) - y = np.array([0.85, 0.93, 0.95, 0.96, 0.97, 0.96]) - # create a characteristic line for a generator - gen = CharLine(x=x, y=y) - power.add_comps( - {'comp': turbine_hp, 'char': gen1}, - {'comp': turbine_lp, 'char': gen2}) - my_network.add_busses(power_bus) - -Create a bus for the electrical power output of a combustion engine -:code:`comb_engine`. Use a generator for power conversion and specify the total -power output. - -.. code:: python - - # bus for combustion engine power - el_power_bus = Bus('combustion engine power', P=-10e6) - el_power_bus.add_comps({'comp': comb_engine, 'param': 'P', 'char': gen}) - -Create a bus for the electrical power input of a pump :code:`pu` with -:code:`'bus'` and with :code:`'component'` as base. In both cases, the value of -the component power will be identical. Due to the different efficiency -definitions the value of the bus power will differ in part load. - -.. code:: python - - import numpy as np - from tespy.components import Pump, Sink, Source - from tespy.connections import Bus, Connection - from tespy.networks import Network - from tespy.tools.characteristics import CharLine - - nw = Network(fluids=['H2O'], p_unit='bar', T_unit='C') - - si = Sink('sink') - so = Source('source') - pu = Pump('pump') - - so_pu = Connection(so, 'out1', pu, 'in1') - pu_si = Connection(pu, 'out1', si, 'in1') - - nw.add_conns(so_pu, pu_si) - - # bus for combustion engine power - x = np.array([0.2, 0.4, 0.6, 0.8, 1.0, 1.1]) - y = np.array([0.85, 0.93, 0.95, 0.96, 0.97, 0.96]) - # create a characteristic line for a generator - mot_bus_based = CharLine(x=x, y=y) - mot_comp_based = CharLine(x=x, y=1 / y) - bus1 = Bus('pump power bus based') - bus1.add_comps({'comp': pu, 'char': mot_bus_based, 'base': 'bus'}) - # the keyword 'base': 'component' is the default value, therefore it does - # not need to be passed - bus2 = Bus('pump power component based') - bus2.add_comps({'comp': pu, 'char': mot_comp_based}) - - nw.add_busses(bus1, bus2) - - so_pu.set_attr(fluid={'H2O': 1}, m=10, p=5, T=20) - pu_si.set_attr(p=10) - - pu.set_attr(eta_s=0.75) - - nw.solve('design') - nw.save('tmp') - print('Bus based efficiency:', pu.calc_bus_efficiency(bus1)) - print('Component based efficiency:', 1 / pu.calc_bus_efficiency(bus2)) - print('Bus based bus power:', pu.calc_bus_value(bus1)) - print('Component based bus power:', pu.calc_bus_value(bus2)) - - so_pu.set_attr(m=9) - nw.solve('offdesign', design_path='tmp') - print('Bus based efficiency:', pu.calc_bus_efficiency(bus1)) - print('Component based efficiency:', 1 / pu.calc_bus_efficiency(bus2)) - print('Bus based bus power:', pu.calc_bus_value(bus1)) - print('Component based bus power:', pu.calc_bus_value(bus2)) - - # get DataFrame with the bus results - bus_results = nw.results['pump power bus based'] - -.. note:: - - The x-values of the characteristic line represent the relative load of the - component: actual value of the bus divided by the reference/design point - value. In design-calculations the x-value used in the function evaluation - will always be at 1. - -As mentioned in the component section: It is also possible to import your -custom characteristics from the :code:`HOME/.tespy/data` folder. Read more -about this :ref:`here `. +.. _tespy_modules_connections_label: + +Connections +=========== + +This section provides an overview of the parametrisation of connections, the +usage of references and busses (connections for energy flow). + +Parametrisation +--------------- + +As mentioned in the introduction, for each connection you can specify the +following parameters: + + * mass flow* (m), + * volumetric flow (v), + * pressure* (p), + * enthalpy* (h), + * temperature* (T), + * vapor mass fraction for pure fluids (x), + * a fluid vector (fluid) and + * a balance closer for the fluid vector (fluid_balance). + +It is possible to specify values, starting values, references and data +containers. The data containers for connections are dc_prop for fluid +properties (mass flow, pressure, enthalpy, temperature and vapor mass +fraction) and dc_flu for fluid composition. If you want to specify +data_containers, you need to import them from the :py:mod:`tespy.tools` module. + +In order to create the connections we create the components to connect first. + +.. code-block:: python + + from tespy.tools import FluidProperties as dc_prop + from tespy.connections import Connection, Ref + from tespy.components import Sink, Source + + # create components + source1 = Source('source 1') + source2 = Source('source 2') + sink1 = Sink('sink 1') + sink2 = Sink('sink 2') + + # create connections + myconn = Connection(source1, 'out1', sink1, 'in1') + myotherconn = Connection(source2, 'out1', sink2, 'in1') + + # set pressure and vapor mass fraction by value, temperature and enthalpy + # analogously + myconn.set_attr(p=7, x=0.5) + + # set starting values for mass flow, pressure and enthalpy (has no effect + # on temperature and vapor mass fraction!) + myconn.set_attr(m0=10, p0=15, h0=100) + + # do the same with a data container + myconn.set_attr(p=dc_prop(val=7, val_set=True), + x=dc_prop(val=0.5, val_set=True)) + myconn.set_attr(m=dc_prop(val0=10), p=dc_prop(val0=15), + h=dc_prop(val0=100)) + + # specify a referenced value: pressure of myconn is 1.2 times pressure at + # myotherconn minus 5 (unit is the network's corresponding unit) + myconn.set_attr(p=Ref(myotherconn, 1.2, -5)) + + # specify value and reference at the same time + myconn.set_attr(p=dc_prop(val=7, val_set=True, + ref=Ref(myotherconn, 1.2, -5), ref_set=True)) + + # possibilities to unset values + myconn.set_attr(p=np.nan) + myconn.set_attr(p=None) + myconn.p.set_attr(val_set=False, ref_set=False) + +If you want to specify the fluid vector you can do it in the following way. + +.. note:: + + If you specify a fluid, use the fluid's name and do not include the fluid + property back end. + +.. code-block:: python + + from tespy.tools import FluidComposition as dc_flu + + # set both elements of the fluid vector + myconn.set_attr(fluid={'water': 1, 'air': 0}) + # same thing, but using data container + myconn.set_attr(fluid=dc_flu(val={'water': 1, 'air': 0}, + val_set={'water': True, 'air': True})) + + # set starting values + myconn.set_attr(fluid0={'water': 1, 'air': 0}) + # same thing, but using data container + myconn.set_attr(fluid=dc_flu(val0={'water': 1, 'air': 0})) + + # unset full fluid vector + myconn.set_attr(fluid={}) + # unset part of fluid vector + myconn.fluid.set_attr(val_set={'water': False}) + +.. note:: + + References can not be used for fluid composition at the moment! + +You may want to access the network's connections other than using the variable +names, for example in an imported network or connections from a subsystem. It +is possible to access these using the connection's label. By default, the label +is generated by this logic: + +:code:`source:source_id_target:target_id`, where + +- :code:`source` and :code:`target` are the labels of the components that are + connected. +- :code:`source_id` and :code:`target_id` are e.g. :code:`out1` and + :code:`in2` respectively. + +.. code-block:: python + + myconn = Connection(source1, 'out1', sink1, 'in1', label='myconnlabel') + mynetwork.add_conns(myconn) + mynetwork.get_conn('myconnlabel').set_attr(p=1e5) + +.. note:: + + The label can only be specified on creation of the connection. Changing the + label after might break this access method. + +.. _tespy_busses_label: + +Busses +------ + +Busses are energy flow connectors. You can sum the energy flow of different +components and create relations between components regarding mass independent +energy transport. + +Different use-cases for busses could be: + +- post-processing +- introduce motor or generator efficiencies +- create relations of different components + +The handling of busses is very similar to connections and components. You need +to add components to your busses as a dictionary containing at least the +instance of your component. Additionally you may provide a characteristic line, +linking the ratio of actual value to a referenced value (design case value) to +an efficiency factor the component value of the bus is multiplied with. For +instance, you can provide a characteristic line of an electrical generator or +motor for a variable conversion efficiency. The referenced value is retrieved +by the design point of your system. Offdesign calculations use the referenced +value from your system's design point for the characteristic line. In design +case, the ratio will always be 1. + +After a simulation, it is possible to output the efficiency of a component on +a bus and to output the bus value of the component using + +- :code:`mycomponent.calc_bus_efficiency(mybus)` +- :code:`mycomponent.calc_bus_value(mybus)` + +These data are also available in the network's results dictionary and contain + +- the bus value, +- the component value, +- the efficiency value and +- the design value of the bus. + +.. code-block:: python + + bus_results = mynetwork.results['power output'] + +.. note:: + + The available keywords for the dictionary are: + + - 'comp' for the component instance. + - 'param' for the parameter (e.g. the combustion engine has various + parameters, have a look at the + :ref:`combustion engine example `) + - 'char' for the characteristic line + - 'base' the base for efficiency definition + - 'P_ref' for the reference value of the component + + There are different specification possibilities: + + - If you specify the component only, the parameter will be default and the + efficiency factor of the characteristic line will be 1 independent of + the load. + - If you specify a numeric value for char, the efficiency factor will be + equal to that value independent of the load. + - If you want to specify a characteristic line, provide + a :py:class:`CharLine ` + object. + - Specify :code:`'base': 'bus'` if you want to change from the default base + to the bus as base. This means, that the definition of the efficiency + factor will change according to your specification. + + .. math :: + + \eta = \begin{cases} + \frac{\dot{E}_\mathrm{component}}{\dot{E}_\mathrm{bus}} & + \text{'base': 'bus'}\\ + \frac{\dot{E}_\mathrm{bus}}{\dot{E}_\mathrm{component}} & + \text{'base': 'component'} + \end{cases} + + This applies to the calculation of the bus value analogously. + + .. math:: + + \dot{E}_\mathrm{bus} = \begin{cases} + \frac{\dot{E}_\mathrm{component}}{f\left( + \frac{\dot{E}_\mathrm{bus}}{\dot{E}_\mathrm{bus,design}}\right)} & + \text{'base': 'bus'}\\ + \dot{E}_\mathrm{component} \cdot f\left( + \frac{\dot{E}_\mathrm{component}} + {\dot{E}_\mathrm{component,design}}\right) & + \text{'base': 'component'} + \end{cases} + +The examples below show the implementation of busses in your TESPy simulation. + +Create a pump that is powered by a turbine. The turbine's :code:`turbine_fwp` +power output must therefore be equal to the pump's :code:`fwp` power +consumption. + +.. code-block:: python + + from tespy.networks import Network + from tespy.components import Pump, Turbine, CombustionEngine + from tespy.connections import Bus + + # the total power on this bus must be zero + # this way we can make sure the power of the turbine has the same value as + # the pump's power but with negative sign + fwp_bus = Bus('feed water pump bus', P=0) + fwp_bus.add_comps({'comp': turbine_fwp}, {'comp': fwp}) + my_network.add_busses(fwp_bus) + +Create two turbines :code:`turbine1` and :code:`turbine2` which have the same +power output. + +.. code:: python + + # the total power on this bus must be zero, too + # we make sure the two turbines yield the same power output by adding the char + # parameter for the second turbine and using -1 as char + turbine_bus = Bus('turbines', P=0) + turbine_bus.add_comps({'comp': turbine_1}, {'comp': turbine_2, 'char': -1}) + my_network.add_busses(turbine_bus) + +Create a bus for post-processing purpose only. Include a characteristic line +for a generator and add two turbines :code:`turbine_hp` and :code:`turbine_lp` +to the bus. + +.. code:: python + + # bus for postprocessing, no power (or heat flow) specified but with variable + # conversion efficiency + power_bus = Bus('power output') + x = np.array([0.2, 0.4, 0.6, 0.8, 1.0, 1.1]) + y = np.array([0.85, 0.93, 0.95, 0.96, 0.97, 0.96]) + # create a characteristic line for a generator + gen = CharLine(x=x, y=y) + power.add_comps( + {'comp': turbine_hp, 'char': gen1}, + {'comp': turbine_lp, 'char': gen2}) + my_network.add_busses(power_bus) + +Create a bus for the electrical power output of a combustion engine +:code:`comb_engine`. Use a generator for power conversion and specify the total +power output. + +.. code:: python + + # bus for combustion engine power + el_power_bus = Bus('combustion engine power', P=-10e6) + el_power_bus.add_comps({'comp': comb_engine, 'param': 'P', 'char': gen}) + +Create a bus for the electrical power input of a pump :code:`pu` with +:code:`'bus'` and with :code:`'component'` as base. In both cases, the value of +the component power will be identical. Due to the different efficiency +definitions the value of the bus power will differ in part load. + +.. code:: python + + import numpy as np + from tespy.components import Pump, Sink, Source + from tespy.connections import Bus, Connection + from tespy.networks import Network + from tespy.tools.characteristics import CharLine + + nw = Network(fluids=['H2O'], p_unit='bar', T_unit='C') + + si = Sink('sink') + so = Source('source') + pu = Pump('pump') + + so_pu = Connection(so, 'out1', pu, 'in1') + pu_si = Connection(pu, 'out1', si, 'in1') + + nw.add_conns(so_pu, pu_si) + + # bus for combustion engine power + x = np.array([0.2, 0.4, 0.6, 0.8, 1.0, 1.1]) + y = np.array([0.85, 0.93, 0.95, 0.96, 0.97, 0.96]) + # create a characteristic line for a generator + mot_bus_based = CharLine(x=x, y=y) + mot_comp_based = CharLine(x=x, y=1 / y) + bus1 = Bus('pump power bus based') + bus1.add_comps({'comp': pu, 'char': mot_bus_based, 'base': 'bus'}) + # the keyword 'base': 'component' is the default value, therefore it does + # not need to be passed + bus2 = Bus('pump power component based') + bus2.add_comps({'comp': pu, 'char': mot_comp_based}) + + nw.add_busses(bus1, bus2) + + so_pu.set_attr(fluid={'H2O': 1}, m=10, p=5, T=20) + pu_si.set_attr(p=10) + + pu.set_attr(eta_s=0.75) + + nw.solve('design') + nw.save('tmp') + print('Bus based efficiency:', pu.calc_bus_efficiency(bus1)) + print('Component based efficiency:', 1 / pu.calc_bus_efficiency(bus2)) + print('Bus based bus power:', pu.calc_bus_value(bus1)) + print('Component based bus power:', pu.calc_bus_value(bus2)) + + so_pu.set_attr(m=9) + nw.solve('offdesign', design_path='tmp') + print('Bus based efficiency:', pu.calc_bus_efficiency(bus1)) + print('Component based efficiency:', 1 / pu.calc_bus_efficiency(bus2)) + print('Bus based bus power:', pu.calc_bus_value(bus1)) + print('Component based bus power:', pu.calc_bus_value(bus2)) + + # get DataFrame with the bus results + bus_results = nw.results['pump power bus based'] + +.. note:: + + The x-values of the characteristic line represent the relative load of the + component: actual value of the bus divided by the reference/design point + value. In design-calculations the x-value used in the function evaluation + will always be at 1. + +As mentioned in the component section: It is also possible to import your +custom characteristics from the :code:`HOME/.tespy/data` folder. Read more +about this :ref:`here `. diff --git a/docs/tespy_modules/fluid_properties.rst b/docs/tespy_modules/fluid_properties.rst index e50198c78..038e12179 100644 --- a/docs/tespy_modules/fluid_properties.rst +++ b/docs/tespy_modules/fluid_properties.rst @@ -1,3 +1,5 @@ +.. _tespy_fluid_properties_label: + Fluid properties ================ The basic fluid properties are handled by @@ -32,14 +34,14 @@ If you use pure fluids, TESPy directly uses CoolProp functions to gather all fluid properties. CoolProp covers the most important fluids such as water, air as a pseudo-pure fluid as well as its components, several fuels and refrigerants etc.. Look for the aliases in the list of -`fluids `_. +`fluids `__. All fluids provided in this list cover liquid and gaseous state and the two-phase region. Incompressible fluids --------------------- If you are looking for heat transfer fluids, the list of incompressible -`fluids `_ +`fluids `__ might be interesting for you. In contrast to the pure fluids, the properties cover liquid state only. diff --git a/docs/tespy_modules/networks.rst b/docs/tespy_modules/networks.rst index 4fbf2173b..79d1dbca5 100644 --- a/docs/tespy_modules/networks.rst +++ b/docs/tespy_modules/networks.rst @@ -1,4 +1,4 @@ -.. _using_tespy_networks_label: +.. _tespy_modules_networks_label: Networks ======== @@ -396,7 +396,7 @@ power :math:`P` to be 1000 W, the set of equations will look like this: &0 = \dot{m}_{in} - \dot{m}_{out}\\ \mathrm{additional:} \, &0 = 1000 - \dot{m}_{in} (\cdot {h_{out} - h_{in}}) -.. _using_tespy_convergence_check_label: +.. _tespy_modules_convergence_check_label: Convergence stability +++++++++++++++++++++ diff --git a/docs/tespy_modules/other.rst b/docs/tespy_modules/other.rst index 111294cff..459bee364 100644 --- a/docs/tespy_modules/other.rst +++ b/docs/tespy_modules/other.rst @@ -1,299 +1,288 @@ -User defined equations -====================== -User defined functions provide a powerful tool to the user as they enable -the definition of generic and individual equations that can be applied to your -TESPy model. In order to implement this functionality in your model you will -use the :py:class:`tespy.tools.helpers.UserDefinedEquation`. The API -documentation provides you with an interesting example application, too. - -Getting started ---------------- - -For an easy start, let's consider two different streams. The mass flow of both -streams should be coupled within the model. There is already a possibility -covering simple relations, i.e. applying value referencing with the -:py:class:`tespy.connections.connection.Ref` class. This class allows to -formulate simple linear relations: - -.. math:: - - 0 = \dot{m}_1 - \left(\dot{m}_2 \cdot a + b\right) - -Instead of this simple application, other relations could be useful. For -example, the mass flow of our first stream should be quadratic to the mass -flow of the second stream. - -.. math:: - - 0 = \dot{m}_1 - \dot{m}_2^2 - -In order to apply this relation, we need to import the -:py:class:`tespy.tools.helpers.UserDefinedEquation` class into our model an -create an instance with the respective data. First, we set up the TESPy model. - -.. code-block:: python - - from tespy.networks import Network - from tespy.components import Sink, Source - from tespy.connections import Connection - from tespy.tools.helpers import UserDefinedEquation - - fluids = ['water'] - - nw = Network(fluids=fluids) - nw.set_attr(p_unit='bar', T_unit='C', h_unit='kJ / kg') - - so1 = Source('source 1') - so2 = Source('source 2') - si1 = Sink('sink 1') - si2 = Sink('sink 2') - - c1 = Connection(so1, 'out1', si1, 'in1') - c2 = Connection(so2, 'out1', si2, 'in1') - - nw.add_conns(c1, c2) - - c1.set_attr(fluid={'water': 1}, p=1, T=50) - c2.set_attr(fluid={'water': 1}, p=5, T=250, v=4) - -In the model both streams are well defined regarding pressure, enthalpy and -fluid composition. The second stream's mass flow is defined through -specification of the volumetric flow, we are missing the mass flow of the -connection :code:`c1`. As described, its value should be quadratic to the -(still unknown) mass flow of :code:`c2`. First, we now need to define the -equation in a function which returns the residual value of the equation. - -.. code-block:: python - - def my_ude(self): - return self.conns[0].m.val_SI - self.conns[1].m.val_SI ** 2 - - -.. note:: - - The function must only take one parameter, i.e. the UserDefinedEquation - class instance. The **name of the parameter is arbitrary**. We will use - :code:`self` in this example. It serves to access some important parameters - of the equation: - - - connections required in the equation - - Jacobian matrix to place the partial derivatives - - automatic numerical derivatives - - other (external) parameters (e.g. the CharLine in the API docs example of - :py:class:`tespy.tools.helpers.UserDefinedEquation`) - -.. note:: - - It is only possible to use the SI-values of the connection variables as - these values are updated in every iteration. The values in the network's - specified unit system are only updated after a simulation. - -The second step is to define the derivatives with respect to all primary -variables of the network, i.e. mass flow, pressure, enthalpy and fluid -composition of every connection. The derivatives have to be passed to the -Jacobian. In order to do this, we create a function that updates the values -inside the Jacobian of the :code:`UserDefinedEquation` and returns it: - -- :code:`self.jacobian` is a dictionary containing numpy arrays for every - connection required by the :code:`UserDefinedEquation`. -- derivatives to **mass flow** are placed in the first element of the numpy - array (**index 0**) -- derivatives to **pressure** are placed in the second element of the numpy - array (**index 1**) -- derivatives to **enthalpy** are placed in the third element of the numpy - array (**index 2**) -- derivatives to **fluid composition** are placed in the remaining elements - beginning at the fourth element of the numpy array (**indices 3:**) - -If we calculate the derivatives of our equation, it is easy to find, that only -derivatives to mass flow are not zero. - -- The derivative to mass flow of connection :code:`c1` is equal to :math:`1` -- The derivative to mass flow of connection :code:`c2` is equal to - :math:`2 \cdot \dot{m}_2`. - -.. code-block:: python - - def my_ude_deriv(self): - self.jacobian[self.conns[0]][0] = 1 - self.jacobian[self.conns[1]][0] = 2 * self.conns[1].m.val_SI - return self.jacobian - -Now we can create our instance of the :code:`UserDefinedEquation` and add it to -the network. The class requires four mandatory arguments to be passed: - -- :code:`label` of type String. -- :code:`func` which is the function holding the equation to be applied. -- :code:`deriv` which is the function holding the calculation of the Jacobian. -- :code:`conns` which is a list of the connections required by the equation. - The order of the connections specified in the list is equal to the accessing - order in the equation and derivative calculation. -- :code:`params` (optional keyword argument) which is a dictionary holding - additional data required in the equation or derivative calculation. - -.. code-block:: python - - ude = UserDefinedEquation('my ude', my_ude, my_ude_deriv, [c1, c2]) - nw.add_ude(ude) - nw.solve('design') - nw.print_results() - -More examples -------------- - -After warm-up let's create some more complex examples, e.g. the -square root of the temperature of the second stream should be equal to the -the logarithmic value of the pressure squared divided by the mass flow of the -first stream. - -.. math:: - - 0 = \sqrt{T_2} - \ln\left(\frac{p_1^2}{\dot{m}_1}\right) - -In order to access the temperature within the iteration process, we need to -calculate it with the respective method. We can import it from the -:py:mod:`tespy.tools.fluid_properties` module. Additionally, import numpy for -the logarithmic value. - -.. code-block:: python - - from tespy.tools.fluid_properties import T_mix_ph - import numpy as np - - def my_ude(self): - return ( - T_mix_ph(self.conns[1].get_flow()) ** 0.5 - - np.log(abs(self.conns[0].p.val_SI ** 2 / self.conns[0].m.val_SI))) - -.. note:: - - We use the absolute value inside of the logarithm expression to avoid - ValueErrors within the solution process as the mass flow is not restricted - to positive values. - -The derivatives can be determined analytically for the pressure and mass flow -of the first stream easily. For the temperature value, you can use the -predefined fluid property functions :code:`dT_mix_dph` and :code:`dT_mix_pdh` -respectively to calculate the partial derivatives. - -.. code-block:: python - - from tespy.tools.fluid_properties import dT_mix_dph - from tespy.tools.fluid_properties import dT_mix_pdh - - def my_ude_deriv(self): - self.jacobian[self.conns[0]][0] = 1 / self.conns[0].m.val_SI - self.jacobian[self.conns[0]][1] = - 2 / self.conns[0].p.val_SI - T = T_mix_ph(self.conns[1].get_flow()) - self.jacobian[self.conns[1]][1] = ( - dT_mix_dph(self.conns[1].get_flow()) * 0.5 / (T ** 0.5)) - self.jacobian[self.conns[1]][2] = ( - dT_mix_pdh(self.conns[1].get_flow()) * 0.5 / (T ** 0.5)) - return self.jacobian - -But, what if the analytical derivative is not available? You can make use of -generic numerical derivatives using the inbuilt method :code:`numeric_deriv`. -The methods expects the variable :code:`'m'`, :code:`'p'`, :code:`'h'` or -:code:`'fluid'` (fluid composition) to derive the function to as well as the -respective connection index from the list of connections. The "lazy" solution -for the above derivatives would therefore look like this: - -.. code-block:: python - - def my_ude_deriv(self): - self.jacobian[self.conns[0]][0] = self.numeric_deriv('m', 0) - self.jacobian[self.conns[0]][1] = self.numeric_deriv('p', 0) - self.jacobian[self.conns[1]][1] = self.numeric_deriv('p', 1) - self.jacobian[self.conns[1]][2] = self.numeric_deriv('h', 1) - return self.jacobian - -Obviously, the downside is a slower performance of the solver, as for every -:code:`numeric_deriv` call the function will be evaluated fully twice -(central finite difference). - -Last, we want to consider an example using additional parameters in the -UserDefinedEquation, where :math:`a` might be a factor between 0 and 1 and -:math:`b` is the steam mass fraction (also, between 0 and 1). The difference of -the enthalpy between the two streams multiplied with factor a should be equal -to the difference of the enthalpy of stream two and the enthalpy of saturated -gas at the pressure of stream 1. The definition of the UserDefinedEquation -instance must therefore be changed as below. - -.. math:: - - 0 = a \cdot \left(h_2 - h_1 \right) - - \left(h_2 - h\left(p_1, x=b \right)\right) - -.. code-block:: python - - from tespy.tools.fluid_properties import h_mix_pQ - from tespy.tools.fluid_properties import dh_mix_dpQ - - def my_ude(self): - a = self.params['a'] - b = self.params['b'] - return ( - a * (self.conns[1].h.val_SI - self.conns[0].h.val_SI) - - (self.conns[1].h.val_SI - h_mix_pQ(self.conns[0].get_flow(), b))) - - def my_ude_deriv(self): - a = self.params['a'] - b = self.params['b'] - self.jacobian[self.conns[0]][1] = dh_mix_dpQ( - self.conns[0].get_flow(), b) - self.jacobian[self.conns[0]][2] = -a - self.jacobian[self.conns[1]][2] = a - 1 - return self.jacobian - - ude = UserDefinedEquation( - 'my ude', my_ude, my_ude_deriv, [c1, c2], params={'a': 0.5, 'b': 1}) - - -One more example (using a CharLine for datapoint interpolation) can be found in -the API documentation of class -:py:class:`tespy.tools.helpers.UserDefinedEquation`. - -Document your equations ------------------------ - -For the automatic documentation of your models just pass the :code:`latex` -keyword on creation of the UserDefinedEquation instance. It should contain the -latex equation string. For example, the last equation from above: - -.. code-block:: python - - latex = ( - r'0 = a \cdot \left(h_2 - h_1 \right) - ' - r'\left(h_2 - h\left(p_1, x=b \right)\right)') - - ude = UserDefinedEquation( - 'my ude', my_ude, my_ude_deriv, [c1, c2], params={'a': 0.5, 'b': 1}, - latex={'equation': latex}) - -The documentation will also create figures of :code:`CharLine` and -:code:`CharMap` objects provided. To add these, adjust the code like this. -Provide the :code:`CharLine` and :code:`CharMap` objects within a list. - -.. code-block:: python - - ude = UserDefinedEquation( - 'my ude', my_ude, my_ude_deriv, [c1, c2], params={'a': 0.5, 'b': 1}, - latex={ - 'equation': latex, - 'lines': [charline1, charline2], - 'maps': [map1]}) - -How can TESPy contribute to your energy system calculations? -============================================================ - -In this part you learn how you can use TESPy for your energy system -calculations: In energy system calculations, for instance in oemof-solph, -plants are usually modeled as abstract components on a much lower level of -detail. In order to represent a plant within an abstract component it is -possible to supply characteristics establishing a connection between your -energy system model and a specific plant model. Thus the characteristics are a -representation of a specific plant layout in terms of topology and process -parameters. In the examples section we have an example of a heat pump COP at -different loads and ambient temperatures as well as a CHP unit with -backpressure turbine operating at different loads and varying feed flow -temperatures of a heating system. +.. _tespy_other_label: + +User defined equations +====================== +User defined functions provide a powerful tool to the user as they enable +the definition of generic and individual equations that can be applied to your +TESPy model. In order to implement this functionality in your model you will +use the :py:class:`tespy.tools.helpers.UserDefinedEquation`. The API +documentation provides you with an interesting example application, too. + +Getting started +--------------- + +For an easy start, let's consider two different streams. The mass flow of both +streams should be coupled within the model. There is already a possibility +covering simple relations, i.e. applying value referencing with the +:py:class:`tespy.connections.connection.Ref` class. This class allows to +formulate simple linear relations: + +.. math:: + + 0 = \dot{m}_1 - \left(\dot{m}_2 \cdot a + b\right) + +Instead of this simple application, other relations could be useful. For +example, the mass flow of our first stream should be quadratic to the mass +flow of the second stream. + +.. math:: + + 0 = \dot{m}_1 - \dot{m}_2^2 + +In order to apply this relation, we need to import the +:py:class:`tespy.tools.helpers.UserDefinedEquation` class into our model an +create an instance with the respective data. First, we set up the TESPy model. + +.. code-block:: python + + from tespy.networks import Network + from tespy.components import Sink, Source + from tespy.connections import Connection + from tespy.tools.helpers import UserDefinedEquation + + fluids = ['water'] + + nw = Network(fluids=fluids) + nw.set_attr(p_unit='bar', T_unit='C', h_unit='kJ / kg') + + so1 = Source('source 1') + so2 = Source('source 2') + si1 = Sink('sink 1') + si2 = Sink('sink 2') + + c1 = Connection(so1, 'out1', si1, 'in1') + c2 = Connection(so2, 'out1', si2, 'in1') + + nw.add_conns(c1, c2) + + c1.set_attr(fluid={'water': 1}, p=1, T=50) + c2.set_attr(fluid={'water': 1}, p=5, T=250, v=4) + +In the model both streams are well defined regarding pressure, enthalpy and +fluid composition. The second stream's mass flow is defined through +specification of the volumetric flow, we are missing the mass flow of the +connection :code:`c1`. As described, its value should be quadratic to the +(still unknown) mass flow of :code:`c2`. First, we now need to define the +equation in a function which returns the residual value of the equation. + +.. code-block:: python + + def my_ude(self): + return self.conns[0].m.val_SI - self.conns[1].m.val_SI ** 2 + + +.. note:: + + The function must only take one parameter, i.e. the UserDefinedEquation + class instance. The **name of the parameter is arbitrary**. We will use + :code:`self` in this example. It serves to access some important parameters + of the equation: + + - connections required in the equation + - Jacobian matrix to place the partial derivatives + - automatic numerical derivatives + - other (external) parameters (e.g. the CharLine in the API docs example of + :py:class:`tespy.tools.helpers.UserDefinedEquation`) + +.. note:: + + It is only possible to use the SI-values of the connection variables as + these values are updated in every iteration. The values in the network's + specified unit system are only updated after a simulation. + +The second step is to define the derivatives with respect to all primary +variables of the network, i.e. mass flow, pressure, enthalpy and fluid +composition of every connection. The derivatives have to be passed to the +Jacobian. In order to do this, we create a function that updates the values +inside the Jacobian of the :code:`UserDefinedEquation` and returns it: + +- :code:`self.jacobian` is a dictionary containing numpy arrays for every + connection required by the :code:`UserDefinedEquation`. +- derivatives to **mass flow** are placed in the first element of the numpy + array (**index 0**) +- derivatives to **pressure** are placed in the second element of the numpy + array (**index 1**) +- derivatives to **enthalpy** are placed in the third element of the numpy + array (**index 2**) +- derivatives to **fluid composition** are placed in the remaining elements + beginning at the fourth element of the numpy array (**indices 3:**) + +If we calculate the derivatives of our equation, it is easy to find, that only +derivatives to mass flow are not zero. + +- The derivative to mass flow of connection :code:`c1` is equal to :math:`1` +- The derivative to mass flow of connection :code:`c2` is equal to + :math:`2 \cdot \dot{m}_2`. + +.. code-block:: python + + def my_ude_deriv(self): + self.jacobian[self.conns[0]][0] = 1 + self.jacobian[self.conns[1]][0] = 2 * self.conns[1].m.val_SI + return self.jacobian + +Now we can create our instance of the :code:`UserDefinedEquation` and add it to +the network. The class requires four mandatory arguments to be passed: + +- :code:`label` of type String. +- :code:`func` which is the function holding the equation to be applied. +- :code:`deriv` which is the function holding the calculation of the Jacobian. +- :code:`conns` which is a list of the connections required by the equation. + The order of the connections specified in the list is equal to the accessing + order in the equation and derivative calculation. +- :code:`params` (optional keyword argument) which is a dictionary holding + additional data required in the equation or derivative calculation. + +.. code-block:: python + + ude = UserDefinedEquation('my ude', my_ude, my_ude_deriv, [c1, c2]) + nw.add_ude(ude) + nw.solve('design') + nw.print_results() + +More examples +------------- + +After warm-up let's create some more complex examples, e.g. the +square root of the temperature of the second stream should be equal to the +the logarithmic value of the pressure squared divided by the mass flow of the +first stream. + +.. math:: + + 0 = \sqrt{T_2} - \ln\left(\frac{p_1^2}{\dot{m}_1}\right) + +In order to access the temperature within the iteration process, we need to +calculate it with the respective method. We can import it from the +:py:mod:`tespy.tools.fluid_properties` module. Additionally, import numpy for +the logarithmic value. + +.. code-block:: python + + from tespy.tools.fluid_properties import T_mix_ph + import numpy as np + + def my_ude(self): + return ( + T_mix_ph(self.conns[1].get_flow()) ** 0.5 - + np.log(abs(self.conns[0].p.val_SI ** 2 / self.conns[0].m.val_SI))) + +.. note:: + + We use the absolute value inside of the logarithm expression to avoid + ValueErrors within the solution process as the mass flow is not restricted + to positive values. + +The derivatives can be determined analytically for the pressure and mass flow +of the first stream easily. For the temperature value, you can use the +predefined fluid property functions :code:`dT_mix_dph` and :code:`dT_mix_pdh` +respectively to calculate the partial derivatives. + +.. code-block:: python + + from tespy.tools.fluid_properties import dT_mix_dph + from tespy.tools.fluid_properties import dT_mix_pdh + + def my_ude_deriv(self): + self.jacobian[self.conns[0]][0] = 1 / self.conns[0].m.val_SI + self.jacobian[self.conns[0]][1] = - 2 / self.conns[0].p.val_SI + T = T_mix_ph(self.conns[1].get_flow()) + self.jacobian[self.conns[1]][1] = ( + dT_mix_dph(self.conns[1].get_flow()) * 0.5 / (T ** 0.5)) + self.jacobian[self.conns[1]][2] = ( + dT_mix_pdh(self.conns[1].get_flow()) * 0.5 / (T ** 0.5)) + return self.jacobian + +But, what if the analytical derivative is not available? You can make use of +generic numerical derivatives using the inbuilt method :code:`numeric_deriv`. +The methods expects the variable :code:`'m'`, :code:`'p'`, :code:`'h'` or +:code:`'fluid'` (fluid composition) to derive the function to as well as the +respective connection index from the list of connections. The "lazy" solution +for the above derivatives would therefore look like this: + +.. code-block:: python + + def my_ude_deriv(self): + self.jacobian[self.conns[0]][0] = self.numeric_deriv('m', 0) + self.jacobian[self.conns[0]][1] = self.numeric_deriv('p', 0) + self.jacobian[self.conns[1]][1] = self.numeric_deriv('p', 1) + self.jacobian[self.conns[1]][2] = self.numeric_deriv('h', 1) + return self.jacobian + +Obviously, the downside is a slower performance of the solver, as for every +:code:`numeric_deriv` call the function will be evaluated fully twice +(central finite difference). + +Last, we want to consider an example using additional parameters in the +UserDefinedEquation, where :math:`a` might be a factor between 0 and 1 and +:math:`b` is the steam mass fraction (also, between 0 and 1). The difference of +the enthalpy between the two streams multiplied with factor a should be equal +to the difference of the enthalpy of stream two and the enthalpy of saturated +gas at the pressure of stream 1. The definition of the UserDefinedEquation +instance must therefore be changed as below. + +.. math:: + + 0 = a \cdot \left(h_2 - h_1 \right) - + \left(h_2 - h\left(p_1, x=b \right)\right) + +.. code-block:: python + + from tespy.tools.fluid_properties import h_mix_pQ + from tespy.tools.fluid_properties import dh_mix_dpQ + + def my_ude(self): + a = self.params['a'] + b = self.params['b'] + return ( + a * (self.conns[1].h.val_SI - self.conns[0].h.val_SI) - + (self.conns[1].h.val_SI - h_mix_pQ(self.conns[0].get_flow(), b))) + + def my_ude_deriv(self): + a = self.params['a'] + b = self.params['b'] + self.jacobian[self.conns[0]][1] = dh_mix_dpQ( + self.conns[0].get_flow(), b) + self.jacobian[self.conns[0]][2] = -a + self.jacobian[self.conns[1]][2] = a - 1 + return self.jacobian + + ude = UserDefinedEquation( + 'my ude', my_ude, my_ude_deriv, [c1, c2], params={'a': 0.5, 'b': 1}) + + +One more example (using a CharLine for datapoint interpolation) can be found in +the API documentation of class +:py:class:`tespy.tools.helpers.UserDefinedEquation`. + +Document your equations +----------------------- + +For the automatic documentation of your models just pass the :code:`latex` +keyword on creation of the UserDefinedEquation instance. It should contain the +latex equation string. For example, the last equation from above: + +.. code-block:: python + + latex = ( + r'0 = a \cdot \left(h_2 - h_1 \right) - ' + r'\left(h_2 - h\left(p_1, x=b \right)\right)') + + ude = UserDefinedEquation( + 'my ude', my_ude, my_ude_deriv, [c1, c2], params={'a': 0.5, 'b': 1}, + latex={'equation': latex}) + +The documentation will also create figures of :code:`CharLine` and +:code:`CharMap` objects provided. To add these, adjust the code like this. +Provide the :code:`CharLine` and :code:`CharMap` objects within a list. + +.. code-block:: python + + ude = UserDefinedEquation( + 'my ude', my_ude, my_ude_deriv, [c1, c2], params={'a': 0.5, 'b': 1}, + latex={ + 'equation': latex, + 'lines': [charline1, charline2], + 'maps': [map1] + } + ) diff --git a/docs/tutorials.rst b/docs/tutorials.rst new file mode 100644 index 000000000..b5d3076d1 --- /dev/null +++ b/docs/tutorials.rst @@ -0,0 +1,27 @@ +.. _tespy_tutorial_label: + +~~~~~~~~~~~~~~~~~~ +Advanced Tutorials +~~~~~~~~~~~~~~~~~~ + +We provide tutorials for you to better understand how to work +with TESPy. You will learn how to create basic models and get the idea of +designing a plant and simulating the offdesign behavior in the heat pump +tutorial. Furthermore, the starting values tutorial will help you to get a +stable simulation and faster solutions. On top of that, we created a tutorial +for the usage of the combustion chamber: It is an important component for +thermal power plants while being a source for many errors in the calculation. + +The last tutorial is a plant design optimization tutorial. A thermal power +plant with two extraction stages is optimized in regard of thermal efficiency +with respect to the extraction pressure levels. + +.. toctree:: + :maxdepth: 1 + :glob: + + tutorials/tutorial_heat_pump.rst + tutorials/tutorial_starting_values.rst + tutorials/tutorial_combustion_chamber.rst + tutorials/tutorial_pygmo_optimization.rst + tutorials/tutorial_heat_pump_exergy.rst diff --git a/docs/tutorials_examples/clausius_rankine.rst b/docs/tutorials/clausius_rankine.rst similarity index 100% rename from docs/tutorials_examples/clausius_rankine.rst rename to docs/tutorials/clausius_rankine.rst diff --git a/docs/tutorials_examples/clausius_rankine_chp.rst b/docs/tutorials/clausius_rankine_chp.rst similarity index 100% rename from docs/tutorials_examples/clausius_rankine_chp.rst rename to docs/tutorials/clausius_rankine_chp.rst diff --git a/docs/tutorials_examples/combined_cycle_chp.rst b/docs/tutorials/combined_cycle_chp.rst similarity index 100% rename from docs/tutorials_examples/combined_cycle_chp.rst rename to docs/tutorials/combined_cycle_chp.rst diff --git a/docs/tutorials_examples/combustion_engine.rst b/docs/tutorials/combustion_engine.rst similarity index 100% rename from docs/tutorials_examples/combustion_engine.rst rename to docs/tutorials/combustion_engine.rst diff --git a/docs/tutorials_examples/district_heating.rst b/docs/tutorials/district_heating.rst similarity index 100% rename from docs/tutorials_examples/district_heating.rst rename to docs/tutorials/district_heating.rst diff --git a/docs/tutorials_examples/heat_pump.rst b/docs/tutorials/heat_pump.rst similarity index 100% rename from docs/tutorials_examples/heat_pump.rst rename to docs/tutorials/heat_pump.rst diff --git a/docs/tutorials_examples/solar_collector.rst b/docs/tutorials/solar_collector.rst similarity index 100% rename from docs/tutorials_examples/solar_collector.rst rename to docs/tutorials/solar_collector.rst diff --git a/docs/tutorials_examples/tutorial_combustion_chamber.rst b/docs/tutorials/tutorial_combustion_chamber.rst similarity index 96% rename from docs/tutorials_examples/tutorial_combustion_chamber.rst rename to docs/tutorials/tutorial_combustion_chamber.rst index 42638de22..4ae02f717 100644 --- a/docs/tutorials_examples/tutorial_combustion_chamber.rst +++ b/docs/tutorials/tutorial_combustion_chamber.rst @@ -1,11 +1,8 @@ +.. _tespy_tutorial_waste_heat_steam_recovery_label: + Combustion Chamber Tutorial --------------------------- -.. contents:: - :depth: 1 - :local: - :backlinks: top - There are two different types of combustion chambers available: - :py:class:`tespy.components.combustion.base.CombustionChamber` and diff --git a/docs/tutorials_examples/tutorial_heat_pump.rst b/docs/tutorials/tutorial_heat_pump.rst similarity index 98% rename from docs/tutorials_examples/tutorial_heat_pump.rst rename to docs/tutorials/tutorial_heat_pump.rst index e3fc85e56..96a22abb4 100644 --- a/docs/tutorials_examples/tutorial_heat_pump.rst +++ b/docs/tutorials/tutorial_heat_pump.rst @@ -1,11 +1,8 @@ +.. _tespy_tutorial_heat_pump_label: + Heat pump tutorial ------------------ -.. contents:: - :depth: 1 - :local: - :backlinks: top - Task ^^^^ @@ -96,7 +93,7 @@ originates, the source id is the outlet id of that component. This applies analogously to the target. To find all inlet and outlet ids of a component look up the class documentation of the respective component. An overview of the components available and the class documentations is provided in the -:ref:`TESPy modules overview `. The +:ref:`TESPy modules overview `. The :py:class:`tespy.connections.connection.Ref` class is used specify fluid property values by referencing fluid properties of different connections. It is used in a later step. @@ -205,7 +202,7 @@ After creating the system, we want to solve our network. First, we calculate the design case and directly after we can perform the offdesign calculation at a different value for our key parameter. For general information on the solving process in TESPy and available parameters check the corresponding section in -the :ref:`TESPy modules introduction `. +the :ref:`TESPy modules introduction `. .. code-block:: python @@ -300,7 +297,7 @@ default characteristic line of 'EVAPORATING FLUID' on the cold side and the default line 'DEFAULT' on the hot side. These lines are defined in the :ref:`tespy_data_label`. If you want to learn more about handling characteristic functions you should have a glance at the -:ref:`TESPy components section `. The superheater +:ref:`TESPy components section `. The superheater will also use the pressure ratios on hot and cold side. Further we set a value for the upper terminal temperature difference. For the pump we set the isentropic efficiency. For offdesign and design parameter specification of diff --git a/docs/tutorials_examples/tutorial_heat_pump_exergy.rst b/docs/tutorials/tutorial_heat_pump_exergy.rst similarity index 97% rename from docs/tutorials_examples/tutorial_heat_pump_exergy.rst rename to docs/tutorials/tutorial_heat_pump_exergy.rst index f44a38418..d6667af60 100644 --- a/docs/tutorials_examples/tutorial_heat_pump_exergy.rst +++ b/docs/tutorials/tutorial_heat_pump_exergy.rst @@ -1,12 +1,8 @@ +.. _tespy_tutorial_heat_pump_exergy_label: + Exergy Analysis of a Ground-Coupled Heat Pump --------------------------------------------- -.. contents:: - :depth: 1 - :local: - :backlinks: top - - Task ^^^^ @@ -49,7 +45,7 @@ ground heat feed flow (Source) and return flow (Sink). The heat pump circuit consists of the basic components: condenser, expansion valve, evaporator and compressor. -.. figure:: /api/_images/heat_pump_exergy_flowsheet.svg +.. figure:: /_static/images/tutorials/heat_pump_exergy/flowsheet.svg :align: center :alt: Topology of the Ground-Couped Heat Pump (GCHP) @@ -212,7 +208,7 @@ saved with the code shown below. diagram.save('NH3_logph.svg') -.. figure:: /api/_images/NH3_logph.svg +.. figure:: /_static/images/tutorials/heat_pump_exergy/NH3_logph.svg :align: center :alt: Fluid Property Diagram h-log(p) of the GCHP @@ -293,7 +289,7 @@ The product exergy is represented by the bus :code:`power`. The busses :code:`heat_cons` and :code:`heat_geo` are passed as fuel exergy. In the example of the GCHP, only :code:`E_F` and :code:`E_P` are defined. Other examples of exergy analysis setup can be found in the -:ref:`TESPy analysis ` page and in the API +:ref:`TESPy analysis ` page and in the API documentation of class :py:class:`tespy.tools.analyses.ExergyAnalysis`. .. code-block:: python @@ -308,7 +304,7 @@ The :py:meth:`tespy.tools.analyses.ExergyAnalysis.analyse` method will run the exergy analysis automatically. This method expects information about the ambient pressure and ambient temperature. Additionally, an automatic check of consistency is performed by the analysis as further described in -:ref:`TESPy analysis `. +:ref:`TESPy analysis `. Results +++++++ @@ -321,7 +317,7 @@ The results can be printed by using the ean.print_results() Further descriptions of which tables are printed and how to select what is -printed can be found in the :ref:`TESPy analysis section `. +printed can be found in the :ref:`TESPy analysis section `. There you can also find more detailed descriptions of how to access the underlying data for the tabular printouts, which are stored in `pandas DataFrames `_. @@ -344,7 +340,7 @@ method returns a dictionary containing links and nodes for the sankey diagram. plot(fig, filename='NH3_sankey') -.. figure:: /api/_images/NH3_sankey.svg +.. figure:: /_static/images/tutorials/heat_pump_exergy/NH3_sankey.svg :align: center :alt: Sankey diagram of the Ground-Coupled Heat Pump (GCHP) @@ -354,7 +350,7 @@ method returns a dictionary containing links and nodes for the sankey diagram. In the figure above you can see the sankey diagram which is created by running the script of the GCHP with NH3 as refrigerant. Information about, for example, the colors used or the node order can be found in the -:ref:`TESPy analysis section `. +:ref:`TESPy analysis section `. Post-Processing ^^^^^^^^^^^^^^^ @@ -441,7 +437,7 @@ Matplotlib, please check the `Matplotlib documentation `_. The resulting bar chart is shown below. -.. figure:: /api/_images/diagram_E_D.svg +.. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_E_D.svg :align: center :alt: Comparison of exergy destruction and exergy efficiency @@ -536,7 +532,7 @@ figure. The related Python code to create this plot can be found in the plot script (:download:`plots.py `). For further documentation please see the `Matplotlib documentation `_. -.. figure:: /api/_images/diagram_eps_Tamb_Tgeo.svg +.. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo.svg :align: center :alt: Varying Tamb and Tgeo of the GCHP @@ -614,7 +610,7 @@ The results of this calculation are shown in the following figure. The corresponding Python code can likewise be found in the plot script (:download:`plots.py `). -.. figure:: /api/_images/diagram_cop_eps_Tgeo_Ths.svg +.. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths.svg :align: center :alt: Varying Tgeo and Ths of the GCHP @@ -644,7 +640,7 @@ similarity to the previous parameter variation, the corresponding Python code is not presented, but can be found in the scripts linked at the beginning instead. -.. figure:: /api/_images/diagram_cop_eps_Tgeo_Q.svg +.. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q.svg :align: center :alt: Varying Tgeo and Q of the GCHP @@ -667,7 +663,7 @@ but also in the Python script of the plots, if a plot is created with the stand-alone plot script. More examples of exergy analysis can be found in the -:ref:`TESPy analysis section ` and in the API +:ref:`TESPy analysis section ` and in the API documentation of the :py:class:`tespy.tools.analyses.ExergyAnalysis` class. If you are interested in contributing or have questions and remarks on this tutorial, you are welcome to file an issue at our GitHub page. diff --git a/docs/tutorials_examples/tutorial_pygmo_optimization.rst b/docs/tutorials/tutorial_pygmo_optimization.rst similarity index 99% rename from docs/tutorials_examples/tutorial_pygmo_optimization.rst rename to docs/tutorials/tutorial_pygmo_optimization.rst index ba94a2f08..7196c9c3c 100644 --- a/docs/tutorials_examples/tutorial_pygmo_optimization.rst +++ b/docs/tutorials/tutorial_pygmo_optimization.rst @@ -1,11 +1,8 @@ +.. _tespy_tutorial_pygmo_optimization_label: + Thermal Power Plant Efficiency Optimization ------------------------------------------- -.. contents:: - :depth: 1 - :local: - :backlinks: top - Task ^^^^ @@ -87,6 +84,10 @@ It is necessary to use object oriented programming in PyGMO. Therefore we create a class :code:`PowerPlant` which contains our TESPy-Model and a function to return the cycle efficiency. +```{dropdown} Open dropdown +:open: + + .. code-block:: python from tespy.networks import Network @@ -248,6 +249,7 @@ return the cycle efficiency. return np.nan else: return self.nw.busses['power'].P.val / self.nw.busses['heat'].P.val +``` Note, that you have to label all busses and connections you want to access later on with PyGMO. In :code:`calculate_efficiency(self, x)` the variable diff --git a/docs/tutorials_examples/tutorial_starting_values.rst b/docs/tutorials/tutorial_starting_values.rst similarity index 98% rename from docs/tutorials_examples/tutorial_starting_values.rst rename to docs/tutorials/tutorial_starting_values.rst index b4ec4fe5b..6298fcf68 100644 --- a/docs/tutorials_examples/tutorial_starting_values.rst +++ b/docs/tutorials/tutorial_starting_values.rst @@ -1,11 +1,8 @@ +.. _tespy_tutorial_starting_values_label: + Stable starting values for subcritical heat pumps ------------------------------------------------- -.. contents:: - :depth: 1 - :local: - :backlinks: top - Applying numerical algorithms and methods, the starting value of a variable is the value used for the first iteration. With more complex TESPy models it can happen that the simulation does not converge easily due to a combination @@ -37,7 +34,7 @@ Following the first tutorial a slightly different topology for a heat pump with internal heat exchangers is considered instead of dumping the heat to the ambient. You can see the plant topology in the figure below. -.. figure:: api/_images/tutorial_sv_heat_pump_intheatex.svg +.. figure:: /_static/images/tutorials/heat_pump_starting_values/flowsheet.svg :align: center Figure: Topology of heat pump with internal heat exchanger @@ -233,7 +230,7 @@ pressure and enthalpy values instead of temperature differences. In this example, fixed points can be identified with the help of the logph diagram which you can see in the figure below. -.. figure:: api/_images/tutorial_sv_logph.svg +.. figure:: /_static/images/tutorials/heat_pump_starting_values/logph.svg :align: center Figure: Logph diagram of ammonia @@ -478,10 +475,10 @@ building a network, that works with a variety of working fluids. ax.set_title('Coefficicent of performance for different working fluids') plt.tight_layout() - fig.savefig('tutorial_sv_COP_by_wf.svg') + fig.savefig('COP_by_wf.svg') -.. figure:: api/_images/tutorial_sv_COP_by_wf.svg +.. figure:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg :align: center Figure: Topology of heat pump with internal heat exchanger diff --git a/docs/tutorials_examples.rst b/docs/tutorials_examples.rst deleted file mode 100644 index 030eddf80..000000000 --- a/docs/tutorials_examples.rst +++ /dev/null @@ -1,80 +0,0 @@ -~~~~~~~~~~~~~~~~~~~~~~ -Examples and Tutorials -~~~~~~~~~~~~~~~~~~~~~~ - -.. _tespy_examples_label: - -Examples -======== - -In the example section we provide a variety of TESPy applications, among -others: - -* a very basic model of the clausius rankine process, -* the calculation of backpressure lines of a combined heat and power cycle at - different loads and feed flow temperature levels, -* modeling approach for a district heating system with various consumers and - system infrastructure as well as -* the COP of a heat pump dependent on load, ambient temperature and heat - delivering fluid (air vs. water). - -You can find all examples in the TESPy -`examples repository `__ -on github. Additional small examples can be found in the API-documentation. - -* :py:mod:`Components ` -* :py:mod:`Connections and Busses ` -* :py:mod:`Networks ` -* :py:mod:`Importing Networks ` - -.. contents:: `Examples` - :depth: 1 - :local: - :backlinks: top - -.. _basic_example_label: -.. include:: tutorials_examples/clausius_rankine.rst -.. _combined_cycle_example_label: -.. include:: tutorials_examples/combined_cycle_chp.rst -.. _chp_example_label: -.. include:: tutorials_examples/clausius_rankine_chp.rst -.. _combustion_engine_label: -.. include:: tutorials_examples/combustion_engine.rst -.. _dh_example_label: -.. include:: tutorials_examples/district_heating.rst -.. _heat_pump_cop_label: -.. include:: tutorials_examples/heat_pump.rst -.. _solar_collector_example_label: -.. include:: tutorials_examples/solar_collector.rst -.. _tespy_tutorial_label: - -Tutorials -========= - -We provide tutorials for you to better understand how to work -with TESPy. You will learn how to create basic models and get the idea of -designing a plant and simulating the offdesign behavior in the heat pump -tutorial. Furthermore, the starting values tutorial will help you to get a -stable simulation and faster solutions. On top of that, we created a tutorial -for the usage of the combustion chamber: It is an important component for -thermal power plants while being a source for many errors in the calculation. - -The last tutorial is a plant design optimization tutorial. A thermal power -plant with two extraction stages is optimized in regard of thermal efficiency -with respect to the extraction pressure levels. - -.. contents:: `Tutorials` - :depth: 1 - :local: - :backlinks: top - -.. _heat_pump_tutorial_label: -.. include:: tutorials_examples/tutorial_heat_pump.rst -.. _starting_values_tutorial_label: -.. include:: tutorials_examples/tutorial_starting_values.rst -.. _combustion_chamber_tutorial_label: -.. include:: tutorials_examples/tutorial_combustion_chamber.rst -.. _pygmo_tutorial_label: -.. include:: tutorials_examples/tutorial_pygmo_optimization.rst -.. _heat_pump_exergy_tutorial_label: -.. include:: tutorials_examples/tutorial_heat_pump_exergy.rst diff --git a/docs/whats_new.rst b/docs/whats_new.rst index ec549e38a..b90e28fb2 100644 --- a/docs/whats_new.rst +++ b/docs/whats_new.rst @@ -3,11 +3,6 @@ What's New Discover noteable new features and improvements in each release -.. contents:: `Releases` - :depth: 1 - :local: - :backlinks: top - .. include:: whats_new/v0-6-1.rst .. include:: whats_new/v0-6-0.rst .. include:: whats_new/v0-5-1.rst diff --git a/docs/whats_new/v0-1-3.rst b/docs/whats_new/v0-1-3.rst index 00b3517c9..8afbddbd6 100644 --- a/docs/whats_new/v0-1-3.rst +++ b/docs/whats_new/v0-1-3.rst @@ -1,43 +1,43 @@ -v0.1.3 (November, 6, 2019) -++++++++++++++++++++++++++ - -New Features -############ -- Individual design path specification is available: Specify the design_path individually for single connections or a components in your network, if - you want the individual design parameters be loaded from a different design case than the network's design case given in the network's - design path (`PR #84 `_). -- Implement local design and local offdesign features: It is possible to design a plant while some parts of the plant are in offdesign mode. This is useful, - e.g. when designing an extraction turbine, where the district heating condenser is designed for maximum extraction and the backpressure turbine is designed - for minimum extraction (`PR #92 `_). -- Implement warning messages for all components, if the component's properties are out of physical bounds. The bounds can be customized when specifying a property - by data containers (read more at :ref:`component parameter specification `), (`PR #85 `_). - -Documentation -############# -- Change license from GPLv3 to MIT (`PR #93 `_). -- Fix unit error in component documentation for the zeta-value (`PR #93 `_). -- Improve documentation of the functions :func:`tespy.components.components.component.zeta_func` and :func:`tespy.components.components.component.zeta2_func` - (`4291bd `_). - -Parameter renaming -################## - -Testing -####### -- Added tests for the new design path feature (`PR #84 `_). -- Implemented additional network and component tests, (`PR #86 `_). - -Bug fixes -######### -- Offdesign values for connections are specified from the design case files (`PR #84 `_). Before, the offdesign values - were the actual values of the fluid property in the last calculation (which is not necessarily the design case). -- Add debug logging message, if the enthalpy is adjusted on connections with the keyword :code:`state` specified (`PR #85 `_). - -Other changes -############# -- Improved calculation speed for fluid mixture properties with the parameter T0 as starting value for root finding (`PR #84 `_). - -Contributors -############ - -- Francesco Witte +v0.1.3 (November, 6, 2019) +++++++++++++++++++++++++++ + +New Features +############ +- Individual design path specification is available: Specify the design_path individually for single connections or a components in your network, if + you want the individual design parameters be loaded from a different design case than the network's design case given in the network's + design path (`PR #84 `_). +- Implement local design and local offdesign features: It is possible to design a plant while some parts of the plant are in offdesign mode. This is useful, + e.g. when designing an extraction turbine, where the district heating condenser is designed for maximum extraction and the backpressure turbine is designed + for minimum extraction (`PR #92 `_). +- Implement warning messages for all components, if the component's properties are out of physical bounds. The bounds can be customized when specifying a property + by data containers (read more at :ref:`component parameter specification `), (`PR #85 `_). + +Documentation +############# +- Change license from GPLv3 to MIT (`PR #93 `_). +- Fix unit error in component documentation for the zeta-value (`PR #93 `_). +- Improve documentation of the functions :func:`tespy.components.components.component.zeta_func` and :func:`tespy.components.components.component.zeta2_func` + (`4291bd `_). + +Parameter renaming +################## + +Testing +####### +- Added tests for the new design path feature (`PR #84 `_). +- Implemented additional network and component tests, (`PR #86 `_). + +Bug fixes +######### +- Offdesign values for connections are specified from the design case files (`PR #84 `_). Before, the offdesign values + were the actual values of the fluid property in the last calculation (which is not necessarily the design case). +- Add debug logging message, if the enthalpy is adjusted on connections with the keyword :code:`state` specified (`PR #85 `_). + +Other changes +############# +- Improved calculation speed for fluid mixture properties with the parameter T0 as starting value for root finding (`PR #84 `_). + +Contributors +############ + +- Francesco Witte diff --git a/docs/whats_new/v0-2-2.rst b/docs/whats_new/v0-2-2.rst index 40c153357..4376a817b 100644 --- a/docs/whats_new/v0-2-2.rst +++ b/docs/whats_new/v0-2-2.rst @@ -1,65 +1,65 @@ -v0.2.2 - Rankine's Realm (March, 6, 2020) -+++++++++++++++++++++++++++++++++++++++++ - -New Features -############ -- Allow initialisation for the primary variables from previous calculation. - Until now, the user needed to save the network's state and reload that state - for his next simulation. This feature is enabled as default. If you want to - disable this feature, you need to state - :code:`mynetwork.solve(..., init_previous=False)` - (`PR #156 `_). -- Extrapolation for characteristic lines is available. In default state, the - upper or lower value range limit is used when a characteristic line is - evaluated outside of the available x-value range. The :code:`extrapolate` - parameter allows linear extrapolation, for an example see the corresponding - sections in the online documentation: - :ref:`component characteristics `, - :ref:`tespy characteristics ` - (`PR #159 `_). -- Add a new component evaporator for geothermal organic rankine cycle. The - component has inlets for geothermal steam brine. On the cold side, the orc - working fluid is evaporated. Read more about this component in the API - documentation: :py:class:`tespy.components.customs.orc_evaporator` - (`PR #148 `_). - -Documentation -############# -- Add method for automatic citations and references - (`PR #163 `_). - -Parameter renaming -################## - -Testing -####### -- Add convergence checks for all component tests. Some tests did not fail, even - if the calculation did not converge - (`PR #153 `_). -- Improve coverage of the networks module - (`PR #153 `_). -- Add tests for characteristic line and map evaluation - (`PR #159 `_). - -Bug fixes -######### -- Fix the bugged tests for compressor characteristic maps - (:py:meth:`tespy.components.turbomachinery.compressor.char_map_func`). The - pressure ratio factor of the lowest speedline available in the default data - ranges from about 0.2 to 0.5. Therefore the design pressure ratio should be - higher than 5 (`PR #156 `_). - -Other changes -############# -- Use the method :py:meth:`tespy.components.components.component.fluid_deriv` - for all components, that do not change composition between an inlet and the - respective outlet (`PR #153 `_). -- Adjust the method :py:meth:`tespy.components.components.component.zeta_func` - to work with all zeta value specifications - (`PR #153 `_). - -Contributors -############ -- Francesco Witte (`@fwitte `_) -- `@maltefritz `_ -- `@ChaofanChen `_ +v0.2.2 - Rankine's Realm (March, 6, 2020) ++++++++++++++++++++++++++++++++++++++++++ + +New Features +############ +- Allow initialisation for the primary variables from previous calculation. + Until now, the user needed to save the network's state and reload that state + for his next simulation. This feature is enabled as default. If you want to + disable this feature, you need to state + :code:`mynetwork.solve(..., init_previous=False)` + (`PR #156 `_). +- Extrapolation for characteristic lines is available. In default state, the + upper or lower value range limit is used when a characteristic line is + evaluated outside of the available x-value range. The :code:`extrapolate` + parameter allows linear extrapolation, for an example see the corresponding + sections in the online documentation: + :ref:`component characteristics `, + :ref:`tespy characteristics ` + (`PR #159 `_). +- Add a new component evaporator for geothermal organic rankine cycle. The + component has inlets for geothermal steam brine. On the cold side, the orc + working fluid is evaporated. Read more about this component in the API + documentation: :py:class:`tespy.components.customs.orc_evaporator` + (`PR #148 `_). + +Documentation +############# +- Add method for automatic citations and references + (`PR #163 `_). + +Parameter renaming +################## + +Testing +####### +- Add convergence checks for all component tests. Some tests did not fail, even + if the calculation did not converge + (`PR #153 `_). +- Improve coverage of the networks module + (`PR #153 `_). +- Add tests for characteristic line and map evaluation + (`PR #159 `_). + +Bug fixes +######### +- Fix the bugged tests for compressor characteristic maps + (:py:meth:`tespy.components.turbomachinery.compressor.char_map_func`). The + pressure ratio factor of the lowest speedline available in the default data + ranges from about 0.2 to 0.5. Therefore the design pressure ratio should be + higher than 5 (`PR #156 `_). + +Other changes +############# +- Use the method :py:meth:`tespy.components.components.component.fluid_deriv` + for all components, that do not change composition between an inlet and the + respective outlet (`PR #153 `_). +- Adjust the method :py:meth:`tespy.components.components.component.zeta_func` + to work with all zeta value specifications + (`PR #153 `_). + +Contributors +############ +- Francesco Witte (`@fwitte `_) +- `@maltefritz `_ +- `@ChaofanChen `_ diff --git a/docs/whats_new/v0-4-3-003.rst b/docs/whats_new/v0-4-3-003.rst index 57d2e4bdb..5d05df4c8 100644 --- a/docs/whats_new/v0-4-3-003.rst +++ b/docs/whats_new/v0-4-3-003.rst @@ -1,19 +1,19 @@ -v0.4.3-003 - Grassmann's Graph (May, 17, 2021) -++++++++++++++++++++++++++++++++++++++++++++++ - -Documentation -############# -- Fix typos in the HeatExchanger classes API docs. -- Add two more examples for exergy analysis setups. - -Other Changes -############# -- Remove Python3.6 support. -- Make it possible to include results in automatic model report, for more - information see the corresponding section in the documentation: - :ref:`TESPy Networks Postprocessing ` - (`PR #267 `_). - -Contributors -############ -- Francesco Witte (`@fwitte `_) +v0.4.3-003 - Grassmann's Graph (May, 17, 2021) +++++++++++++++++++++++++++++++++++++++++++++++ + +Documentation +############# +- Fix typos in the HeatExchanger classes API docs. +- Add two more examples for exergy analysis setups. + +Other Changes +############# +- Remove Python3.6 support. +- Make it possible to include results in automatic model report, for more + information see the corresponding section in the documentation: + :ref:`TESPy Networks Postprocessing ` + (`PR #267 `_). + +Contributors +############ +- Francesco Witte (`@fwitte `_) diff --git a/docs/whats_new/v0-4-3.rst b/docs/whats_new/v0-4-3.rst index 96778fb5c..bfb931088 100644 --- a/docs/whats_new/v0-4-3.rst +++ b/docs/whats_new/v0-4-3.rst @@ -37,7 +37,7 @@ New Features Documentation ############# - An own chapter for the - :ref:`exergy analysis toolbox ` has been added + :ref:`exergy analysis toolbox ` has been added (`PR #251 `_). - Fix some typos in the code of heat pump tutorial (`PR #260 `_). diff --git a/docs/zliterature.rst b/docs/zliterature.rst index 5d756bbc2..ba7707151 100644 --- a/docs/zliterature.rst +++ b/docs/zliterature.rst @@ -3,3 +3,4 @@ Literature .. bibliography:: references.bib :all: + :style: unsrt diff --git a/setup.py b/setup.py index 5f9a113a5..f1d85a1fe 100644 --- a/setup.py +++ b/setup.py @@ -71,7 +71,15 @@ def read(*names, **kwargs): 'tabulate>=0.8.2,<0.9' ], extras_require={ - 'dev': ['pytest', 'sphinx', 'sphinx_rtd_theme', - 'sphinxcontrib.bibtex', 'tox', ], - 'dummy': ['tespy']} + 'dev': [ + 'furo', + 'pytest', + 'sphinx', + 'sphinx-copybutton', + 'sphinx-inline-tabs', + 'sphinxcontrib.bibtex', + 'tox', + ], + 'dummy': ['tespy'] + } ) diff --git a/src/tespy/components/basics/subsystem_interface.py b/src/tespy/components/basics/subsystem_interface.py index 259bf2265..c5dd3e0c4 100644 --- a/src/tespy/components/basics/subsystem_interface.py +++ b/src/tespy/components/basics/subsystem_interface.py @@ -23,10 +23,8 @@ class SubsystemInterface(Component): - :py:meth:`tespy.components.component.Component.fluid_func` - :py:meth:`tespy.components.component.Component.mass_flow_func` - - Pressure: - :py:meth:`tespy.components.basics.subsystem_interface.SubsystemInterface.variable_equality_func` - - Enthalpy: - :py:meth:`tespy.components.basics.subsystem_interface.SubsystemInterface.variable_equality_func` + - :py:meth:`tespy.components.component.Component.pressure_equality_func` + - :py:meth:`tespy.components.component.Component.enthalpy_equality_func` Inlets/Outlets @@ -35,7 +33,7 @@ class SubsystemInterface(Component): Image - .. image:: _images/SubsystemInterface.svg + .. image:: /api/_images/SubsystemInterface.svg :alt: alternative text :align: center From bd1c3dc6b4627eba324884e1960741bd2d91c996 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 16 Aug 2022 19:42:47 +0200 Subject: [PATCH 029/120] Add try for basics flowsheets with darkmode --- docs/_static/images/basics/heat_pump.svg | 336 ++++++++++++++++++ .../images/basics/heat_pump_darkmode.svg | 336 ++++++++++++++++++ docs/_static/images/basics/rankine_cycle.svg | 336 ++++++++++++++++++ .../images/basics/rankine_cycle_darkmode.svg | 336 ++++++++++++++++++ 4 files changed, 1344 insertions(+) create mode 100644 docs/_static/images/basics/heat_pump.svg create mode 100644 docs/_static/images/basics/heat_pump_darkmode.svg create mode 100644 docs/_static/images/basics/rankine_cycle.svg create mode 100644 docs/_static/images/basics/rankine_cycle_darkmode.svg diff --git a/docs/_static/images/basics/heat_pump.svg b/docs/_static/images/basics/heat_pump.svg new file mode 100644 index 000000000..b6def10e5 --- /dev/null +++ b/docs/_static/images/basics/heat_pump.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + compressor + condenser + evaporator + expansion valve + + 0 + 1 + 2 + 3 + 4 + + diff --git a/docs/_static/images/basics/heat_pump_darkmode.svg b/docs/_static/images/basics/heat_pump_darkmode.svg new file mode 100644 index 000000000..200b2b81b --- /dev/null +++ b/docs/_static/images/basics/heat_pump_darkmode.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + compressor + condenser + evaporator + expansion valve + + 0 + 1 + 2 + 3 + 4 + + diff --git a/docs/_static/images/basics/rankine_cycle.svg b/docs/_static/images/basics/rankine_cycle.svg new file mode 100644 index 000000000..ae2e92e64 --- /dev/null +++ b/docs/_static/images/basics/rankine_cycle.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + feed pump + condenser + steamgenerator + turbine + + 0 + 1 + 2 + 3 + 4 + + diff --git a/docs/_static/images/basics/rankine_cycle_darkmode.svg b/docs/_static/images/basics/rankine_cycle_darkmode.svg new file mode 100644 index 000000000..4d57c2807 --- /dev/null +++ b/docs/_static/images/basics/rankine_cycle_darkmode.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + feed pump + condenser + steamgenerator + turbine + + 0 + 1 + 2 + 3 + 4 + + From 76f335f41606e34f4c51d493365855e4f8e02d22 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 16 Aug 2022 20:11:22 +0200 Subject: [PATCH 030/120] Fiddle around with some images --- docs/_static/images/basics/rankine_cycle.svg | 4 +-- .../images/basics/rankine_cycle_darkmode.svg | 36 +++++++++---------- docs/basics/district_heating.rst | 4 +-- docs/basics/gas_turbine.rst | 4 +-- docs/basics/heat_pump.rst | 6 ++-- docs/basics/rankine_cycle.rst | 6 ++-- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/_static/images/basics/rankine_cycle.svg b/docs/_static/images/basics/rankine_cycle.svg index ae2e92e64..40bc64160 100644 --- a/docs/_static/images/basics/rankine_cycle.svg +++ b/docs/_static/images/basics/rankine_cycle.svg @@ -3,7 +3,7 @@ inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" - sodipodi:docname="basics_rankine_cycle.svg" + sodipodi:docname="rankine_cycle.svg" inkscape:version="1.1.2 (1:1.1+202202050950+0a00cf5339)" id="svg8" version="1.1" @@ -69,7 +69,7 @@ inkscape:current-layer="layer1" inkscape:document-units="mm" inkscape:cy="204.5" - inkscape:cx="133" + inkscape:cx="79" inkscape:zoom="1" inkscape:pageshadow="2" inkscape:pageopacity="0.0" diff --git a/docs/_static/images/basics/rankine_cycle_darkmode.svg b/docs/_static/images/basics/rankine_cycle_darkmode.svg index 4d57c2807..e1e189230 100644 --- a/docs/_static/images/basics/rankine_cycle_darkmode.svg +++ b/docs/_static/images/basics/rankine_cycle_darkmode.svg @@ -3,7 +3,7 @@ inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" - sodipodi:docname="basics_rankine_cycle_dm.svg" + sodipodi:docname="rankine_cycle_darkmode.svg" inkscape:version="1.1.2 (1:1.1+202202050950+0a00cf5339)" id="svg8" version="1.1" @@ -69,7 +69,7 @@ inkscape:current-layer="layer1" inkscape:document-units="mm" inkscape:cy="204.5" - inkscape:cx="133" + inkscape:cx="79" inkscape:zoom="1" inkscape:pageshadow="2" inkscape:pageopacity="0.0" @@ -117,22 +117,22 @@ id="g2293-1" inkscape:export-xdpi="1012" inkscape:export-ydpi="1012" - style="stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke:#ffffff;stroke-opacity:1"> + style="stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"> @@ -140,29 +140,29 @@ + style="stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1">
turbine Date: Tue, 16 Aug 2022 20:47:54 +0200 Subject: [PATCH 031/120] Fix the alignment of figures --- docs/basics/district_heating.rst | 6 ++++-- docs/basics/gas_turbine.rst | 6 ++++-- docs/basics/heat_pump.rst | 6 ++++-- docs/basics/rankine_cycle.rst | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/basics/district_heating.rst b/docs/basics/district_heating.rst index 979347998..7d93a842b 100644 --- a/docs/basics/district_heating.rst +++ b/docs/basics/district_heating.rst @@ -6,11 +6,13 @@ District Heating Network .. figure:: /_static/images/basics/district_heating.svg :align: center :alt: Topology of the district heating network - :class: only-light + :figclass: only-light + + Figure: Topology of the district heating network .. figure:: /_static/images/basics/district_heating_darkmode.svg :align: center :alt: Topology of the district heating network - :class: only-dark + :figclass: only-dark Figure: Topology of the district heating network diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst index 128b852ee..c0ea8f727 100644 --- a/docs/basics/gas_turbine.rst +++ b/docs/basics/gas_turbine.rst @@ -6,11 +6,13 @@ Gas Turbine .. figure:: /_static/images/basics/gas_turbine.svg :align: center :alt: Topology of the gas turbine - :class: only-light + :figclass: only-light + + Figure: Topology of the gas turbine .. figure:: /_static/images/basics/gas_turbine_darkmode.svg :align: center :alt: Topology of the gas turbine - :class: only-dark + :figclass: only-dark Figure: Topology of the gas turbine diff --git a/docs/basics/heat_pump.rst b/docs/basics/heat_pump.rst index 256cfc52b..4c6ee07c7 100644 --- a/docs/basics/heat_pump.rst +++ b/docs/basics/heat_pump.rst @@ -6,11 +6,13 @@ Heat Pump .. figure:: /_static/images/basics/heat_pump.svg :align: center :alt: Topology of the heat pump - :class: only-light + :figclass: only-light + + Figure: Topology of the heat pump .. figure:: /_static/images/basics/heat_pump_darkmode.svg :align: center :alt: Topology of the heat pump - :class: only-dark + :figclass: only-dark Figure: Topology of the heat pump diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst index cd114564a..e76abc390 100644 --- a/docs/basics/rankine_cycle.rst +++ b/docs/basics/rankine_cycle.rst @@ -6,11 +6,13 @@ Rankine Cycle .. figure:: /_static/images/basics/rankine_cycle.svg :align: center :alt: Topology of the rankine cycle - :class: only-light + :figclass: only-light + + Figure: Topology of the rankine cycle .. figure:: /_static/images/basics/rankine_cycle_darkmode.svg :align: center :alt: Topology of the rankine cycle - :class: only-dark + :figclass: only-dark Figure: Topology of the rankine cycle From 67a2cab70402c2ea7b35a3d9404657f24829e7a9 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 20 Aug 2022 10:37:48 +0200 Subject: [PATCH 032/120] Change some sphinx stuff, try dropdown --- docs/_static/images/NH3_logph.svg | 5320 ----------------- docs/basics.rst | 4 +- docs/conf.py | 3 +- docs/contents.rst | 1 - docs/development/how.rst | 4 +- docs/development/what.rst | 4 +- docs/installation.rst | 80 +- .../tutorials/tutorial_pygmo_optimization.rst | 340 +- setup.py | 2 +- 9 files changed, 217 insertions(+), 5541 deletions(-) delete mode 100644 docs/_static/images/NH3_logph.svg diff --git a/docs/_static/images/NH3_logph.svg b/docs/_static/images/NH3_logph.svg deleted file mode 100644 index 8f92ce182..000000000 --- a/docs/_static/images/NH3_logph.svg +++ /dev/null @@ -1,5320 +0,0 @@ - - - - - - - - - 2021-08-20T14:47:53.897807 - image/svg+xml - - - Matplotlib v3.3.4, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/basics.rst b/docs/basics.rst index 55190a273..6e5126552 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -1,5 +1,5 @@ -Basics -~~~~~~ +Modeling Basic Systems +~~~~~~~~~~~~~~~~~~~~~~ * :py:mod:`Components ` * :py:mod:`Connections and Busses ` diff --git a/docs/conf.py b/docs/conf.py index 39749f058..080ce709a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,12 +22,11 @@ 'sphinx.ext.doctest', 'sphinx.ext.extlinks', 'sphinx.ext.ifconfig', - 'sphinx.ext.imgmath', 'sphinx.ext.napoleon', 'sphinx.ext.todo', 'sphinx.ext.viewcode', 'sphinx_copybutton', - 'sphinx_inline_tabs', + 'sphinx_design', 'sphinxcontrib.bibtex', ] diff --git a/docs/contents.rst b/docs/contents.rst index 7b0459787..051e7b477 100644 --- a/docs/contents.rst +++ b/docs/contents.rst @@ -8,7 +8,6 @@ Contents .. toctree:: :maxdepth: 2 - :caption: Quickstart introduction diff --git a/docs/development/how.rst b/docs/development/how.rst index fb690e4b6..37c0cf3cd 100644 --- a/docs/development/how.rst +++ b/docs/development/how.rst @@ -1,7 +1,7 @@ .. _tespy_development_how_label: -How to contribute -================= +How can I contribute? +===================== You will find the most important information concerning the development process in the following sections. If you have any further questions feel free to diff --git a/docs/development/what.rst b/docs/development/what.rst index 796a58a0c..4f3bd4fac 100644 --- a/docs/development/what.rst +++ b/docs/development/what.rst @@ -1,7 +1,7 @@ .. __tespy_development_what_label: -What can I contribute -===================== +What can I contribute? +====================== TESPy has been developed mainly by Francesco Witte at the University of Applied Sciences Flensburg - and a lot of free time. We hope that many people can make use of this project and that it will be a community driven project in the diff --git a/docs/installation.rst b/docs/installation.rst index 84d9adad3..ad8cecd3c 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -8,62 +8,64 @@ Following you find guidelines for the installation process for linux and windows. TESPy is a Python package, thus it requires you to have Python 3 installed. -.. tab:: Linux +.. tab-set:: - **Installing Python 3** + .. tab-item:: Linux - Most Linux distributions will have Python 3 in their repository. Use the - specific software management to install it, if it is not yet installed. If - you are using Ubuntu/Debian try executing the following code in your - terminal: + **Installing Python 3** - .. code:: console + Most Linux distributions will have Python 3 in their repository. Use the + specific software management to install it, if it is not yet installed. If + you are using Ubuntu/Debian try executing the following code in your + terminal: - sudo apt-get install python3 + .. code:: console - You can also download different versions of Python via - https://www.python.org/downloads/. + sudo apt-get install python3 - **Having Python 3 installed** + You can also download different versions of Python via + https://www.python.org/downloads/. - We recommend installting TESPy within a virtual Python enviroment an not - into the base, system wide Python installation. On Linux you can use - virtualenv to do so. + **Having Python 3 installed** - 1. Install virtualenv using the package management of your Linux distribution, - pip install or install it from source - (`see virtualenv documentation `_) - 2. Open terminal to create and activate a virtual environment by typing: + We recommend installting TESPy within a virtual Python enviroment an not + into the base, system wide Python installation. On Linux you can use + virtualenv to do so. - .. code-block:: console + 1. Install virtualenv using the package management of your Linux distribution, + pip install or install it from source + (`see virtualenv documentation `_) + 2. Open terminal to create and activate a virtual environment by typing: - virtualenv -p /usr/bin/python3 your_env_name - source your_env_name/bin/activate + .. code-block:: console - 3. In terminal type: :code:`pip install tespy` + virtualenv -p /usr/bin/python3 your_env_name + source your_env_name/bin/activate - Warning: If you have an older version of virtualenv you should update pip - :code:`pip install --upgrade pip`. + 3. In terminal type: :code:`pip install tespy` - **Using Conda** + Warning: If you have an older version of virtualenv you should update pip + :code:`pip install --upgrade pip`. - Alternatively you can use conda for enviroment and package management. You - can follow the installation instructions for windows users. + **Using Conda** -.. tab:: Windows + Alternatively you can use conda for enviroment and package management. You + can follow the installation instructions for windows users. - For windows we recommend using conda as package manager. You can download a - light weight open source variant of conda: "miniforge3". + .. tab-item:: Windows - 1. Download latest `miniforge3 `__ - for Python 3.x (64 or 32 bit). - 2. Install miniforge3 - 3. Open "miniforge prompt" to manage your virtual environments. You can - create a new environment and acivate it by + For windows we recommend using conda as package manager. You can download a + light weight open source variant of conda: "miniforge3". - .. code-block:: console + 1. Download latest `miniforge3 `__ + for Python 3.x (64 or 32 bit). + 2. Install miniforge3 + 3. Open "miniforge prompt" to manage your virtual environments. You can + create a new environment and acivate it by - conda create -n tespy-env python=3.9 - activate tespy-env + .. code-block:: console - 4. In the active prompt type: :code:`pip install tespy` + conda create -n tespy-env python=3.9 + activate tespy-env + + 4. In the active prompt type: :code:`pip install tespy` diff --git a/docs/tutorials/tutorial_pygmo_optimization.rst b/docs/tutorials/tutorial_pygmo_optimization.rst index 7196c9c3c..cc0e3ad1d 100644 --- a/docs/tutorials/tutorial_pygmo_optimization.rst +++ b/docs/tutorials/tutorial_pygmo_optimization.rst @@ -51,13 +51,11 @@ approximation for the real optimum. Install PyGMO +++++++++++++ - -Conda +conda ##### -With the `conda `_ package manager PyGMO is -available for Linux, OSX and Windows thanks to the infrastructure of -`conda-forge `_: +With the conda package manager PyGMO is available for Linux, OSX and Windows +thanks to the infrastructure of `conda-forge `_: .. code-block:: bash @@ -75,7 +73,8 @@ On Linux you also have the option to use the Windows user can perform an installation from source as an alternative to conda. For further information on this process we recommend the `PyGMO installation -`_ accordingly. +`__ +accordingly. Creating your TESPy-Model ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,172 +83,169 @@ It is necessary to use object oriented programming in PyGMO. Therefore we create a class :code:`PowerPlant` which contains our TESPy-Model and a function to return the cycle efficiency. -```{dropdown} Open dropdown -:open: - - -.. code-block:: python - - from tespy.networks import Network - from tespy.components import ( - Turbine, Splitter, Merge, Condenser, Pump, Sink, Source, - HeatExchangerSimple, Desuperheater, CycleCloser - ) - from tespy.connections import Connection, Bus - from tespy.tools import logger - import logging - - import numpy as np - - - logger.define_logging(screen_level=logging.ERROR) - - - class PowerPlant(): - - def __init__(self): - self.nw = Network( - fluids=['BICUBIC::water'], - p_unit='bar', T_unit='C', h_unit='kJ / kg', - iterinfo=False) - # components - # main cycle - eco = HeatExchangerSimple('economizer') - eva = HeatExchangerSimple('evaporator') - sup = HeatExchangerSimple('superheater') - cc = CycleCloser('cycle closer') - hpt = Turbine('high pressure turbine') - sp1 = Splitter('splitter 1', num_out=2) - mpt = Turbine('mid pressure turbine') - sp2 = Splitter('splitter 2', num_out=2) - lpt = Turbine('low pressure turbine') - con = Condenser('condenser') - pu1 = Pump('feed water pump') - fwh1 = Condenser('feed water preheater 1') - fwh2 = Condenser('feed water preheater 2') - dsh = Desuperheater('desuperheater') - me2 = Merge('merge2', num_in=2) - pu2 = Pump('feed water pump 2') - pu3 = Pump('feed water pump 3') - me = Merge('merge', num_in=2) - - # cooling water - cwi = Source('cooling water source') - cwo = Sink('cooling water sink') - - # connections - # main cycle - cc_hpt = Connection(cc, 'out1', hpt, 'in1', label='feed steam') - hpt_sp1 = Connection(hpt, 'out1', sp1, 'in1', label='extraction1') - sp1_mpt = Connection(sp1, 'out1', mpt, 'in1', state='g') - mpt_sp2 = Connection(mpt, 'out1', sp2, 'in1', label='extraction2') - sp2_lpt = Connection(sp2, 'out1', lpt, 'in1') - lpt_con = Connection(lpt, 'out1', con, 'in1') - con_pu1 = Connection(con, 'out1', pu1, 'in1') - pu1_fwh1 = Connection(pu1, 'out1', fwh1, 'in2') - fwh1_me = Connection(fwh1, 'out2', me, 'in1', state='l') - me_fwh2 = Connection(me, 'out1', fwh2, 'in2', state='l') - fwh2_dsh = Connection(fwh2, 'out2', dsh, 'in2', state='l') - dsh_me2 = Connection(dsh, 'out2', me2, 'in1') - me2_eco = Connection(me2, 'out1', eco, 'in1', state='l') - eco_eva = Connection(eco, 'out1', eva, 'in1') - eva_sup = Connection(eva, 'out1', sup, 'in1') - sup_cc = Connection(sup, 'out1', cc, 'in1') - - self.nw.add_conns(cc_hpt, hpt_sp1, sp1_mpt, mpt_sp2, sp2_lpt, - lpt_con, con_pu1, pu1_fwh1, fwh1_me, me_fwh2, - fwh2_dsh, dsh_me2, me2_eco, eco_eva, eva_sup, sup_cc) - - # cooling water - cwi_con = Connection(cwi, 'out1', con, 'in2') - con_cwo = Connection(con, 'out2', cwo, 'in1') - - self.nw.add_conns(cwi_con, con_cwo) - - # preheating - sp1_dsh = Connection(sp1, 'out2', dsh, 'in1') - dsh_fwh2 = Connection(dsh, 'out1', fwh2, 'in1') - fwh2_pu2 = Connection(fwh2, 'out1', pu2, 'in1') - pu2_me2 = Connection(pu2, 'out1', me2, 'in2') - - sp2_fwh1 = Connection(sp2, 'out2', fwh1, 'in1') - fwh1_pu3 = Connection(fwh1, 'out1', pu3, 'in1') - pu3_me = Connection(pu3, 'out1', me, 'in2') - - self.nw.add_conns(sp1_dsh, dsh_fwh2, fwh2_pu2, pu2_me2, - sp2_fwh1, fwh1_pu3, pu3_me) - - # busses - # power bus - self.power = Bus('power') - self.power.add_comps( - {'comp': hpt, 'char': -1}, {'comp': mpt, 'char': -1}, - {'comp': lpt, 'char': -1}, {'comp': pu1, 'char': -1}, - {'comp': pu2, 'char': -1}, {'comp': pu3, 'char': -1}) - - # heating bus - self.heat = Bus('heat') - self.heat.add_comps( - {'comp': eco, 'char': 1}, {'comp': eva, 'char': 1}, - {'comp': sup, 'char': 1}) - - self.nw.add_busses(self.power, self.heat) - - # parametrization - # components - hpt.set_attr(eta_s=0.9) - mpt.set_attr(eta_s=0.9) - lpt.set_attr(eta_s=0.9) - - pu1.set_attr(eta_s=0.8) - pu2.set_attr(eta_s=0.8) - pu3.set_attr(eta_s=0.8) - - eco.set_attr(pr=0.99) - eva.set_attr(pr=0.99) - sup.set_attr(pr=0.99) - - con.set_attr(pr1=1, pr2=0.99, ttd_u=5) - fwh1.set_attr(pr1=1, pr2=0.99, ttd_u=5) - fwh2.set_attr(pr1=1, pr2=0.99, ttd_u=5) - dsh.set_attr(pr1=0.99, pr2=0.99) - - # connections - eco_eva.set_attr(x=0) - eva_sup.set_attr(x=1) - - cc_hpt.set_attr(m=200, T=650, p=100, fluid={'water': 1}) - hpt_sp1.set_attr(p=20) - mpt_sp2.set_attr(p=3) - lpt_con.set_attr(p=0.05) - - cwi_con.set_attr(T=20, p=10, fluid={'water': 1}) - - def calculate_efficiency(self, x): - # set extraction pressure - self.nw.get_conn('extraction1').set_attr(p=x[0]) - self.nw.get_conn('extraction2').set_attr(p=x[1]) - - self.nw.solve('design') - - # components are saved in a DataFrame, column 'object' holds the - # component instances - for cp in self.nw.comps['object']: - if isinstance(cp, Condenser) or isinstance(cp, Desuperheater): - if cp.Q.val > 0: - return np.nan - elif isinstance(cp, Pump): - if cp.P.val < 0: - return np.nan - elif isinstance(cp, Turbine): - if cp.P.val > 0: - return np.nan - - if self.nw.res[-1] > 1e-3 or self.nw.lin_dep: - return np.nan - else: - return self.nw.busses['power'].P.val / self.nw.busses['heat'].P.val -``` +.. dropdown:: Display source code for the PowerPlant class + + .. code-block:: python + + from tespy.networks import Network + from tespy.components import ( + Turbine, Splitter, Merge, Condenser, Pump, Sink, Source, + HeatExchangerSimple, Desuperheater, CycleCloser + ) + from tespy.connections import Connection, Bus + from tespy.tools import logger + import logging + + import numpy as np + + + logger.define_logging(screen_level=logging.ERROR) + + + class PowerPlant(): + + def __init__(self): + self.nw = Network( + fluids=['BICUBIC::water'], + p_unit='bar', T_unit='C', h_unit='kJ / kg', + iterinfo=False) + # components + # main cycle + eco = HeatExchangerSimple('economizer') + eva = HeatExchangerSimple('evaporator') + sup = HeatExchangerSimple('superheater') + cc = CycleCloser('cycle closer') + hpt = Turbine('high pressure turbine') + sp1 = Splitter('splitter 1', num_out=2) + mpt = Turbine('mid pressure turbine') + sp2 = Splitter('splitter 2', num_out=2) + lpt = Turbine('low pressure turbine') + con = Condenser('condenser') + pu1 = Pump('feed water pump') + fwh1 = Condenser('feed water preheater 1') + fwh2 = Condenser('feed water preheater 2') + dsh = Desuperheater('desuperheater') + me2 = Merge('merge2', num_in=2) + pu2 = Pump('feed water pump 2') + pu3 = Pump('feed water pump 3') + me = Merge('merge', num_in=2) + + # cooling water + cwi = Source('cooling water source') + cwo = Sink('cooling water sink') + + # connections + # main cycle + cc_hpt = Connection(cc, 'out1', hpt, 'in1', label='feed steam') + hpt_sp1 = Connection(hpt, 'out1', sp1, 'in1', label='extraction1') + sp1_mpt = Connection(sp1, 'out1', mpt, 'in1', state='g') + mpt_sp2 = Connection(mpt, 'out1', sp2, 'in1', label='extraction2') + sp2_lpt = Connection(sp2, 'out1', lpt, 'in1') + lpt_con = Connection(lpt, 'out1', con, 'in1') + con_pu1 = Connection(con, 'out1', pu1, 'in1') + pu1_fwh1 = Connection(pu1, 'out1', fwh1, 'in2') + fwh1_me = Connection(fwh1, 'out2', me, 'in1', state='l') + me_fwh2 = Connection(me, 'out1', fwh2, 'in2', state='l') + fwh2_dsh = Connection(fwh2, 'out2', dsh, 'in2', state='l') + dsh_me2 = Connection(dsh, 'out2', me2, 'in1') + me2_eco = Connection(me2, 'out1', eco, 'in1', state='l') + eco_eva = Connection(eco, 'out1', eva, 'in1') + eva_sup = Connection(eva, 'out1', sup, 'in1') + sup_cc = Connection(sup, 'out1', cc, 'in1') + + self.nw.add_conns(cc_hpt, hpt_sp1, sp1_mpt, mpt_sp2, sp2_lpt, + lpt_con, con_pu1, pu1_fwh1, fwh1_me, me_fwh2, + fwh2_dsh, dsh_me2, me2_eco, eco_eva, eva_sup, sup_cc) + + # cooling water + cwi_con = Connection(cwi, 'out1', con, 'in2') + con_cwo = Connection(con, 'out2', cwo, 'in1') + + self.nw.add_conns(cwi_con, con_cwo) + + # preheating + sp1_dsh = Connection(sp1, 'out2', dsh, 'in1') + dsh_fwh2 = Connection(dsh, 'out1', fwh2, 'in1') + fwh2_pu2 = Connection(fwh2, 'out1', pu2, 'in1') + pu2_me2 = Connection(pu2, 'out1', me2, 'in2') + + sp2_fwh1 = Connection(sp2, 'out2', fwh1, 'in1') + fwh1_pu3 = Connection(fwh1, 'out1', pu3, 'in1') + pu3_me = Connection(pu3, 'out1', me, 'in2') + + self.nw.add_conns(sp1_dsh, dsh_fwh2, fwh2_pu2, pu2_me2, + sp2_fwh1, fwh1_pu3, pu3_me) + + # busses + # power bus + self.power = Bus('power') + self.power.add_comps( + {'comp': hpt, 'char': -1}, {'comp': mpt, 'char': -1}, + {'comp': lpt, 'char': -1}, {'comp': pu1, 'char': -1}, + {'comp': pu2, 'char': -1}, {'comp': pu3, 'char': -1}) + + # heating bus + self.heat = Bus('heat') + self.heat.add_comps( + {'comp': eco, 'char': 1}, {'comp': eva, 'char': 1}, + {'comp': sup, 'char': 1}) + + self.nw.add_busses(self.power, self.heat) + + # parametrization + # components + hpt.set_attr(eta_s=0.9) + mpt.set_attr(eta_s=0.9) + lpt.set_attr(eta_s=0.9) + + pu1.set_attr(eta_s=0.8) + pu2.set_attr(eta_s=0.8) + pu3.set_attr(eta_s=0.8) + + eco.set_attr(pr=0.99) + eva.set_attr(pr=0.99) + sup.set_attr(pr=0.99) + + con.set_attr(pr1=1, pr2=0.99, ttd_u=5) + fwh1.set_attr(pr1=1, pr2=0.99, ttd_u=5) + fwh2.set_attr(pr1=1, pr2=0.99, ttd_u=5) + dsh.set_attr(pr1=0.99, pr2=0.99) + + # connections + eco_eva.set_attr(x=0) + eva_sup.set_attr(x=1) + + cc_hpt.set_attr(m=200, T=650, p=100, fluid={'water': 1}) + hpt_sp1.set_attr(p=20) + mpt_sp2.set_attr(p=3) + lpt_con.set_attr(p=0.05) + + cwi_con.set_attr(T=20, p=10, fluid={'water': 1}) + + def calculate_efficiency(self, x): + # set extraction pressure + self.nw.get_conn('extraction1').set_attr(p=x[0]) + self.nw.get_conn('extraction2').set_attr(p=x[1]) + + self.nw.solve('design') + + # components are saved in a DataFrame, column 'object' holds the + # component instances + for cp in self.nw.comps['object']: + if isinstance(cp, Condenser) or isinstance(cp, Desuperheater): + if cp.Q.val > 0: + return np.nan + elif isinstance(cp, Pump): + if cp.P.val < 0: + return np.nan + elif isinstance(cp, Turbine): + if cp.P.val > 0: + return np.nan + + if self.nw.res[-1] > 1e-3 or self.nw.lin_dep: + return np.nan + else: + return self.nw.busses['power'].P.val / self.nw.busses['heat'].P.val Note, that you have to label all busses and connections you want to access later on with PyGMO. In :code:`calculate_efficiency(self, x)` the variable diff --git a/setup.py b/setup.py index f1d85a1fe..dd1423e6c 100644 --- a/setup.py +++ b/setup.py @@ -76,7 +76,7 @@ def read(*names, **kwargs): 'pytest', 'sphinx', 'sphinx-copybutton', - 'sphinx-inline-tabs', + 'sphinx-design', 'sphinxcontrib.bibtex', 'tox', ], From b5d044d45fe714e6b07ca0c584805e7455a82ff5 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 20 Aug 2022 10:38:35 +0200 Subject: [PATCH 033/120] Some imporvements to loading time and mass flow default starting values --- src/tespy/connections/bus.py | 2 +- src/tespy/networks/network.py | 5 +++-- src/tespy/tools/characteristics.py | 5 ++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tespy/connections/bus.py b/src/tespy/connections/bus.py index d81e74f38..05bb5687a 100644 --- a/src/tespy/connections/bus.py +++ b/src/tespy/connections/bus.py @@ -93,7 +93,7 @@ class Bus: >>> pu.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) >>> amb_comb.set_attr(p=5, T=30, fluid={'Ar': 0.0129, 'N2': 0.7553, ... 'H2O': 0, 'CH4': 0, 'CO2': 0.0004, 'O2': 0.2314}) - >>> sf_comb.set_attr(m0=0.1, T=30, fluid={'CO2': 0, 'Ar': 0, 'N2': 0, + >>> sf_comb.set_attr(T=30, fluid={'CO2': 0, 'Ar': 0, 'N2': 0, ... 'O2': 0, 'H2O': 0, 'CH4': 1}) >>> cw_pu.set_attr(p=3, T=60, fluid={'CO2': 0, 'Ar': 0, 'N2': 0, ... 'O2': 0, 'H2O': 1, 'CH4': 0}) diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index 29b68ab91..a681c88b8 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -1464,9 +1464,10 @@ def init_val0(self, c, key): Connection to initialise. """ if np.isnan(c.get_attr(key).val0): - # starting value for mass flow is 1 kg/s + # starting value for mass flow is random between 1 and 2 kg/s + # (should be generated based on some hash maybe?) if key == 'm': - c.get_attr(key).val0 = 1 + c.get_attr(key).val0 = np.random.random() + 1 # generic starting values for pressure and enthalpy else: diff --git a/src/tespy/tools/characteristics.py b/src/tespy/tools/characteristics.py index 8b86d5f81..75bfa413a 100644 --- a/src/tespy/tools/characteristics.py +++ b/src/tespy/tools/characteristics.py @@ -19,7 +19,6 @@ import os import numpy as np -from matplotlib import pyplot as plt from tespy import __datapath__ from tespy.tools.helpers import extend_basic_path @@ -170,6 +169,8 @@ def get_attr(self, key): def plot(self, path, title, xlabel, ylabel): + from matplotlib import pyplot as plt + # plotting fig = plt.figure() ax = plt.subplot() @@ -446,6 +447,8 @@ def get_attr(self, key): def plot(self, path, title, xlabel, ylabel): + from matplotlib import pyplot as plt + # plotting fig = plt.figure() ax = plt.subplot() From b262dec3b61292ebe743ddf753f166c80f22ab06 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 20 Aug 2022 11:21:22 +0200 Subject: [PATCH 034/120] Move first steps to basics directory --- docs/{first_steps.rst => basics/intro.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{first_steps.rst => basics/intro.rst} (100%) diff --git a/docs/first_steps.rst b/docs/basics/intro.rst similarity index 100% rename from docs/first_steps.rst rename to docs/basics/intro.rst From 005c043e97addf5914ac9508c7c79910157f2373 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 20 Aug 2022 11:22:01 +0200 Subject: [PATCH 035/120] Move district heating tutorial files --- .../images/{ => tutorials/district_heating_system}/dhs.svg | 0 .../images/{ => tutorials/district_heating_system}/dhs_closed.svg | 0 .../images/{ => tutorials/district_heating_system}/dhs_forks.svg | 0 .../images/{ => tutorials/district_heating_system}/dhs_open.svg | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename docs/_static/images/{ => tutorials/district_heating_system}/dhs.svg (100%) rename docs/_static/images/{ => tutorials/district_heating_system}/dhs_closed.svg (100%) rename docs/_static/images/{ => tutorials/district_heating_system}/dhs_forks.svg (100%) rename docs/_static/images/{ => tutorials/district_heating_system}/dhs_open.svg (100%) diff --git a/docs/_static/images/dhs.svg b/docs/_static/images/tutorials/district_heating_system/dhs.svg similarity index 100% rename from docs/_static/images/dhs.svg rename to docs/_static/images/tutorials/district_heating_system/dhs.svg diff --git a/docs/_static/images/dhs_closed.svg b/docs/_static/images/tutorials/district_heating_system/dhs_closed.svg similarity index 100% rename from docs/_static/images/dhs_closed.svg rename to docs/_static/images/tutorials/district_heating_system/dhs_closed.svg diff --git a/docs/_static/images/dhs_forks.svg b/docs/_static/images/tutorials/district_heating_system/dhs_forks.svg similarity index 100% rename from docs/_static/images/dhs_forks.svg rename to docs/_static/images/tutorials/district_heating_system/dhs_forks.svg diff --git a/docs/_static/images/dhs_open.svg b/docs/_static/images/tutorials/district_heating_system/dhs_open.svg similarity index 100% rename from docs/_static/images/dhs_open.svg rename to docs/_static/images/tutorials/district_heating_system/dhs_open.svg From 10ffb964c3f0a9f38a4a806f42fa1944b7728887 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 20 Aug 2022 11:22:28 +0200 Subject: [PATCH 036/120] Create figures for all basics --- .../images/basics/district_heating.svg | 376 ++++++++++++++++++ .../basics/district_heating_darkmode.svg | 376 ++++++++++++++++++ docs/_static/images/basics/gas_turbine.svg | 350 ++++++++++++++++ .../images/basics/gas_turbine_darkmode.svg | 350 ++++++++++++++++ 4 files changed, 1452 insertions(+) create mode 100644 docs/_static/images/basics/district_heating.svg create mode 100644 docs/_static/images/basics/district_heating_darkmode.svg create mode 100644 docs/_static/images/basics/gas_turbine.svg create mode 100644 docs/_static/images/basics/gas_turbine_darkmode.svg diff --git a/docs/_static/images/basics/district_heating.svg b/docs/_static/images/basics/district_heating.svg new file mode 100644 index 000000000..a146466b1 --- /dev/null +++ b/docs/_static/images/basics/district_heating.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + consumer + control valve + return pipe + feed pipe + feed pump + sink + source + 1 + 2 + 3 + 4 + 5 + 6 + + diff --git a/docs/_static/images/basics/district_heating_darkmode.svg b/docs/_static/images/basics/district_heating_darkmode.svg new file mode 100644 index 000000000..bd92000b6 --- /dev/null +++ b/docs/_static/images/basics/district_heating_darkmode.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + consumer + control valve + return pipe + feed pipe + feed pump + sink + source + 1 + 2 + 3 + 4 + 5 + 6 + + diff --git a/docs/_static/images/basics/gas_turbine.svg b/docs/_static/images/basics/gas_turbine.svg new file mode 100644 index 000000000..0b15ac120 --- /dev/null +++ b/docs/_static/images/basics/gas_turbine.svg @@ -0,0 +1,350 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + compressor + combustion chamber + 2 + + turbine + 1 + + + + 3 + 4 + 5 + + + + + + + + + + + G + + diff --git a/docs/_static/images/basics/gas_turbine_darkmode.svg b/docs/_static/images/basics/gas_turbine_darkmode.svg new file mode 100644 index 000000000..4c3bd9e4b --- /dev/null +++ b/docs/_static/images/basics/gas_turbine_darkmode.svg @@ -0,0 +1,350 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + compressor + combustion chamber + 2 + + turbine + 1 + + + + 3 + 4 + 5 + + + + + + + + + + + G + + From 3e42cd836e86cc20416b5ca3b2a37a75beeffc0f Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 20 Aug 2022 11:48:40 +0200 Subject: [PATCH 037/120] Add nice overview for tutorials --- docs/basics.rst | 80 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/docs/basics.rst b/docs/basics.rst index 6e5126552..c961b3bf8 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -1,16 +1,86 @@ Modeling Basic Systems ~~~~~~~~~~~~~~~~~~~~~~ -* :py:mod:`Components ` -* :py:mod:`Connections and Busses ` -* :py:mod:`Networks ` -* :py:mod:`Importing Networks ` +In this section we will introduce how to create your first simple TESPy models. +In the intro part you learn about the modeling concept of TESPy. The other +subsections are step by step walkthroughs for well-known thermodynamic +applications. + +If you want to learn more about the details of the different parts of the +software, you should also have a look at the +:ref:`Documentation section <>` after the first steps. If you have any +questions please reach out to the :ref:`TESPy community <>`. There are regular +online meetings as well as a discussion forum on github. .. toctree:: :maxdepth: 1 - :glob: + :hidden: + basics/intro.rst basics/heat_pump.rst basics/rankine_cycle.rst basics/gas_turbine.rst basics/district_heating.rst + + +.. card:: Introduction + :link: tespy_basics_intro_label + :link-type: ref + + Learn the basic modeling concept of TESPy + + +.. grid:: 1 1 2 2 + :gutter: 1 + + .. grid-item:: + :child-align: center + + .. grid:: 1 1 1 1 + :gutter: 1 + + .. grid-item-card:: Heat Pump + :link: tespy_basics_heat_pump_label + :link-type: ref + + .. image:: /_static/images/basics/heat_pump.svg + :class: only-light + + .. image:: /_static/images/basics/heat_pump_darkmode.svg + :class: only-dark + + .. grid-item-card:: Clausius Rankine Cycle + :link: tespy_basics_rankine_cycle_label + :link-type: ref + + .. image:: /_static/images/basics/rankine_cycle.svg + :class: only-light + + .. image:: /_static/images/basics/rankine_cycle_darkmode.svg + :class: only-dark + + .. grid-item:: + :child-align: center + + .. grid:: 1 1 1 1 + :gutter: 1 + + .. grid-item-card:: Gas Turbine + :link: tespy_basics_gas_turbine_label + :link-type: ref + + .. image:: /_static/images/basics/gas_turbine.svg + :class: only-light + + .. image:: /_static/images/basics/gas_turbine_darkmode.svg + :class: only-dark + + .. grid-item-card:: District Heating System + :link: tespy_basics_district_heating_label + :link-type: ref + + .. image:: /_static/images/basics/district_heating.svg + :class: only-light + + .. image:: /_static/images/basics/district_heating_darkmode.svg + :class: only-dark From dc76faacdd69758af32d74df714496a56e2b447e Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 20 Aug 2022 11:49:20 +0200 Subject: [PATCH 038/120] Add some labels to the basics pages --- docs/basics/district_heating.rst | 2 +- docs/basics/heat_pump.rst | 2 +- docs/basics/intro.rst | 2 ++ docs/basics/rankine_cycle.rst | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/basics/district_heating.rst b/docs/basics/district_heating.rst index 7d93a842b..128ff0fbd 100644 --- a/docs/basics/district_heating.rst +++ b/docs/basics/district_heating.rst @@ -1,4 +1,4 @@ -.. _tespy_basics_district_heating: +.. _tespy_basics_district_heating_label: District Heating Network ======================== diff --git a/docs/basics/heat_pump.rst b/docs/basics/heat_pump.rst index 4c6ee07c7..92719662a 100644 --- a/docs/basics/heat_pump.rst +++ b/docs/basics/heat_pump.rst @@ -1,4 +1,4 @@ -.. _tespy_basics_heat_pump: +.. _tespy_basics_heat_pump_label: Heat Pump ========= diff --git a/docs/basics/intro.rst b/docs/basics/intro.rst index f7d01412e..056db3779 100644 --- a/docs/basics/intro.rst +++ b/docs/basics/intro.rst @@ -1,3 +1,5 @@ +.. _tespy_basics_intro_label: + First steps =========== diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst index e76abc390..01eee8057 100644 --- a/docs/basics/rankine_cycle.rst +++ b/docs/basics/rankine_cycle.rst @@ -1,4 +1,4 @@ -.. _tespy_basics_rankine_cycle: +.. _tespy_basics_rankine_cycle_label: Rankine Cycle ============= From cde9ed65218573ea99de8b85ce0659333f9e1891 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 21 Aug 2022 11:32:30 +0200 Subject: [PATCH 039/120] Add missing sphinx dependency and fix grid layout --- docs/basics.rst | 72 +++++++++++++++++++------------------------ docs/requirements.txt | 2 +- 2 files changed, 32 insertions(+), 42 deletions(-) diff --git a/docs/basics.rst b/docs/basics.rst index c961b3bf8..7b33c5fee 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -29,58 +29,48 @@ online meetings as well as a discussion forum on github. Learn the basic modeling concept of TESPy - -.. grid:: 1 1 2 2 +.. grid:: 2 :gutter: 1 - .. grid-item:: - :child-align: center - - .. grid:: 1 1 1 1 - :gutter: 1 - - .. grid-item-card:: Heat Pump - :link: tespy_basics_heat_pump_label - :link-type: ref + .. grid-item-card:: Heat Pump + :link: tespy_basics_heat_pump_label + :link-type: ref - .. image:: /_static/images/basics/heat_pump.svg - :class: only-light + .. image:: /_static/images/basics/heat_pump.svg + :class: only-light - .. image:: /_static/images/basics/heat_pump_darkmode.svg - :class: only-dark + .. image:: /_static/images/basics/heat_pump_darkmode.svg + :class: only-dark - .. grid-item-card:: Clausius Rankine Cycle - :link: tespy_basics_rankine_cycle_label - :link-type: ref + .. grid-item-card:: Clausius Rankine Cycle + :link: tespy_basics_rankine_cycle_label + :link-type: ref - .. image:: /_static/images/basics/rankine_cycle.svg - :class: only-light + .. image:: /_static/images/basics/rankine_cycle.svg + :class: only-light - .. image:: /_static/images/basics/rankine_cycle_darkmode.svg - :class: only-dark + .. image:: /_static/images/basics/rankine_cycle_darkmode.svg + :class: only-dark - .. grid-item:: - :child-align: center - - .. grid:: 1 1 1 1 - :gutter: 1 +.. grid:: 2 + :gutter: 1 - .. grid-item-card:: Gas Turbine - :link: tespy_basics_gas_turbine_label - :link-type: ref + .. grid-item-card:: Gas Turbine + :link: tespy_basics_gas_turbine_label + :link-type: ref - .. image:: /_static/images/basics/gas_turbine.svg - :class: only-light + .. image:: /_static/images/basics/gas_turbine.svg + :class: only-light - .. image:: /_static/images/basics/gas_turbine_darkmode.svg - :class: only-dark + .. image:: /_static/images/basics/gas_turbine_darkmode.svg + :class: only-dark - .. grid-item-card:: District Heating System - :link: tespy_basics_district_heating_label - :link-type: ref + .. grid-item-card:: District Heating System + :link: tespy_basics_district_heating_label + :link-type: ref - .. image:: /_static/images/basics/district_heating.svg - :class: only-light + .. image:: /_static/images/basics/district_heating.svg + :class: only-light - .. image:: /_static/images/basics/district_heating_darkmode.svg - :class: only-dark + .. image:: /_static/images/basics/district_heating_darkmode.svg + :class: only-dark diff --git a/docs/requirements.txt b/docs/requirements.txt index 0e8ec6137..69d0a7e5f 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,4 +2,4 @@ furo sphinx>=1.3 sphinxcontrib-bibtex sphinx-copybutton -sphinx-inline-tabs +sphinx-design From de58f22c0e43e9b963210aa946812412e0607335 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 21 Aug 2022 11:49:07 +0200 Subject: [PATCH 040/120] Make referencing volumetric flow possible --- docs/whats_new/v0-6-1.rst | 3 +++ src/tespy/connections/connection.py | 8 ++++---- src/tespy/networks/network.py | 20 ++++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/docs/whats_new/v0-6-1.rst b/docs/whats_new/v0-6-1.rst index d4602506c..62197a349 100644 --- a/docs/whats_new/v0-6-1.rst +++ b/docs/whats_new/v0-6-1.rst @@ -13,6 +13,9 @@ New Features - Integration of an optimization suite using pygmo :cite:`Biscani2020` to apply a variety of state of the art optimization algorithms to your TESPy model (`PR #296 `_). +- Volumetric flow can be referenced using the + :py:class:`tespy.connections.connection.Ref` class + (`Discussion #352 `_). Documentation ############# diff --git a/src/tespy/connections/connection.py b/src/tespy/connections/connection.py index 5998dd47f..214efe025 100644 --- a/src/tespy/connections/connection.py +++ b/src/tespy/connections/connection.py @@ -443,11 +443,11 @@ def set_attr(self, **kwargs): # reference object elif isinstance(kwargs[key], Ref): - if key in ['x', 'v', 'Td_bp']: + if key in ['x', 'Td_bp']: msg = ( - 'References for volumetric flow, vapor mass ' - 'fraction and subcooling/superheating are not ' - 'implemented.') + 'References for vapor mass fraction and ' + 'subcooling/superheating are not implemented.' + ) logging.error(msg) raise NotImplementedError(msg) else: diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index a681c88b8..38022e44b 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -2381,6 +2381,26 @@ def solve_connections(self): fp.dv_mix_pdh(flow, T0=c.T.val_SI) * c.m.val_SI) k += 1 + # referenced volumetric flow + if c.v.ref_set: + ref = c.v.ref + flow_ref = ref.obj.get_flow() + ref_col = ref.obj.conn_loc * self.num_conn_vars + self.residual[k] = fp.v_mix_ph(flow, T0=c.T.val_SI) - ( + fp.v_mix_ph(flow_ref, T0=ref.obj.T.val_SI) * + ref.factor + ref.delta_SI) + + self.jacobian[k, col + 1] = ( + fp.dv_mix_dph(flow, T0=c.T.val_SI)) + self.jacobian[k, col + 2] = ( + fp.dv_mix_pdh(flow, T0=c.T.val_SI)) + + self.jacobian[k, ref_col + 1] = -( + fp.dv_mix_dph(flow_ref, T0=ref.obj.T.val_SI) * ref.factor) + self.jacobian[k, ref_col + 2] = -( + fp.dv_mix_pdh(flow_ref, T0=ref.obj.T.val_SI) * ref.factor) + k += 1 + # temperature difference to boiling point if c.Td_bp.val_set: if (np.absolute(self.residual[k]) > err ** 2 or From fab3f02793c31f4577bfce98cb25b92eafac5e4e Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 21 Aug 2022 12:24:29 +0200 Subject: [PATCH 041/120] Add unit test --- src/tespy/networks/network.py | 25 +++++++++---- tests/test_connections.py | 70 +++++++++++++++++++++++++++++++++++ tests/test_errors.py | 1 + 3 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 tests/test_connections.py diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index 38022e44b..3d638986b 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -2386,19 +2386,30 @@ def solve_connections(self): ref = c.v.ref flow_ref = ref.obj.get_flow() ref_col = ref.obj.conn_loc * self.num_conn_vars - self.residual[k] = fp.v_mix_ph(flow, T0=c.T.val_SI) - ( - fp.v_mix_ph(flow_ref, T0=ref.obj.T.val_SI) * - ref.factor + ref.delta_SI) + v = fp.v_mix_ph(flow, T0=c.T.val_SI) + v_ref = fp.v_mix_ph(flow_ref, T0=ref.obj.T.val_SI) + self.residual[k] = ( + (v * c.m.val_SI) + - ((v_ref * ref.obj.m.val_SI) * ref.factor + ref.delta_SI) + ) + self.jacobian[k, col] = v self.jacobian[k, col + 1] = ( - fp.dv_mix_dph(flow, T0=c.T.val_SI)) + fp.dv_mix_dph(flow, T0=c.T.val_SI) * c.m.val_SI + ) self.jacobian[k, col + 2] = ( - fp.dv_mix_pdh(flow, T0=c.T.val_SI)) + fp.dv_mix_pdh(flow, T0=c.T.val_SI) * c.m.val_SI + ) + self.jacobian[k, ref_col] = -v_ref * ref.factor self.jacobian[k, ref_col + 1] = -( - fp.dv_mix_dph(flow_ref, T0=ref.obj.T.val_SI) * ref.factor) + fp.dv_mix_dph(flow_ref, T0=ref.obj.T.val_SI) + * ref.factor * ref.obj.m.val_SI + ) self.jacobian[k, ref_col + 2] = -( - fp.dv_mix_pdh(flow_ref, T0=ref.obj.T.val_SI) * ref.factor) + fp.dv_mix_pdh(flow_ref, T0=ref.obj.T.val_SI) + * ref.factor * ref.obj.m.val_SI + ) k += 1 # temperature difference to boiling point diff --git a/tests/test_connections.py b/tests/test_connections.py new file mode 100644 index 000000000..6ed1181c3 --- /dev/null +++ b/tests/test_connections.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 + +"""Module for testing busses. + +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 +tests/test_busses.py + +SPDX-License-Identifier: MIT +""" +import shutil + +import numpy as np + +from tespy.components import Sink +from tespy.components import Source +from tespy.connections import Bus +from tespy.connections import Connection +from tespy.connections import Ref +from tespy.networks import Network + + +class TestConnections: + + def setup(self): + """Set up the model.""" + # %% network setup + fluid_list = ['Air'] + self.nw = Network( + fluids=fluid_list, p_unit='bar', T_unit='C', p_range=[0.5, 20]) + + # %% components + so1 = Source('source 1') + so2 = Source('source 2') + si1 = Sink('sink 1') + si2 = Sink('sink 2') + + # %% connections + c1 = Connection(so1, 'out1', si1, 'in1', label='Some example label') + c2 = Connection(so2, 'out1', si2, 'in1') + + self.nw.add_conns(c1, c2) + + # %% component parameters + c1.set_attr(m=1, p=1, T=25, fluid={'Air': 1}) + c2.set_attr(m=0.5, p=10, T=25, fluid={'Air': 1}) + + # %% solving + self.nw.solve('design') + + def test_volumetric_flow_reference(self): + """Test the referenced volumetric flow.""" + c1, c2 = self.nw.get_conn( + ['Some example label', 'source 2:out1_sink 2:in1'] + ) + c2.set_attr(m=None, v=Ref(c1, 1, 0)) + + self.nw.solve('design') + + # expected result: mass flow of second connection is lower by + # the fraction of the specific volumes + + m_expected = round(c1.m.val * c1.vol.val / c2.vol.val, 4) + m_is = round(c2.m.val, 4) + msg = ( + 'The mass flow of the connection 2 should be equal to ' + f'{m_expected} kg/s, but is {m_is} kg/s' + ) + assert m_is == m_expected, msg diff --git a/tests/test_errors.py b/tests/test_errors.py index f7fe16673..b5a9419f8 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -129,6 +129,7 @@ def test_set_attr_errors(): # NotImplementedError set_attr_NotImplementedError(conn, Td_bp=Ref(conn, 1, 0)) + set_attr_NotImplementedError(conn, x=Ref(conn, 1, 0)) def test_get_attr_errors(): From 07ff308cfca8af5206d6efa90f9d5340bbe2d6f7 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 21 Aug 2022 12:26:09 +0200 Subject: [PATCH 042/120] Remove starting value for mass flow --- src/tespy/components/combustion/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tespy/components/combustion/engine.py b/src/tespy/components/combustion/engine.py index 4050c6b6b..49e408bf5 100644 --- a/src/tespy/components/combustion/engine.py +++ b/src/tespy/components/combustion/engine.py @@ -215,7 +215,7 @@ class CombustionEngine(CombustionChamber): ... design=['pr1'], offdesign=['zeta1']) >>> amb_comb.set_attr(p=5, T=30, fluid={'Ar': 0.0129, 'N2': 0.7553, ... 'H2O': 0, 'CH4': 0, 'CO2': 0.0004, 'O2': 0.2314}) - >>> sf_comb.set_attr(m0=0.1, T=30, fluid={'CO2': 0, 'Ar': 0, 'N2': 0, + >>> sf_comb.set_attr(T=30, fluid={'CO2': 0, 'Ar': 0, 'N2': 0, ... 'O2': 0, 'H2O': 0, 'CH4': 1}) >>> cw_sp.set_attr(p=3, T=60, m=50, fluid={'CO2': 0, 'Ar': 0, 'N2': 0, ... 'O2': 0, 'H2O': 1, 'CH4': 0}) From b19ed96ad7470735490122a353011f3e563e19c5 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 21 Aug 2022 12:27:28 +0200 Subject: [PATCH 043/120] Remove unused imports --- tests/test_connections.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_connections.py b/tests/test_connections.py index 6ed1181c3..94a281298 100644 --- a/tests/test_connections.py +++ b/tests/test_connections.py @@ -9,13 +9,9 @@ SPDX-License-Identifier: MIT """ -import shutil - -import numpy as np from tespy.components import Sink from tespy.components import Source -from tespy.connections import Bus from tespy.connections import Connection from tespy.connections import Ref from tespy.networks import Network From 93cf9abe517117f8f6b79e43370b5f744c60f453 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 22 Aug 2022 21:05:23 +0200 Subject: [PATCH 044/120] More restructuring, darkmode images and some good stuff --- .../images/basics/modeling_concept.svg | 347 ++ .../tutorials/heat_pump_exergy/NH3_logph.svg | 5320 +++++++++++++++++ .../tutorials/heat_pump_exergy/flowsheet.svg | 929 +-- .../heat_pump_exergy/flowsheet_darkmode.svg | 577 ++ .../heat_pump_starting_values/COP_by_wf.svg | 2454 ++++---- .../heat_pump_starting_values/flowsheet.svg | 734 +-- .../flowsheet_darkmode.svg | 597 ++ .../heat_pump_stepwise/flowsheet.svg | 809 +++ .../heat_pump_stepwise/flowsheet_darkmode.svg | 811 +++ docs/api.rst | 35 +- docs/basics.rst | 7 +- docs/basics/gas_turbine.rst | 2 +- docs/basics/intro.rst | 195 +- docs/benchmarks.rst | 3 +- docs/contents.rst | 16 +- docs/modules.rst | 20 +- .../characteristics.rst | 0 .../{tespy_modules => modules}/components.rst | 0 .../connections.rst | 0 .../fluid_properties.rst | 0 docs/{tespy_modules => modules}/networks.rst | 0 .../{tespy_modules => modules}/subsystems.rst | 0 .../other.rst => modules/ude.rst} | 2 +- docs/regular_meeting.rst | 4 +- docs/tutorials.rst | 11 +- ...ion_chamber.rst => combustion_chamber.rst} | 0 ...t_pump_exergy.rst => heat_pump_exergy.rst} | 14 +- ...rial_heat_pump.rst => heat_pump_steps.rst} | 0 ...ptimization.rst => pygmo_optimization.rst} | 0 ...tarting_values.rst => starting_values.rst} | 316 +- 30 files changed, 10939 insertions(+), 2264 deletions(-) create mode 100644 docs/_static/images/basics/modeling_concept.svg create mode 100644 docs/_static/images/tutorials/heat_pump_exergy/NH3_logph.svg create mode 100644 docs/_static/images/tutorials/heat_pump_exergy/flowsheet_darkmode.svg create mode 100644 docs/_static/images/tutorials/heat_pump_starting_values/flowsheet_darkmode.svg create mode 100644 docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg create mode 100644 docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg rename docs/{tespy_modules => modules}/characteristics.rst (100%) rename docs/{tespy_modules => modules}/components.rst (100%) rename docs/{tespy_modules => modules}/connections.rst (100%) rename docs/{tespy_modules => modules}/fluid_properties.rst (100%) rename docs/{tespy_modules => modules}/networks.rst (100%) rename docs/{tespy_modules => modules}/subsystems.rst (100%) rename docs/{tespy_modules/other.rst => modules/ude.rst} (97%) rename docs/tutorials/{tutorial_combustion_chamber.rst => combustion_chamber.rst} (100%) rename docs/tutorials/{tutorial_heat_pump_exergy.rst => heat_pump_exergy.rst} (98%) rename docs/tutorials/{tutorial_heat_pump.rst => heat_pump_steps.rst} (100%) rename docs/tutorials/{tutorial_pygmo_optimization.rst => pygmo_optimization.rst} (100%) rename docs/tutorials/{tutorial_starting_values.rst => starting_values.rst} (62%) diff --git a/docs/_static/images/basics/modeling_concept.svg b/docs/_static/images/basics/modeling_concept.svg new file mode 100644 index 000000000..eccad3d3d --- /dev/null +++ b/docs/_static/images/basics/modeling_concept.svg @@ -0,0 +1,347 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + compressor + condenser + evaporator + expansion valve + 0 + 1 + 2 + 3 + 4 + + + + network + + diff --git a/docs/_static/images/tutorials/heat_pump_exergy/NH3_logph.svg b/docs/_static/images/tutorials/heat_pump_exergy/NH3_logph.svg new file mode 100644 index 000000000..8f92ce182 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_exergy/NH3_logph.svg @@ -0,0 +1,5320 @@ + + + + + + + + + 2021-08-20T14:47:53.897807 + image/svg+xml + + + Matplotlib v3.3.4, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg b/docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg index f4a7899c1..711b23938 100644 --- a/docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg +++ b/docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg @@ -1,504 +1,577 @@ + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="flowsheet.svg" + inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" + id="svg8" + version="1.1" + viewBox="0 0 201.93968 126.88142" + height="126.88142mm" + width="201.93967mm"> + + + + + + + + + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false"> - - - - - - - - - - - + originx="-37.992792" + originy="-38.118971" /> - - - - - - - - - - - - - - - - + id="metadata5"> image/svg+xml + - - + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-37.99277,-38.118978)"> + - - - + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 169.99999,144 v -8" + id="path984-0-9-9-9-7-0-1-5-0-8-4-7" /> - + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 167.99999,145.99999 2,-2 2,2 z" + id="path4652-12-9-60-5-4-2" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + - + + + + + + + cx="143.98833" + cy="57.596603" + transform="rotate(-1.0295798)" + rx="7.7354536" + ry="7.7354012" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> - - + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + + + - ground heatfeed flow + inkscape:connector-curvature="0" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 187.49997,72.5 v 15.00001 h 15.00002 V 72.5 Z" + id="path1057-2-7-1-9" + sodipodi:nodetypes="ccccc" /> + sodipodi:nodetypes="ccc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 152.49999,105.00001 h 42.49999 V 100" + id="path984-0-9-9-9-7-6-9" /> condenser + id="text1025-3-9-3" + y="45.887463" + x="130.48715" + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;" + xml:space="preserve">compressor expansion valve + id="text1025-3-9-3-3" + y="66.838829" + x="92.131836" + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;" + xml:space="preserve">condenser evaporator + id="text1025-3-9-3-7" + y="71.237137" + x="156.43851" + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;" + xml:space="preserve">evaporator + expansion valve cycle closer - + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-5" + x="158.42764" + y="101.79421" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">0 compressor + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1" + x="188.35771" + y="96.801445" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">1 ground heat return flow + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-0" + x="188.39629" + y="61.832798" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">2 heating systemfeed flow + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-0-5" + x="123.35771" + y="61.801449" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">3 heating systemreturn flow - + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-0-5-6" + x="123.44694" + y="101.80025" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">4 + - + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 93.999987,100 99.999983,94.000007 105.99998,100" + id="path4585-2-7" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" /> + + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 164,130 5.99999,-6 6,6" + id="path4585-2-7-1" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" /> + + - + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccc" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 169.99999,124 c -0.001,-0.70265 -7e-5,-8.50814 0,-17 -2,-1 -2,-3 0,-4 2.7e-4,-10.037691 -4.9e-4,-21.297569 0,-22.999996 l 17.50008,10e-6" + id="path984-0-9-9-9-7-6-8" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 202.49999,80.000004 c 1.66488,-0.0033 13.98639,-0.0022 17.5,-9.81e-4 V 144" + id="path984-0-9-9-9-7-6-4" /> + + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 99.999988,114 c -2e-6,-1.41227 -3e-6,-2.74322 0,-8" + id="path984-0-9-9-9-7-0-1-5-0-8-4-7-5" /> - + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 97.999988,115.99999 2,-2 2.000002,2 z" + id="path4652-12-9-60-5-4-2-4" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + consumer heating system - - - - + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-6" + x="171.78777" + y="141.80145" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">11 + 12 + 13 + 21 + 22 geothermal heat collector + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-6-3-6-1-2" + x="71.851677" + y="81.795418" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">23 + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 99.999987,94.000007 0,-9.50001 5.000003,-8e-6 m 0,-8.999987 H 69.999987 l 3e-6,16.764641" + id="path984-0-9-9-9-7" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 69.999982,107.73544 c -2e-6,1.41227 -3e-6,1.00779 0,6.26457" + id="path984-0-9-9-9-7-0-1-5-0-8-4-7-5-9" /> + ground heat feed flow + ground heatreturn flow + heating systemreturn flow diff --git a/docs/_static/images/tutorials/heat_pump_exergy/flowsheet_darkmode.svg b/docs/_static/images/tutorials/heat_pump_exergy/flowsheet_darkmode.svg new file mode 100644 index 000000000..aa5c66d4e --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_exergy/flowsheet_darkmode.svg @@ -0,0 +1,577 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + compressor + condenser + evaporator + expansion valve + 0 + 1 + 2 + 3 + 4 + + + + + + + + + + + + + + consumer + 11 + 12 + 13 + 21 + 22 + 23 + + + ground heat feed flow + ground heatreturn flow + heating systemreturn flow + + diff --git a/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg b/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg index 143865cc4..bc7f3b70f 100644 --- a/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg +++ b/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg @@ -1,1181 +1,1273 @@ - - - - - - - - 2022-08-14T11:47:38.613328 - image/svg+xml - - - Matplotlib v3.5.1, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + 2022-08-14T11:47:38.613328 + image/svg+xml + + + Matplotlib v3.5.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet.svg b/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet.svg index 476358ddb..639a27ff7 100644 --- a/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet.svg +++ b/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet.svg @@ -15,9 +15,9 @@ inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" version="1.1" - viewBox="0 0 156.89704 119.13103" - height="119.13103mm" - width="156.89703mm"> + viewBox="0 0 200.75479 118.13102" + height="118.13102mm" + width="200.75478mm"> + originx="-33.892303" + originy="-33.118976" /> @@ -111,332 +111,199 @@ id="layer1" inkscape:groupmode="layer" inkscape:label="Ebene 1" - transform="translate(-67.750036,-38.118978)"> + transform="translate(-33.892281,-33.118981)"> + + + + + + + + + + + + - - - - - - - - - - - + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> - - - - - - - - - - - - - - - - - - - - - - - - + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 162.5,72.500002 v 15.00001 h 15.00002 v -15.00001 z" + id="path1057-2-7-1-9" + sodipodi:nodetypes="ccccc" /> + compressor heat sink + style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;" + y="66.838829" + x="87.131836" + id="tspan1023-6-9-1-6" + sodipodi:role="line">condenser + evaporator expansion valve - heat source - - 0 + x="218.42764" + y="121.79422" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">0 1 + x="173.3577" + y="96.801453" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">1 2 + x="163.39629" + y="61.832802" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">2 3 + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">3 4 + x="123.44694" + y="101.80025" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">4 + + + + + + + + + + + + + + heat sink 5 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-6" + x="146.78777" + y="141.80145" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">11 6 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-7" + x="146.68529" + y="116.80144" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">12 11 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-3" + x="186.7106" + y="116.80144" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">13 12 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-6-3" + x="101.82877" + y="116.79543" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">20 13 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-6-3-6" + x="101.92885" + y="91.832802" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">21 20 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-6-3-6-1" + x="71.826355" + y="81.832802" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">22 21 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-6-3-6-1-2" + x="71.851677" + y="121.79543" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">23 + + + + + + + + 22 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-0-5-6-2" + x="183.37941" + y="86.758041" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">5 23 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-0-5-6-3" + x="218.3987" + y="86.791801" + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;">6
diff --git a/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet_darkmode.svg b/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet_darkmode.svg new file mode 100644 index 000000000..8870b207c --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet_darkmode.svg @@ -0,0 +1,597 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + compressor + condenser + evaporator + expansion valve + 0 + 1 + 2 + 3 + 4 + + + + + + + + + + + + + + heat sink + 11 + 12 + 13 + 20 + 21 + 22 + 23 + + + + + + + + + 5 + 6 + + diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg new file mode 100644 index 000000000..83c682881 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg @@ -0,0 +1,809 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + compressor 1 + condenser + evaporator + expansion valve + 1 + 6 + + + + + + + + consumer + 20 + 21 + 22 + + + 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 2 + 3 + 4 + 5 + 7 + 8 + 9 + 11 + 12 + 13 + 14 + 15 + superheater + compressor 2 + + diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg new file mode 100644 index 000000000..4074793b5 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg @@ -0,0 +1,811 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + compressor 1 + condenser + evaporator + expansion valve + 1 + 6 + + + + + + + + consumer + 20 + 21 + 22 + + + 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 2 + 3 + 4 + 5 + 7 + 8 + 9 + 11 + 12 + 13 + 14 + 15 + superheater + compressor 2 + + diff --git a/docs/api.rst b/docs/api.rst index 1c6e253b9..67abc834b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,16 +1,19 @@ -~~~~~~~~~~~~~~~~~ -API Documentation -~~~~~~~~~~~~~~~~~ - -All component and connection property equations derive from balance equations -for fluid composition, mass flow and energy in regarding thermal as well as -hydraulic state and thermodynamic fluid property equations respectively. -Standard literature is for example :cite:`Baehr2016,Epple2012,Bswirth2012` -(german) :cite:`Epple2017` (english). Equations and properties from other -sources are cited individually. - -.. toctree:: - :maxdepth: 1 - :glob: - - api/* +~~~~~~~~~~~~~~~~~ +API Documentation +~~~~~~~~~~~~~~~~~ + +All component and connection property equations derive from balance equations +for fluid composition, mass flow and energy in regarding thermal as well as +hydraulic state and thermodynamic fluid property equations respectively. +Standard literature is for example :cite:`Baehr2016,Epple2012,Bswirth2012` +(german) :cite:`Epple2017` (english). Equations and properties from other +sources are cited individually. + +.. toctree:: + :maxdepth: 1 + :glob: + :hidden: + + api/* + +TODO: NICE CARDS HERE AS WELL diff --git a/docs/basics.rst b/docs/basics.rst index 7b33c5fee..8bd6e0a21 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -8,9 +8,10 @@ applications. If you want to learn more about the details of the different parts of the software, you should also have a look at the -:ref:`Documentation section <>` after the first steps. If you have any -questions please reach out to the :ref:`TESPy community <>`. There are regular -online meetings as well as a discussion forum on github. +:ref:`Documentation section ` after the first steps. If +you have any questions please reach out to the +:ref:`TESPy community `. There are regular online +meetings as well as a discussion forum on GitHub. .. toctree:: :maxdepth: 1 diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst index c0ea8f727..457d9c022 100644 --- a/docs/basics/gas_turbine.rst +++ b/docs/basics/gas_turbine.rst @@ -1,4 +1,4 @@ -.. _tespy_basics_gas_turbine: +.. _tespy_basics_gas_turbine_label: Gas Turbine =========== diff --git a/docs/basics/intro.rst b/docs/basics/intro.rst index 056db3779..0363ad0a4 100644 --- a/docs/basics/intro.rst +++ b/docs/basics/intro.rst @@ -1,41 +1,40 @@ .. _tespy_basics_intro_label: -First steps -=========== +Introduction +============ -In this section we provide you with a very simple example as firsts steps in -using TESPy. The model used in this introduction is shown the figure. It -consists of a central heating plant and a consumer, represented by a heat -exchanger with a control valve. +In this section we provide you with the basics of the TESPy's modeling concept. +TESPy builds up on **components** that are connected using **connections** to +form a topological **network**. The figure below highlights these three core +components of the software at the example of a small heat pump. -.. figure:: /api/_images/intro_district_heating_scheme.svg +.. figure:: /_static/images/basics/modeling_concept.svg :align: center + :alt: TESPy's modeling concept - Figure: Topology of the simplest district heating system. + Figure: TESPy's modeling concept. Set up a plant -------------- -In order to simulate a plant we start by creating a network +In order to simulate a plant we start by creating the network (:py:class:`tespy.networks.network.Network`). The network is the main container for the model. You need to specify a list of the fluids you require for the calculation in your plant. For more information on the fluid properties go to -the :ref:`corresponding section ` in TESPy -modules. +the :ref:`corresponding section ` in the +documentation. .. code-block:: python from tespy.networks import Network - # create a network object with water as fluid - fluid_list = ['water'] + # create a network object with R134a as fluid + fluid_list = ['R134a'] my_plant = Network(fluids=fluid_list) On top of that, it is possible to specify a unit system and value ranges for the network's variables. If you do not specify these, TESPy will use SI-units. -The specification of the **value range** is used to **improve convergence** -**stability**, in case you are dealing with **fluid mixtures**, e.g. using -combustion. We will thus only specify the unit systems, in this case. +We will thus only specify the unit systems, in this case. .. code-block:: python @@ -48,17 +47,13 @@ Set up components ----------------- The list of components available can be found -:ref:`here `. If you set up a component you have -to specify a (within one network) unique label. Moreover, it is possible to -specify parameters for the component, for example power :math:`P` for a turbine +:ref:`here `. If you set up a component you +have to specify a (within one network) unique label. Moreover, it is possible +to specify parameters for the component, for example power :math:`P` for a pump or upper terminal temperature difference :math:`ttd_\mathrm{u}` of a heat exchanger. The full list of parameters for a specific component is stated in -the respective class documentation. The example uses pipes, a control valve and -a heat exchanger. The definition of the parameters available can be found here: - -- :py:class:`tespy.components.piping.pipe.Pipe` -- :py:class:`tespy.components.piping.valve.Valve` -- :py:class:`tespy.components.heat_exchangers.simple.HeatExchangerSimple` +the respective class documentation. This example uses a compressor, a control +valve two (simple) heat exchangers and a so called cycle closer. .. note:: @@ -66,38 +61,25 @@ a heat exchanger. The definition of the parameters available can be found here: label is mandatory. If an optional parameter is not specified by the user, it will be a result of the plant's simulation. This way, the set of equations a component returns is determined by which parameters you - specify. You can find all equations in the components documentation as + specify. You can find all equations in each component's documentation as well. .. code-block:: python from tespy.components import ( - Sink, Source, Pipe, Valve, HeatExchangerSimple) - - # sources & sinks (central heating plant) - so = Source('heat source output') - si = Sink('heat source input') - - # consumer - cons = HeatExchangerSimple('consumer') - cons.set_attr(Q=-10000, pr=0.98) # Q in W - val = Valve('valve') - val.set_attr(pr=1) # pr - pressure ratio (output/input pressure) - - # pipes - pipe_feed = Pipe('pipe_feed') - pipe_back = Pipe('pipe_back') - - pipe_feed.set_attr(ks=0.0005, # pipe's roughness in meters - L=100, # length in m - D=0.06, # diameter in m - kA=10, # area independent heat transfer coefficient kA in W/K - Tamb=10) # ambient temperature of the pipe environment (ground temperature) - pipe_back.set_attr(ks=0.0005, - L=100, - D=0.06, - kA=10, - Tamb=10) + CycleCloser, Compressor, Valve, HeatExchangerSimple + ) + + cc = CycleCloser('cycle closer') + + # heat sink + co = HeatExchangerSimple('condenser') + # heat source + ev = HeatExchangerSimple('evaporator') + + va = Valve('expansion valve') + cp = Compressor('compressor') + After creating the components the next step is to connect them in order to form your topological network. @@ -111,75 +93,110 @@ the fluid properties at the source will be equal to the properties at the target. It is possible to set the properties on each connection in a similar way as parameters are set for components. The basic specification options are: - * mass flow (m) - * volumetric flow (v) - * pressure (p) - * enthalpy (h) - * temperature (T) - * a fluid vector (fluid) +* mass flow (m) +* volumetric flow (v) +* pressure (p) +* enthalpy (h) +* temperature (T) +* a fluid vector (fluid) -.. note:: +.. seealso:: There are more specification options available. Please refer to - the :ref:`connections section ` in the TESPy - modules chapter for detailed information. The specification options are - stated in the - connection class documentation, too: + the :ref:`connections section ` in the + TESPy modules documentation for detailed information. The specification + options are stated in the connection class documentation, too: :py:class:`tespy.connections.connection.Connection`. After creating the connections, we need to add them to the network. As the connections hold the information, which components are connected in which way, we do not need to pass the components to the network. -The connection parameters specified in the example case, are inlet and outlet -temperature of the system as well as the inlet pressure. The pressure losses in -the pipes, the consumer and the control valve determine the pressure at all -other points of the network. The enthalpy is calculated from given temperature -and heat losses in the pipes. Additionally we have to specify the fluid vector -at one point in our network. - .. code-block:: python from tespy.connections import Connection # connections of the disctrict heating system - so_pif = Connection(so, 'out1', pipe_feed, 'in1') + c1 = Connection(cc, 'out1', ev, 'in1', label='1') + c2 = Connection(ev, 'out1', cp, 'in1', label='2') + c3 = Connection(cp, 'out1', co, 'in1', label='3') + c4 = Connection(co, 'out1', va, 'in1', label='4') + c0 = Connection(va, 'out1', cc, 'in1', label='0') - pif_cons = Connection(pipe_feed, 'out1', cons, 'in1') - cons_val = Connection(cons, 'out1', val, 'in1') + # this line is crutial: you have to add all connections to your network + my_plant.add_conns(c1, c2, c3, c4, c0) - val_pib = Connection(val, 'out1', pipe_back, 'in1') - pib_si = Connection(pipe_back, 'out1', si, 'in1') +.. note:: - # this line is crutial: you have to add all connections to your network - my_plant.add_conns(so_pif, pif_cons, cons_val, val_pib, pib_si) + The :code:`CycleCloser` is a necessary component when working with closed + cycles, because a system would always be overdetermined, if, for example, + a mass flow is specified at some point within the cycle. It would propagate + through all of the components, since they have an equality constraint for + the mass flow at their inlet and their outlet. With the example here, that + would mean: **Without the cycle closer** specification of massflow at an + connection would lead to the following set of equations for massflow, which + is an overdetermination: + + .. math:: + + \dot{m}_1 = \text{5 kg/s}\\ + \dot{m}_1 = \dot_{m}_2\\ + \dot{m}_2 = \dot_{m}_3\\ + \dot{m}_3 = \dot_{m}_4\\ + \dot{m}_4 = \dot_{m}_1 + + Similarly, this applies to the fluid composition. + + The cycle closer will prompt a warning, if the mass flow and fluid + composition are not equal at its inlet and outlet. + +We can set the component and connection parameters. In this example, we specify +the pressure losses (by outlet to inlet pressure ratio :code:`pr`) in the +condenser and the evaporator as well as the efficiency :code:`eta_s` of the +compressor. On top of that, the heat production of the heat pump can be set +with :code:`Q` for the condenser. Since we are working in **subcritical** +regime in this tutorial, we set the state of the fluid at the evaporator's +outlet to fully saturated steam (:code:`x=1`) and at the condenser's outlet to +fully saturated liqud (:code:`x=0`). On top of that, we want to impose the +condensation and the evaporation temperature levels. Last, we have to specify +the fluid vector at one point in our network. - so_pif.set_attr(T=90, p=15, fluid={'water': 1}) - cons_val.set_attr(T=60) +.. code-block:: python + + co.set_attr(pr=0.98, Q=-1e6) + ev.set_attr(pr=0.98) + cp.set_attr(eta_s=0.9) + + c2.set_attr(T=20, x=1, fluid={'R134a': 1}) + c4.set_attr(T=75, x=0) Start your calculation ---------------------- After building your network, the components and the connections, add the -following line at the end of your script and run it: +following line at the end of your script and run it. You can calculate the COP +with the respective component parameters. .. code-block:: python my_plant.solve(mode='design') my_plant.print_results() -We highly recommend to check our step-by-step -:ref:`tutorial ` on how to set up a heat pump (see -figure below) in TESPy. You will learn, how to set up and design a plant as -well as calculate offdesign/partload performance. + print(f'COP = {abs(co.Q.val) / cp.P.val}') -.. figure:: /api/_images/tutorial_heat_pump.svg - :align: center +Next steps +---------- - Figure: Topology of a heat pump +We highly recommend to check our other basic model examples on how to set up +different standard thermodynamic cycles in TESPy. The heat pump cycle in that +section builds on this heat pump. We will introduce couple of different inputs +and change the working fluid. The other tutorials show the usage of more +components, for example the combustion chamber and the turbine or a condenser +including the cooling water side of the system. -Additional examples are provided in the -:ref:`examples section `. +In the more advanced tutorials, you will learn, how to set up more complex +plants ste by step, make a design calculation of the plant as well as calculate +offdesign/partload performance. In order to get a good overview of the TESPy functionalities, the sections on the :ref:`TESPy modules ` will guide you in detail. diff --git a/docs/benchmarks.rst b/docs/benchmarks.rst index 40919da2f..c7a1fc79d 100644 --- a/docs/benchmarks.rst +++ b/docs/benchmarks.rst @@ -1,4 +1,5 @@ Benchmarks ========== - +TODO: REFERENCES TO PAPERS +TODO: UNIT TESTING STUFF diff --git a/docs/contents.rst b/docs/contents.rst index 051e7b477..14d771fb5 100644 --- a/docs/contents.rst +++ b/docs/contents.rst @@ -2,18 +2,16 @@ .. include:: introduction.rst - -Contents -======== - .. toctree:: :maxdepth: 2 + :hidden: introduction .. toctree:: :maxdepth: 2 :caption: User Guide + :hidden: installation basics @@ -24,6 +22,7 @@ Contents .. toctree:: :maxdepth: 2 :caption: Documentation + :hidden: modules benchmarks @@ -34,6 +33,7 @@ Contents .. toctree:: :maxdepth: 2 :caption: Advanced Features + :hidden: advanced/exergy advanced/optimization @@ -41,13 +41,7 @@ Contents .. toctree:: :maxdepth: 2 :caption: Contribute to TESPy + :hidden: development/what development/how - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/modules.rst b/docs/modules.rst index 4d5eb27df..f410df946 100644 --- a/docs/modules.rst +++ b/docs/modules.rst @@ -8,17 +8,17 @@ The following sections give a detailed overview on the modules of TESPy. This includes all important settings of networks, components and connections as well as the underlying functionalities of the software. -At the end of this page, we provide an example on how to couple energy system -simulation with TESPy. - .. toctree:: :maxdepth: 1 :glob: + :hidden: + + modules/networks.rst + modules/components.rst + modules/subsystems.rst + modules/connections.rst + modules/characteristics.rst + modules/fluid_properties.rst + modules/ude.rst - tespy_modules/networks.rst - tespy_modules/components.rst - tespy_modules/subsystems.rst - tespy_modules/connections.rst - tespy_modules/characteristics.rst - tespy_modules/fluid_properties.rst - tespy_modules/other.rst +TODO: INSERT SOME NICE CARDS HERE diff --git a/docs/tespy_modules/characteristics.rst b/docs/modules/characteristics.rst similarity index 100% rename from docs/tespy_modules/characteristics.rst rename to docs/modules/characteristics.rst diff --git a/docs/tespy_modules/components.rst b/docs/modules/components.rst similarity index 100% rename from docs/tespy_modules/components.rst rename to docs/modules/components.rst diff --git a/docs/tespy_modules/connections.rst b/docs/modules/connections.rst similarity index 100% rename from docs/tespy_modules/connections.rst rename to docs/modules/connections.rst diff --git a/docs/tespy_modules/fluid_properties.rst b/docs/modules/fluid_properties.rst similarity index 100% rename from docs/tespy_modules/fluid_properties.rst rename to docs/modules/fluid_properties.rst diff --git a/docs/tespy_modules/networks.rst b/docs/modules/networks.rst similarity index 100% rename from docs/tespy_modules/networks.rst rename to docs/modules/networks.rst diff --git a/docs/tespy_modules/subsystems.rst b/docs/modules/subsystems.rst similarity index 100% rename from docs/tespy_modules/subsystems.rst rename to docs/modules/subsystems.rst diff --git a/docs/tespy_modules/other.rst b/docs/modules/ude.rst similarity index 97% rename from docs/tespy_modules/other.rst rename to docs/modules/ude.rst index 459bee364..a9daf3beb 100644 --- a/docs/tespy_modules/other.rst +++ b/docs/modules/ude.rst @@ -1,4 +1,4 @@ -.. _tespy_other_label: +.. _tespy_ude_label: User defined equations ====================== diff --git a/docs/regular_meeting.rst b/docs/regular_meeting.rst index 8867f35e9..f616305ac 100644 --- a/docs/regular_meeting.rst +++ b/docs/regular_meeting.rst @@ -1,4 +1,4 @@ -.. _installation_and_setup_label: +.. _tespy_community_label: ############### TESPy community @@ -26,3 +26,5 @@ In-person meetings ================== Currently, no in-person meetings are scheduled. We will update this section, as soon as a meeting is planned. + +TODO: INSERT SCREENSHOT OF MEETING HERE diff --git a/docs/tutorials.rst b/docs/tutorials.rst index b5d3076d1..f6d2c9a05 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -19,9 +19,10 @@ with respect to the extraction pressure levels. .. toctree:: :maxdepth: 1 :glob: + :hidden: - tutorials/tutorial_heat_pump.rst - tutorials/tutorial_starting_values.rst - tutorials/tutorial_combustion_chamber.rst - tutorials/tutorial_pygmo_optimization.rst - tutorials/tutorial_heat_pump_exergy.rst + tutorials/heat_pump_steps.rst + tutorials/starting_values.rst + tutorials/combustion_chamber.rst + tutorials/pygmo_optimization.rst + tutorials/heat_pump_exergy.rst diff --git a/docs/tutorials/tutorial_combustion_chamber.rst b/docs/tutorials/combustion_chamber.rst similarity index 100% rename from docs/tutorials/tutorial_combustion_chamber.rst rename to docs/tutorials/combustion_chamber.rst diff --git a/docs/tutorials/tutorial_heat_pump_exergy.rst b/docs/tutorials/heat_pump_exergy.rst similarity index 98% rename from docs/tutorials/tutorial_heat_pump_exergy.rst rename to docs/tutorials/heat_pump_exergy.rst index d6667af60..204d99e8a 100644 --- a/docs/tutorials/tutorial_heat_pump_exergy.rst +++ b/docs/tutorials/heat_pump_exergy.rst @@ -48,6 +48,14 @@ compressor. .. figure:: /_static/images/tutorials/heat_pump_exergy/flowsheet.svg :align: center :alt: Topology of the Ground-Couped Heat Pump (GCHP) + :figclass: only-light + + Figure: Topology of the Ground-Couped Heat Pump (GCHP). + +.. figure:: /_static/images/tutorials/heat_pump_exergy/flowsheet_darkmode.svg + :align: center + :alt: Topology of the Ground-Couped Heat Pump (GCHP) + :figclass: only-dark Figure: Topology of the Ground-Couped Heat Pump (GCHP). @@ -104,8 +112,10 @@ The units used and the ambient state are defined as follows: .. code-block:: python - nw = Network(fluids=['water', 'NH3'], T_unit='C', p_unit='bar', - h_unit='kJ / kg', m_unit='kg / s') + nw = Network( + fluids=['water', 'NH3'], T_unit='C', p_unit='bar', + h_unit='kJ / kg', m_unit='kg / s' + ) pamb = 1.013 Tamb = 2.8 diff --git a/docs/tutorials/tutorial_heat_pump.rst b/docs/tutorials/heat_pump_steps.rst similarity index 100% rename from docs/tutorials/tutorial_heat_pump.rst rename to docs/tutorials/heat_pump_steps.rst diff --git a/docs/tutorials/tutorial_pygmo_optimization.rst b/docs/tutorials/pygmo_optimization.rst similarity index 100% rename from docs/tutorials/tutorial_pygmo_optimization.rst rename to docs/tutorials/pygmo_optimization.rst diff --git a/docs/tutorials/tutorial_starting_values.rst b/docs/tutorials/starting_values.rst similarity index 62% rename from docs/tutorials/tutorial_starting_values.rst rename to docs/tutorials/starting_values.rst index 6298fcf68..b7c4cea8b 100644 --- a/docs/tutorials/tutorial_starting_values.rst +++ b/docs/tutorials/starting_values.rst @@ -36,6 +36,15 @@ ambient. You can see the plant topology in the figure below. .. figure:: /_static/images/tutorials/heat_pump_starting_values/flowsheet.svg :align: center + :alt: Topology of heat pump with internal heat exchanger + :figclass: only-light + + Figure: Topology of heat pump with internal heat exchanger + +.. figure:: /_static/images/tutorials/heat_pump_starting_values/flowsheet_darkmode.svg + :align: center + :alt: Topology of heat pump with internal heat exchanger + :figclass: only-dark Figure: Topology of heat pump with internal heat exchanger @@ -303,185 +312,188 @@ Expand fix to any working fluids Finally, using this strategy, it is possible to build a generic function, building a network, that works with a variety of working fluids. -.. code-block:: python +.. dropdown:: Display source code of the full code - import matplotlib.pyplot as plt - import pandas as pd + .. code-block:: python - from tespy.networks import Network - from tespy.components import ( - Condenser, Compressor, CycleCloser, HeatExchanger, - HeatExchangerSimple, Pump, Sink, Source, Valve - ) - from tespy.connections import Connection, Ref, Bus - import CoolProp.CoolProp as CP + import matplotlib.pyplot as plt + import pandas as pd + from tespy.networks import Network + from tespy.components import ( + Condenser, Compressor, CycleCloser, HeatExchanger, + HeatExchangerSimple, Pump, Sink, Source, Valve + ) + from tespy.connections import Connection, Ref, Bus + import CoolProp.CoolProp as CP - def generate_starting_values(wf): - # network - nw = Network( - fluids=['water', wf], - T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s', - iterinfo=False - ) + def generate_starting_values(wf): - # components - cycle_closer = CycleCloser('Refrigerant Cycle Closer') - - # heat source - heatsource_feedflow = Source('Heat Source Feed Flow') - heatsource_pump = Pump('Heat Source Recirculation Pump') - heatsource_evaporator = HeatExchanger('Heat Source Evaporator') - heatsource_backflow = Sink('Heat Source Back Flow') - - # compression - compressor = Compressor('Compressor') - - # heat sink - cons_pump = Pump('Heat Sink Recirculation Pump') - condenser = Condenser('Heat Sink Condenser') - cons_heatsink = HeatExchangerSimple('Heat Consumer') - cons_cycle_closer = CycleCloser('Consumer Feed Flow') - - # internal heat exchange - int_heatex = HeatExchanger('Internal Heat Exchanger') - - # expansion - valve = Valve('Expansion Valve') - - # connections - # main cycle - cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0') - hs_eva2int_heatex = Connection(heatsource_evaporator, 'out2', int_heatex, 'in2', label='1') - int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='2') - comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='3') - cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='4') - int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='5') - valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='6') - - nw.add_conns( - cc2hs_eva, hs_eva2int_heatex, int_heatex2comp, comp2cond, cond2int_heatex, - int_heatex2valve, valve2cc + # network + nw = Network( + fluids=['water', wf], + T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s', + iterinfo=False ) - # heat source - hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='11') - hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='12') - hs_eva2hs_back = Connection(heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='13') - - nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back) - - # heat sink - cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='20') - cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='21') - cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='22') - cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='23') - - nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed) - - # set feedflow and backflow temperature of heat source and consumer - T_hs_bf = 10 - T_hs_ff = 15 - T_cons_bf = 50 - T_cons_ff = 90 - - # consumer cycle - cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, wf: 0}) - cons_hs2cons_feed.set_attr(T=T_cons_bf) - - # heat source cycle - hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, wf: 0}) - hs_eva2hs_back.set_attr(T=T_hs_bf, p=1) - - # evaporation to fully saturated gas - hs_eva2int_heatex.set_attr(x=1, fluid={'water': 0, wf: 1}) - - # parametrization components - # isentropic efficiency - cons_pump.set_attr(eta_s=0.8) - heatsource_pump.set_attr(eta_s=0.8) - compressor.set_attr(eta_s=0.85) - - # pressure ratios - condenser.set_attr(pr1=0.98, pr2=0.98) - heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98) - cons_heatsink.set_attr(pr=0.99) - int_heatex.set_attr(pr1=0.98, pr2=0.98) - - # evaporation point - p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-5 - hs_eva2int_heatex.set_attr(p=p_eva) - - # condensation point - p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273.15, wf) * 1e-5 - cond2int_heatex.set_attr(p=p_cond) - - # internal heat exchanger to compressor enthalpy - h_evap = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-3 - int_heatex2comp.set_attr(h=h_evap * 1.01) - - # consumer heat demand - cons_heatsink.set_attr(Q=-1e6) - - power_bus = Bus('Total power input') - heat_bus = Bus('Total heat production') - power_bus.add_comps( - {'comp': compressor, 'base': 'bus'}, - {'comp': cons_pump, 'base': 'bus'}, - {'comp': heatsource_pump, 'base': 'bus'}, - ) - heat_bus.add_comps({'comp': cons_heatsink}) + # components + cycle_closer = CycleCloser('Refrigerant Cycle Closer') + + # heat source + heatsource_feedflow = Source('Heat Source Feed Flow') + heatsource_pump = Pump('Heat Source Recirculation Pump') + heatsource_evaporator = HeatExchanger('Heat Source Evaporator') + heatsource_backflow = Sink('Heat Source Back Flow') + + # compression + compressor = Compressor('Compressor') + + # heat sink + cons_pump = Pump('Heat Sink Recirculation Pump') + condenser = Condenser('Heat Sink Condenser') + cons_heatsink = HeatExchangerSimple('Heat Consumer') + cons_cycle_closer = CycleCloser('Consumer Feed Flow') + + # internal heat exchange + int_heatex = HeatExchanger('Internal Heat Exchanger') + + # expansion + valve = Valve('Expansion Valve') + + # connections + # main cycle + cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0') + hs_eva2int_heatex = Connection(heatsource_evaporator, 'out2', int_heatex, 'in2', label='1') + int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='2') + comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='3') + cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='4') + int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='5') + valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='6') + + nw.add_conns( + cc2hs_eva, hs_eva2int_heatex, int_heatex2comp, comp2cond, cond2int_heatex, + int_heatex2valve, valve2cc + ) + + # heat source + hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='11') + hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='12') + hs_eva2hs_back = Connection(heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='13') + + nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back) + + # heat sink + cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='20') + cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='21') + cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='22') + cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='23') + + nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed) + + # set feedflow and backflow temperature of heat source and consumer + T_hs_bf = 10 + T_hs_ff = 15 + T_cons_bf = 50 + T_cons_ff = 90 + + # consumer cycle + cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, wf: 0}) + cons_hs2cons_feed.set_attr(T=T_cons_bf) + + # heat source cycle + hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, wf: 0}) + hs_eva2hs_back.set_attr(T=T_hs_bf, p=1) + + # evaporation to fully saturated gas + hs_eva2int_heatex.set_attr(x=1, fluid={'water': 0, wf: 1}) + + # parametrization components + # isentropic efficiency + cons_pump.set_attr(eta_s=0.8) + heatsource_pump.set_attr(eta_s=0.8) + compressor.set_attr(eta_s=0.85) + + # pressure ratios + condenser.set_attr(pr1=0.98, pr2=0.98) + heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98) + cons_heatsink.set_attr(pr=0.99) + int_heatex.set_attr(pr1=0.98, pr2=0.98) + + # evaporation point + p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-5 + hs_eva2int_heatex.set_attr(p=p_eva) + + # condensation point + p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273.15, wf) * 1e-5 + cond2int_heatex.set_attr(p=p_cond) + + # internal heat exchanger to compressor enthalpy + h_evap = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-3 + int_heatex2comp.set_attr(h=h_evap * 1.01) + + # consumer heat demand + cons_heatsink.set_attr(Q=-1e6) + + power_bus = Bus('Total power input') + heat_bus = Bus('Total heat production') + power_bus.add_comps( + {'comp': compressor, 'base': 'bus'}, + {'comp': cons_pump, 'base': 'bus'}, + {'comp': heatsource_pump, 'base': 'bus'}, + ) + heat_bus.add_comps({'comp': cons_heatsink}) - nw.add_busses(power_bus, heat_bus) + nw.add_busses(power_bus, heat_bus) - nw.solve('design') + nw.solve('design') - # evaporation point - hs_eva2int_heatex.set_attr(p=None) - heatsource_evaporator.set_attr(ttd_l=5) + # evaporation point + hs_eva2int_heatex.set_attr(p=None) + heatsource_evaporator.set_attr(ttd_l=5) - # condensation point - cond2int_heatex.set_attr(p=None) - condenser.set_attr(ttd_u=5) + # condensation point + cond2int_heatex.set_attr(p=None) + condenser.set_attr(ttd_u=5) - # internal heat exchanger superheating - int_heatex2comp.set_attr(Td_bp=5, h=None) + # internal heat exchanger superheating + int_heatex2comp.set_attr(Td_bp=5, h=None) - # solve the network again - nw.solve('design') + # solve the network again + nw.solve('design') - return nw + return nw - cop = pd.DataFrame(columns=["COP"]) + cop = pd.DataFrame(columns=["COP"]) - for wf in ['NH3', 'R22', 'R134a', 'R152a', 'R290', 'R718']: - nw = generate_starting_values(wf) + for wf in ['NH3', 'R22', 'R134a', 'R152a', 'R290', 'R718']: + nw = generate_starting_values(wf) - power = nw.busses['Total power input'].P.val - heat = abs(nw.busses['Total heat production'].P.val) - cop.loc[wf] = heat / power + power = nw.busses['Total power input'].P.val + heat = abs(nw.busses['Total heat production'].P.val) + cop.loc[wf] = heat / power - fig, ax = plt.subplots(1) + fig, ax = plt.subplots(1) - cop.plot.bar(ax=ax, legend=False) + cop.plot.bar(ax=ax, legend=False) - ax.set_axisbelow(True) - ax.yaxis.grid(linestyle='dashed') - ax.set_xlabel('Name of working fluid') - ax.set_ylabel('Coefficicent of performance') - ax.set_title('Coefficicent of performance for different working fluids') - plt.tight_layout() + ax.set_axisbelow(True) + ax.yaxis.grid(linestyle='dashed') + ax.set_xlabel('Name of working fluid') + ax.set_ylabel('Coefficicent of performance') + ax.set_title('Coefficicent of performance for different working fluids') + plt.tight_layout() - fig.savefig('COP_by_wf.svg') + fig.savefig('COP_by_wf.svg') -.. figure:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg - :align: center + .. figure:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg + :align: center + :alit: Analysis of the COP using different working fluids - Figure: Topology of heat pump with internal heat exchanger + Figure: Analysis of the COP using different working fluids Of course, there are different strategies, which include building the plant step by step and successively adding more and more components. From 792438d3bceba77b5e34a5dc305113f9c1fe296a Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 22 Aug 2022 21:16:52 +0200 Subject: [PATCH 045/120] Fix equations, add modules cards layout --- docs/basics/intro.rst | 8 +++---- docs/modules.rst | 55 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/docs/basics/intro.rst b/docs/basics/intro.rst index 0363ad0a4..52aa4e0f3 100644 --- a/docs/basics/intro.rst +++ b/docs/basics/intro.rst @@ -140,10 +140,10 @@ we do not need to pass the components to the network. .. math:: \dot{m}_1 = \text{5 kg/s}\\ - \dot{m}_1 = \dot_{m}_2\\ - \dot{m}_2 = \dot_{m}_3\\ - \dot{m}_3 = \dot_{m}_4\\ - \dot{m}_4 = \dot_{m}_1 + \dot{m}_1 = \dot{m}_2\\ + \dot{m}_2 = \dot{m}_3\\ + \dot{m}_3 = \dot{m}_4\\ + \dot{m}_4 = \dot{m}_1 Similarly, this applies to the fluid composition. diff --git a/docs/modules.rst b/docs/modules.rst index f410df946..b547c24e5 100644 --- a/docs/modules.rst +++ b/docs/modules.rst @@ -21,4 +21,57 @@ as the underlying functionalities of the software. modules/fluid_properties.rst modules/ude.rst -TODO: INSERT SOME NICE CARDS HERE + +.. grid:: 2 + :gutter: 1 + + .. grid-item-card:: Network + :link: tespy_modules_networks_label + :link-type: ref + + .. image:: /_static/images/basics/modeling_concept.svg + + .. grid-item-card:: Components and Component Groups + :link: tespy_modules_components_label + :link-type: ref + + .. image:: /_static/images/modules/components.svg + :class: only-light + + .. image:: /_static/images/modules/components_darkmode.svg + :class: only-dark + +.. grid:: 2 + :gutter: 1 + + .. grid-item-card:: Connections + :link: tespy_modules_connections_label + :link-type: ref + + TODO: IMAGE + + .. grid-item-card:: Characteristics + :link: tespy_modules_characteristics_label + :link-type: ref + + .. image:: /_static/images/modules/characteristics.svg + + +.. grid:: 2 + :gutter: 1 + + .. grid-item-card:: Fluid Properties + :link: tespy_fluid_properties_label + :link-type: ref + + .. image:: /_static/images/modules/fluid_properties.svg + + .. grid-item-card:: User Defined Equations + :link: tespy_ude_label + :link-type: ref + + .. image:: /_static/images/modules/fluid_properties.svg + :class: only-light + + .. image:: /_static/images/modules/fluid_properties_darkmode.svg + :class: only-dark From f03d98311ad290127ec5441effd6f92469dd2e84 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 22 Aug 2022 21:18:46 +0200 Subject: [PATCH 046/120] Polish equation a litte bit --- docs/basics/intro.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/basics/intro.rst b/docs/basics/intro.rst index 52aa4e0f3..530d883f5 100644 --- a/docs/basics/intro.rst +++ b/docs/basics/intro.rst @@ -139,11 +139,13 @@ we do not need to pass the components to the network. .. math:: - \dot{m}_1 = \text{5 kg/s}\\ - \dot{m}_1 = \dot{m}_2\\ - \dot{m}_2 = \dot{m}_3\\ - \dot{m}_3 = \dot{m}_4\\ - \dot{m}_4 = \dot{m}_1 + \begin{split} + \dot{m}_1 = &\;\text{5 kg/s}\\ + \dot{m}_1 = &\;\dot{m}_2\\ + \dot{m}_2 = &\;\dot{m}_3\\ + \dot{m}_3 = &\;\dot{m}_4\\ + \dot{m}_4 = &\;\dot{m}_1\\ + \end{split} Similarly, this applies to the fluid composition. From e1381b9ada981241f2ffc74800d51fe8f7cd22b2 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 24 Aug 2022 17:09:40 +0200 Subject: [PATCH 047/120] Finalize basic heat pump tutorial --- docs/_static/images/basics/COP_parametric.svg | 2029 +++++++++++++++++ docs/basics/heat_pump.rst | 199 ++ docs/basics/intro.rst | 10 +- 3 files changed, 2233 insertions(+), 5 deletions(-) create mode 100644 docs/_static/images/basics/COP_parametric.svg diff --git a/docs/_static/images/basics/COP_parametric.svg b/docs/_static/images/basics/COP_parametric.svg new file mode 100644 index 000000000..ecf808191 --- /dev/null +++ b/docs/_static/images/basics/COP_parametric.svg @@ -0,0 +1,2029 @@ + + + + + + + + 2022-08-24T17:08:18.698999 + image/svg+xml + + + Matplotlib v3.5.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/basics/heat_pump.rst b/docs/basics/heat_pump.rst index 92719662a..ca71283aa 100644 --- a/docs/basics/heat_pump.rst +++ b/docs/basics/heat_pump.rst @@ -16,3 +16,202 @@ Heat Pump :figclass: only-dark Figure: Topology of the heat pump + +This tutorial is the continuation of the tutorial in the +:ref:`introduction `. First, we have a look at +specification options and modeling flexibility in TESPy as well as some +typical errors, that might occur when using the software. Then we will make a +simple analysis of the COP of the heat pump based on several input parameters. + +Flexibility in Modeling +^^^^^^^^^^^^^^^^^^^^^^^ +In TESPy the specifications for components and/or connections are +interchangable in every possible way, provided that the system of equations +representing the plant is well defined. + +For example, instead of the heat provided by the condenser we could specify +the mass flow :code:`m` of the refrigerant. To unset a parameter you need to +set it to :code:`None`. To replace the specification, set the mass flow of +connection c1 to 5 kg/s: + +.. code-block:: python + + co.set_attr(Q=None) + c1.set_attr(m=5) + + my_plant.solve('design') + my_plant.print_results() + +You can observe, that the heat transferred by the condenser now is a result of +the mass flow imposed. We could do similar things, for example with the heat +sink temperature. We imposed it in our initial set up. Now we want to insert +a compressor with a fixed output to input pressure ratio. In that case, we +cannot choose the condensation temperature but it will be a result of that +specification: + +.. code-block:: python + + cp.set_attr(pr=4) + c4.set_attr(T=None) + + my_plant.solve('design') + my_plant.print_results() + +Or, we have a plant running with data observation running. It tells us the +compressor outlet temperature and we want to know what the efficiency of the +compressor would be, in case we measure :code:`T=97.3` at connection 3. + +.. code-block:: python + + cp.set_attr(pr=None, eta_s=None) + c3.set_attr(T=97.3) + c4.set_attr(T=80) + + my_plant.solve('design') + my_plant.print_results() + +Typical Errors +^^^^^^^^^^^^^^ +If you over- or underdetermine the system by specifying too few or too many +parameters, you will get an error message. We could set the heat demand and the +mass flow at the same time. + +.. code-block:: python + + co.set_attr(Q=-1e6) + c1.set_attr(m=5) + + my_plant.solve('design') + +.. error:: + + .. code-block:: bash + + ERROR:root:You have provided too many parameters: 20 required, 21 supplied. Aborting calculation! + Traceback (most recent call last): + File ".\tutorial\basics\heat_pump.py", line 59, in + my_plant.solve('design') + File "c:\users\user\documents\github\tespy\src\tespy\networks\network.py", line 1623, in solve + self.solve_determination() + File "c:\users\user\documents\github\tespy\src\tespy\networks\network.py", line 1749, in solve_determination + raise hlp.TESPyNetworkError(msg) + tespy.tools.helpers.TESPyNetworkError: You have provided too many parameters: 20 required, 21 supplied. Aborting calculation! + +If you make a specification that leads to the correct amount of parameters but +causes a linear dependency in the system of equations, the error message cannot +be that clear to you. To make an easy example, we can set mass flow on the +connections 1 and 2 with the heat demand and the evaporation temperature unset. +In this case the number of equations will be correct, but the specification +obviously does not make any sense. + +.. code-block:: python + + co.set_attr(Q=None) + c1.set_attr(m=5) + c2.set_attr(m=5, T=None) + + my_plant.solve('design') + +.. error:: + + .. code-block:: bash + + ERROR:root:Singularity in jacobian matrix, calculation aborted! Make sure your network does not have any linear dependencies in the parametrisation. Other reasons might be + -> given temperature with given pressure in two phase region, try setting enthalpy instead or provide accurate starting value for pressure. + -> given logarithmic temperature differences or kA-values for heat exchangers, + -> support better starting values. + -> bad starting value for fuel mass flow of combustion chamber, provide small (near to zero, but not zero) starting value. + +.. seealso:: + + For more detailed information about the number of variables involved and + ways of parameter specifications, please go to the + :ref:`TESPy modules section ` inside the Documentation + chapter. + + Another frequent reason for such errors are bad starting values. We have a + tutorial specifically dedicated to this topic + :ref:`here `. + +Parametric Analysis of COP +^^^^^^^^^^^^^^^^^^^^^^^^^^ +For a constant amount of heat production, we will investigate the influence of + +* the source temperature level +* the sink temperature level and +* the isentropic efficiency of the compressor. + +To do this, we import the numpy and matplotlib package and define the ranges +and then iterate over a loop and restart the simulation for every input +parameter. After each loop, we set the respective parameter back to its +original value. We collect the results in lists and can finally make a scatter +plot using matplotlib. + +.. dropdown:: Click to expand to code section + + .. code-block:: python + + import matplotlib.pyplot as plt + import numpy as np + + + data = { + 'T_source': np.linspace(0, 40, 11), + 'T_sink': np.linspace(60, 100, 11), + 'eta_s': np.linspace(0.75, 0.95, 11) * 100 + } + COP = { + 'T_source': [], + 'T_sink': [], + 'eta_s': [] + } + description = { + 'T_source': 'Evaporation temperature in °C', + 'T_sink': 'Condensation temperature in °C', + 'eta_s': 'Isentropic efficiency in %' + } + + for T in data['T_source']: + c2.set_attr(T=T) + my_plant.solve('design') + COP['T_source'] += [abs(co.Q.val) / cp.P.val] + + # reset to base temperature + c2.set_attr(T=20) + + for T in data['T_sink']: + c4.set_attr(T=T) + my_plant.solve('design') + COP['T_sink'] += [abs(co.Q.val) / cp.P.val] + + # reset to base temperature + c4.set_attr(T=80) + + for eta_s in data['eta_s']: + cp.set_attr(eta_s=eta_s / 100) + my_plant.solve('design') + COP['eta_s'] += [abs(co.Q.val) / cp.P.val] + + fig, ax = plt.subplots(1, 3, sharey=True, figsize=(16, 8)) + + [a.grid() for a in ax] + + i = 0 + for key in data: + ax[i].scatter(data[key], COP[key]) + ax[i].set_xlabel(description[key]) + i += 1 + + ax[0].set_ylabel('COP of the heat pump') + plt.tight_layout() + fig.savefig('COP_parametric.svg') + +.. figure:: /_static/images/basics/COP_parametric.svg + :align: center + :alt: Parametric analysis of the COP + + Figure: Parametric analysis of the COP + +The figure shows the results of the COP analysis. The base case is at an +evaporation temperature of 20 °C, the condensation temperature at 80 °C and the +isentropic effficiency of the compressor at 85 %. diff --git a/docs/basics/intro.rst b/docs/basics/intro.rst index 530d883f5..4d0b389ca 100644 --- a/docs/basics/intro.rst +++ b/docs/basics/intro.rst @@ -116,7 +116,7 @@ we do not need to pass the components to the network. from tespy.connections import Connection - # connections of the disctrict heating system + # connections of the network c1 = Connection(cc, 'out1', ev, 'in1', label='1') c2 = Connection(ev, 'out1', cp, 'in1', label='2') c3 = Connection(cp, 'out1', co, 'in1', label='3') @@ -167,7 +167,7 @@ the fluid vector at one point in our network. co.set_attr(pr=0.98, Q=-1e6) ev.set_attr(pr=0.98) - cp.set_attr(eta_s=0.9) + cp.set_attr(eta_s=0.85) c2.set_attr(T=20, x=1, fluid={'R134a': 1}) c4.set_attr(T=75, x=0) @@ -192,9 +192,9 @@ Next steps We highly recommend to check our other basic model examples on how to set up different standard thermodynamic cycles in TESPy. The heat pump cycle in that section builds on this heat pump. We will introduce couple of different inputs -and change the working fluid. The other tutorials show the usage of more -components, for example the combustion chamber and the turbine or a condenser -including the cooling water side of the system. +and show, how to change the working fluid. The other tutorials show the usage +of more components, for example the combustion chamber and the turbine or a +condenser including the cooling water side of the system. In the more advanced tutorials, you will learn, how to set up more complex plants ste by step, make a design calculation of the plant as well as calculate From 8975a1500b850f964f4acb29737e4d8fc3ca0f40 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 24 Aug 2022 17:12:46 +0200 Subject: [PATCH 048/120] Fix basics flowsheets --- .../images/basics/district_heating.svg | 2 +- .../basics/district_heating_darkmode.svg | 2 +- docs/_static/images/basics/gas_turbine.svg | 2 +- .../images/basics/gas_turbine_darkmode.svg | 2 +- docs/_static/images/basics/heat_pump.svg | 2 +- .../images/basics/heat_pump_darkmode.svg | 2 +- .../images/basics/modeling_concept.svg | 2 +- docs/_static/images/basics/rankine_cycle.svg | 97 +++++++--- .../images/basics/rankine_cycle_darkmode.svg | 167 +++++++++++------- 9 files changed, 180 insertions(+), 98 deletions(-) diff --git a/docs/_static/images/basics/district_heating.svg b/docs/_static/images/basics/district_heating.svg index a146466b1..a44f4990f 100644 --- a/docs/_static/images/basics/district_heating.svg +++ b/docs/_static/images/basics/district_heating.svg @@ -10,7 +10,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="district_heating.svg" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" diff --git a/docs/_static/images/basics/district_heating_darkmode.svg b/docs/_static/images/basics/district_heating_darkmode.svg index bd92000b6..9e2723d3a 100644 --- a/docs/_static/images/basics/district_heating_darkmode.svg +++ b/docs/_static/images/basics/district_heating_darkmode.svg @@ -10,7 +10,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="district_heating_darkmode.svg" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" diff --git a/docs/_static/images/basics/gas_turbine.svg b/docs/_static/images/basics/gas_turbine.svg index 0b15ac120..bd77f6d39 100644 --- a/docs/_static/images/basics/gas_turbine.svg +++ b/docs/_static/images/basics/gas_turbine.svg @@ -10,7 +10,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="gas_turbine.svg" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" diff --git a/docs/_static/images/basics/gas_turbine_darkmode.svg b/docs/_static/images/basics/gas_turbine_darkmode.svg index 4c3bd9e4b..571b4fd31 100644 --- a/docs/_static/images/basics/gas_turbine_darkmode.svg +++ b/docs/_static/images/basics/gas_turbine_darkmode.svg @@ -10,7 +10,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="gas_turbine_darkmode.svg" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" diff --git a/docs/_static/images/basics/heat_pump.svg b/docs/_static/images/basics/heat_pump.svg index b6def10e5..ba842e5c8 100644 --- a/docs/_static/images/basics/heat_pump.svg +++ b/docs/_static/images/basics/heat_pump.svg @@ -2,7 +2,7 @@ + viewBox="0 0 128.31751 89.606073" + height="89.606071mm" + width="128.3175mm"> + originx="-77.932497" + originy="-37.750037" /> @@ -104,6 +104,7 @@ image/svg+xml + @@ -111,7 +112,7 @@ id="layer1" inkscape:groupmode="layer" inkscape:label="Ebene 1" - transform="translate(-77.939712,-37.750038)"> + transform="translate(-77.932477,-37.750038)"> feed pump condenser 4 + + + 11 + 12 diff --git a/docs/_static/images/basics/rankine_cycle_darkmode.svg b/docs/_static/images/basics/rankine_cycle_darkmode.svg index e1e189230..c55c590cd 100644 --- a/docs/_static/images/basics/rankine_cycle_darkmode.svg +++ b/docs/_static/images/basics/rankine_cycle_darkmode.svg @@ -1,23 +1,23 @@ + viewBox="0 0 128.31751 89.606073" + height="89.606071mm" + width="128.3175mm"> + originx="-77.932497" + originy="-37.750037" /> @@ -104,6 +104,7 @@ image/svg+xml + @@ -111,28 +112,28 @@ id="layer1" inkscape:groupmode="layer" inkscape:label="Ebene 1" - transform="translate(-77.939712,-37.750038)"> + transform="translate(-77.932477,-37.750038)"> + style="stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> @@ -140,29 +141,29 @@ + style="stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> feed pump condenser steamturbine 0 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">0 1 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">1 2 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">2 3 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">3 4 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">4 + + + 11 + 12 From adbe4a7b8c9e9f2033585d28a0846e769117e63d Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 24 Aug 2022 17:13:14 +0200 Subject: [PATCH 049/120] Update tutorials flow sheets --- docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg | 2 +- .../images/tutorials/heat_pump_exergy/flowsheet_darkmode.svg | 2 +- .../images/tutorials/heat_pump_starting_values/flowsheet.svg | 2 +- .../tutorials/heat_pump_starting_values/flowsheet_darkmode.svg | 2 +- docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg | 2 +- .../images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg b/docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg index 711b23938..dd24cfe56 100644 --- a/docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg +++ b/docs/_static/images/tutorials/heat_pump_exergy/flowsheet.svg @@ -10,7 +10,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="flowsheet.svg" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" diff --git a/docs/_static/images/tutorials/heat_pump_exergy/flowsheet_darkmode.svg b/docs/_static/images/tutorials/heat_pump_exergy/flowsheet_darkmode.svg index aa5c66d4e..f48d9a9b6 100644 --- a/docs/_static/images/tutorials/heat_pump_exergy/flowsheet_darkmode.svg +++ b/docs/_static/images/tutorials/heat_pump_exergy/flowsheet_darkmode.svg @@ -10,7 +10,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="flowsheet_darkmode.svg" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" diff --git a/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet.svg b/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet.svg index 639a27ff7..88b0d0525 100644 --- a/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet.svg +++ b/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet.svg @@ -10,7 +10,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="flowsheet.svg" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" diff --git a/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet_darkmode.svg b/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet_darkmode.svg index 8870b207c..adfef5665 100644 --- a/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet_darkmode.svg +++ b/docs/_static/images/tutorials/heat_pump_starting_values/flowsheet_darkmode.svg @@ -10,7 +10,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="flowsheet_darkmode.svg" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg index 83c682881..77a664358 100644 --- a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg @@ -10,7 +10,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="flowsheet.svg" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg index 4074793b5..f0bf94073 100644 --- a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg @@ -10,7 +10,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\witt_fa\Documents\GitHub\tespy_fiddle\chp_orc\flowsheet.png" + sodipodi:docname="flowsheet.svg" inkscape:version="1.0.2-2 (e86c870879, 2021-01-15)" id="svg8" From 30d761b5e13bb271679a2e545da72de1cb70ace4 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 24 Aug 2022 17:15:45 +0200 Subject: [PATCH 050/120] Fix a lot of link issues --- docs/development/what.rst | 2 +- docs/examples.rst | 59 ++++++++----------- docs/introduction.rst | 4 +- docs/modules.rst | 9 +-- docs/modules/components.rst | 113 +++++++++++++++++++----------------- docs/modules/networks.rst | 82 +++++++++++++------------- docs/regular_meeting.rst | 6 +- 7 files changed, 136 insertions(+), 139 deletions(-) diff --git a/docs/development/what.rst b/docs/development/what.rst index 4f3bd4fac..a0df21442 100644 --- a/docs/development/what.rst +++ b/docs/development/what.rst @@ -1,4 +1,4 @@ -.. __tespy_development_what_label: +.. _tespy_development_what_label: What can I contribute? ====================== diff --git a/docs/examples.rst b/docs/examples.rst index 944890f4c..04841fd82 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -1,36 +1,27 @@ .. _tespy_examples_label: -~~~~~~~~~~~~~~~~~~~~~~~ -Real World Applications -~~~~~~~~~~~~~~~~~~~~~~~ - -In the example section we provide a variety of TESPy applications, among -others: - -* a very basic model of the clausius rankine process, -* the calculation of backpressure lines of a combined heat and power cycle at - different loads and feed flow temperature levels, -* modeling approach for a district heating system with various consumers and - system infrastructure as well as -* the COP of a heat pump dependent on load, ambient temperature and heat - delivering fluid (air vs. water). - -You can find all examples in the TESPy -`examples repository `__ -on github. Additional small examples can be found in the API-documentation. - -.. _basic_example_label: -.. include:: tutorials_examples/clausius_rankine.rst -.. _combined_cycle_example_label: -.. include:: tutorials_examples/combined_cycle_chp.rst -.. _chp_example_label: -.. include:: tutorials_examples/clausius_rankine_chp.rst -.. _combustion_engine_label: -.. include:: tutorials_examples/combustion_engine.rst -.. _dh_example_label: -.. include:: tutorials_examples/district_heating.rst -.. _heat_pump_cop_label: -.. include:: tutorials_examples/heat_pump.rst -.. _solar_collector_example_label: -.. include:: tutorials_examples/solar_collector.rst -.. _tespy_tutorial_label: +~~~~~~~~~~~~~~~~~~~~ +Example Applications +~~~~~~~~~~~~~~~~~~~~ + +.. card:: Exergy Analysis of a supercritical CO2 Powerplant + :link: https://github.com/fwitte/sCO2_exergy + + Header + ^^^ + + .. grid:: 1 2 + :outline: + + .. grid-item:: + + Some description + + .. grid-item:: + + .. image:: /_static/images/tutorials/heat_pump_steps/flowsheet.svg + :align: center + :alt: BLABLA + + +++ + Footer diff --git a/docs/introduction.rst b/docs/introduction.rst index a24898962..0d7cdb1e8 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -56,8 +56,8 @@ We provide more detailed :ref:`installation instructions `, too. If you want to use the latest features, you might want to install the -**developer version**. See section -:ref:`Developing TESPy ` for more information. +**developer version**. See +:ref:`this section ` for more information. Getting into TESPy ================== diff --git a/docs/modules.rst b/docs/modules.rst index b547c24e5..a5f6d2f1d 100644 --- a/docs/modules.rst +++ b/docs/modules.rst @@ -70,8 +70,9 @@ as the underlying functionalities of the software. :link: tespy_ude_label :link-type: ref - .. image:: /_static/images/modules/fluid_properties.svg - :class: only-light + .. math:: - .. image:: /_static/images/modules/fluid_properties_darkmode.svg - :class: only-dark + \dot{m}_2 = f\left(\frac{X}{X_0}\right)\\ + \dot{m}_2 = f\left(\frac{X}{X_0}\right)\\ + \dot{m}_2 = f\left(\frac{X}{X_0}\right)\\ + \dot{m}_2 = f\left(\frac{X}{X_0}\right) diff --git a/docs/modules/components.rst b/docs/modules/components.rst index 1075ad3d2..8eb0656aa 100644 --- a/docs/modules/components.rst +++ b/docs/modules/components.rst @@ -15,51 +15,51 @@ well as the equations. - Basics - * :py:class:`Cycle closer` - * :py:class:`Sink ` - * :py:class:`Source ` - * :py:class:`Subsystem interface ` + * :py:class:`Cycle closer` + * :py:class:`Sink ` + * :py:class:`Source ` + * :py:class:`Subsystem interface ` - Combustion - * :py:class:`Combustion chamber ` - * :py:class:`Diabatic combustion chamber ` - (Advanced version of combustion chamber, featuring heat losses and - pressure drop) - * :py:class:`Combustion engine ` + * :py:class:`Combustion chamber ` + * :py:class:`Diabatic combustion chamber ` + (Advanced version of combustion chamber, featuring heat losses and pressure + drop) + * :py:class:`Combustion engine ` - Heat exchangers - * :py:class:`Simplified heat exchanger ` - * :py:class:`Solar collector ` - * :py:class:`Parabolic trough ` - * :py:class:`Heat exchanger ` - * :py:class:`Condenser ` - * :py:class:`Desuperheater ` + * :py:class:`Simplified heat exchanger ` + * :py:class:`Solar collector ` + * :py:class:`Parabolic trough ` + * :py:class:`Heat exchanger ` + * :py:class:`Condenser ` + * :py:class:`Desuperheater ` - Nodes - * :py:class:`Droplet separator ` - * :py:class:`Drum ` - * :py:class:`Merge ` - * :py:class:`Separator ` - * :py:class:`Splitter ` + * :py:class:`Droplet separator ` + * :py:class:`Drum ` + * :py:class:`Merge ` + * :py:class:`Separator ` + * :py:class:`Splitter ` - Piping - * :py:class:`Pipe ` - * :py:class:`Valve ` + * :py:class:`Pipe ` + * :py:class:`Valve ` - Reactors - * :py:class:`Fuel cell ` - * :py:class:`Water electrolyzer ` + * :py:class:`Fuel cell ` + * :py:class:`Water electrolyzer ` - Turbomachinery - * :py:class:`Compressor ` - * :py:class:`Pump ` - * :py:class:`Turbine ` + * :py:class:`Compressor ` + * :py:class:`Pump ` + * :py:class:`Turbine ` List of custom components ------------------------- @@ -133,21 +133,28 @@ not be implemented by the solver. There are several components using parameter groups: - heat_exchanger_simple and pipe - * :code:`hydro_group` (:code:`D`, :code:`L`, :code:`ks`) - * :code:`kA_group` (:code:`kA`, :code:`Tamb`) - * :code:`kA_char_group` (:code:`kA_char`, :code:`Tamb`) + + * :code:`hydro_group` (:code:`D`, :code:`L`, :code:`ks`) + * :code:`kA_group` (:code:`kA`, :code:`Tamb`) + * :code:`kA_char_group` (:code:`kA_char`, :code:`Tamb`) + - solar_collector - * :code:`hydro_group` (:code:`D`, :code:`L`, :code:`ks`) - * :code:`energy_group` (:code:`E`, :code:`eta_opt`, :code:`lkf_lin`, - :code:`lkf_quad`, :code:`A`, :code:`Tamb`) + + * :code:`hydro_group` (:code:`D`, :code:`L`, :code:`ks`) + * :code:`energy_group` (:code:`E`, :code:`eta_opt`, :code:`lkf_lin`, + :code:`lkf_quad`, :code:`A`, :code:`Tamb`) + - parabolic_trough - * :code:`hydro_group` (:code:`D`, :code:`L`, :code:`ks`) - * :code:`energy_group` (:code:`E`, :code:`eta_opt`, :code:`aoi`, - :code:`doc`, :code:`c_1`, :code:`c_2`, :code:`iam_1`, :code:`iam_2`, - :code:`A`, :code:`Tamb`) + + * :code:`hydro_group` (:code:`D`, :code:`L`, :code:`ks`) + * :code:`energy_group` (:code:`E`, :code:`eta_opt`, :code:`aoi`, + :code:`doc`, :code:`c_1`, :code:`c_2`, :code:`iam_1`, :code:`iam_2`, + :code:`A`, :code:`Tamb`) + - compressor - * :code:`char_map_eta_s_group` (:code:`char_map_eta_s`, :code:`igva`) - * :code:`char_map_pr_group` (:code:`char_map_pr`, :code:`igva`) + + * :code:`char_map_eta_s_group` (:code:`char_map_eta_s`, :code:`igva`) + * :code:`char_map_pr_group` (:code:`char_map_pr`, :code:`igva`) Custom variables ^^^^^^^^^^^^^^^^ @@ -341,41 +348,41 @@ Characteristics are available for the following components and parameters: - combustion engine - * :py:meth:`tiP_char `: thermal input vs. power ratio. - * :py:meth:`Q1_char `: heat output 1 vs. power ratio. - * :py:meth:`Q2_char `: heat output 2 vs. power ratio. - * :py:meth:`Qloss_char `: heat loss vs. power ratio. + * :py:meth:`tiP_char `: thermal input vs. power ratio. + * :py:meth:`Q1_char `: heat output 1 vs. power ratio. + * :py:meth:`Q2_char `: heat output 2 vs. power ratio. + * :py:meth:`Qloss_char `: heat loss vs. power ratio. - compressor - * :py:meth:`char_map `: pressure ratio vs. non-dimensional mass flow. - * :py:meth:`char_map `: isentropic efficiency vs. non-dimensional mass flow. - * :py:meth:`eta_s_char `: isentropic efficiency. + * :py:meth:`char_map `: pressure ratio vs. non-dimensional mass flow. + * :py:meth:`char_map `: isentropic efficiency vs. non-dimensional mass flow. + * :py:meth:`eta_s_char `: isentropic efficiency. - heat exchangers: - * :py:meth:`kA1_char, kA2_char `: heat transfer coefficient. + * :py:meth:`kA1_char, kA2_char `: heat transfer coefficient. - pump - * :py:meth:`eta_s_char `: isentropic efficiency. - * :py:meth:`flow_char `: absolute pressure change. + * :py:meth:`eta_s_char `: isentropic efficiency. + * :py:meth:`flow_char `: absolute pressure change. - simple heat exchangers - * :py:meth:`kA_char `: heat transfer coefficient. + * :py:meth:`kA_char `: heat transfer coefficient. - turbine - * :py:meth:`eta_s_char `: isentropic efficiency. + * :py:meth:`eta_s_char `: isentropic efficiency. - valve - * :py:meth:`dp_char `: absolute pressure change. + * :py:meth:`dp_char `: absolute pressure change. - water electrolyzer - * :py:meth:`eta_char `: efficiency vs. load ratio. + * :py:meth:`eta_char `: efficiency vs. load ratio. For more information on how the characteristic functions work :ref:`click here `. diff --git a/docs/modules/networks.rst b/docs/modules/networks.rst index 79d1dbca5..dea1d535c 100644 --- a/docs/modules/networks.rst +++ b/docs/modules/networks.rst @@ -13,10 +13,10 @@ The TESPy network contains all data of your plant, which in terms of the calculation is represented by a nonlinear system of equations. The system variables of your TESPy network are: - * mass flow, - * pressure, - * enthalpy and - * the mass fractions of the network's fluids. +* mass flow, +* pressure, +* enthalpy and +* the mass fractions of the network's fluids. The solver will solve for these variables. As stated in the introduction the list of fluids is passed to your network on creation. If your **system** @@ -257,19 +257,19 @@ The initialisation is performed in the following steps. **General preprocessing:** - * check network consistency and initialise components (if network topology is - changed to a prior calculation only). - * perform design/offdesign switch (for offdesign calculations only). - * preprocessing of offdesign case using the information from the - :code:`design_path` argument. +* check network consistency and initialise components (if network topology is + changed to a prior calculation only). +* perform design/offdesign switch (for offdesign calculations only). +* preprocessing of offdesign case using the information from the + :code:`design_path` argument. **Finding starting values:** - * fluid propagation. - * fluid property initialisation. - * initialisation from previous simulation run (:code:`ìnit_previous`). - * initialisation from .csv (setting starting values from :code:`init_path` - argument). +* fluid propagation. +* fluid property initialisation. +* initialisation from previous simulation run (:code:`ìnit_previous`). +* initialisation from .csv (setting starting values from :code:`init_path` + argument). The network check is used to find errors in the network topology, the calculation can not start without a successful check. For components, a @@ -413,29 +413,27 @@ added a convergence check. **has been added**. This manipulation has four steps, the first two are always applied: - * Cut off fluid mass fractions smaller than 0 and larger than 1. This way a - mass fraction of a single fluid components never exceeds these boundaries. - * Check, whether the fluid properties of pure fluids are within the available - ranges of CoolProp and readjust the values if not. +* Cut off fluid mass fractions smaller than 0 and larger than 1. This way a + mass fraction of a single fluid components never exceeds these boundaries. +* Check, whether the fluid properties of pure fluids are within the available + ranges of CoolProp and readjust the values if not. The next two steps are applied, if the user did not specify an :code:`init_path` and the iteration count is lower than 3, thus in the first three iteration steps of the algorithm only. In other cases this convergence check is skipped. - * Fox mixtures: check, if the fluid properties (pressure, enthalpy and - mass flow) are within the user specified boundaries - (:code:`p_range, h_range, m_range`) and if not, cut off higher/lower - values. - * Check the fluid properties of the connections based on the components they - are connecting. For example, check if the pressure at the outlet of a - turbine is lower than the pressure at the inlet or if the flue gas - composition at a combustion chamber's outlet is within the range of a - "typical" flue gas composition. If there are any violations, the - corresponding variables are manipulated. If you want to look up, what - exactly the convergence check for a specific component does, look out for - the :code:`convergence_check` methods in the - :py:mod:`tespy.components module `. +* Fox mixtures: check, if the fluid properties (pressure, enthalpy and mass + flow) are within the user specified boundaries + (:code:`p_range, h_range, m_range`) and if not, cut off higher/lower values. +* Check the fluid properties of the connections based on the components they + are connecting. For example, check if the pressure at the outlet of a turbine + is lower than the pressure at the inlet or if the flue gas composition at a + combustion chamber's outlet is within the range of a "typical" flue gas + composition. If there are any violations, the corresponding variables are + manipulated. If you want to look up, what exactly the convergence check for a + specific component does, look out for the :code:`convergence_check` methods + in the :py:mod:`tespy.components module `. In a lot of different tests the algorithm has found a near enough solution after the third iteration, further checks are usually not required. @@ -628,14 +626,14 @@ After having exported the LaTeX code, you can simply use :code:`\input{}` in your main LaTeX document to include the documentation of your model. In order to compile correctly you need to load the following LaTeX packages: - - graphicx - - float - - hyperref - - booktabs - - amsmath - - units - - cleveref - - longtable +* graphicx +* float +* hyperref +* booktabs +* amsmath +* units +* cleveref +* longtable For generating different file formats, like markdown, html or restructuredtext, you could try the `pandoc `_ library. @@ -653,9 +651,9 @@ To print the results in your console use the :code:`print_results()` method. It will print tables containing the component, connection and bus properties. Some of the results will be colored, the colored results indicate - * if a parameter was specified as value before calculation. - * if a parameter is out of its predefined value bounds (e.g. efficiency > 1). - * if a component parameter was set to :code:`'var'` in your calculation. +* if a parameter was specified as value before calculation. +* if a parameter is out of its predefined value bounds (e.g. efficiency > 1). +* if a component parameter was set to :code:`'var'` in your calculation. The color for each of those categories is different and might depend on the console settings of your machine. If you do not want the results to be colored diff --git a/docs/regular_meeting.rst b/docs/regular_meeting.rst index f616305ac..084e5a035 100644 --- a/docs/regular_meeting.rst +++ b/docs/regular_meeting.rst @@ -8,9 +8,9 @@ Online "Stammtisch" =================== We have decided to start a reoccurring "Stammtisch" meeting for all interested TESPy users and (potential) developers. You are invited to join us on every 3rd -Monday of a month at 17:00 CE(S)T for a casual get together. The first meeting -will be held at June, 20, 2022. The intent of this meeting is to establish a -more active and well connected network of TESPy users and developers. +Monday of a month at 17:00 CE(S)T for a casual get together. The intent of this +meeting is to establish a more active and well connected network of TESPy users +and developers. If you are interested, you can simply join the meeting at https://meet.jit.si/tespy_user_meeting. We are looking forward to seeing you! From ba22955548b6280d6073c3253f3d50a18cec20e6 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 24 Aug 2022 17:20:03 +0200 Subject: [PATCH 051/120] Add note to energy sign convention --- docs/basics/intro.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/basics/intro.rst b/docs/basics/intro.rst index 4d0b389ca..30937c6a6 100644 --- a/docs/basics/intro.rst +++ b/docs/basics/intro.rst @@ -172,6 +172,12 @@ the fluid vector at one point in our network. c2.set_attr(T=20, x=1, fluid={'R134a': 1}) c4.set_attr(T=75, x=0) +.. note:: + + The sign convention for energy transfer by components is always from the + perspective of the component. Energy entering the component means positive + sign, energy leaving the component's system boundary means negative sign. + Start your calculation ---------------------- From c6f572276d8841625c651229fd426e820b6aca21 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 24 Aug 2022 17:24:25 +0200 Subject: [PATCH 052/120] Set outline for remaining basic tutorials --- docs/basics/district_heating.rst | 12 ++++++++++++ docs/basics/gas_turbine.rst | 12 ++++++++++++ docs/basics/rankine_cycle.rst | 11 +++++++++++ 3 files changed, 35 insertions(+) diff --git a/docs/basics/district_heating.rst b/docs/basics/district_heating.rst index 128ff0fbd..70a2d02b4 100644 --- a/docs/basics/district_heating.rst +++ b/docs/basics/district_heating.rst @@ -16,3 +16,15 @@ District Heating Network :figclass: only-dark Figure: Topology of the district heating network + + +Setting up the System +^^^^^^^^^^^^^^^^^^^^^ + + +Calculate Heat Losses +^^^^^^^^^^^^^^^^^^^^^ + + +Calculate Pipe Characteristics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst index 457d9c022..eb3d0c29d 100644 --- a/docs/basics/gas_turbine.rst +++ b/docs/basics/gas_turbine.rst @@ -16,3 +16,15 @@ Gas Turbine :figclass: only-dark Figure: Topology of the gas turbine + + +Setting up the Combustion Chamber +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +Setting up the Full System +^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +Fluid Composition Specifications +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst index 01eee8057..54b85e1a0 100644 --- a/docs/basics/rankine_cycle.rst +++ b/docs/basics/rankine_cycle.rst @@ -16,3 +16,14 @@ Rankine Cycle :figclass: only-dark Figure: Topology of the rankine cycle + +Setting up the Cycle +^^^^^^^^^^^^^^^^^^^^ + + +Analyze Efficiency and Powergeneration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +Partload Simulation +^^^^^^^^^^^^^^^^^^^ From 0c110821fa40c3b2dd0e3c7e72f36f20a6f7b45e Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 24 Aug 2022 17:25:48 +0200 Subject: [PATCH 053/120] Add fluid properties card --- .../images/modules/fluid_properties.svg | 2288 +++++++++++++++++ 1 file changed, 2288 insertions(+) create mode 100644 docs/_static/images/modules/fluid_properties.svg diff --git a/docs/_static/images/modules/fluid_properties.svg b/docs/_static/images/modules/fluid_properties.svg new file mode 100644 index 000000000..a9a5d8f02 --- /dev/null +++ b/docs/_static/images/modules/fluid_properties.svg @@ -0,0 +1,2288 @@ + +image/svg+xml0.00135739 +m +3 +kg +0.002 +m +3 +kg +0.005 +m +3 +kg +0.01 +m +3 +kg +0.02 +m +3 +kg +0.05 +m +3 +kg +0.1 +m +3 +kg +0.2 +m +3 +kg +0.5 +m +3 +kg +1.0 +m +3 +kg +2.0 +m +3 +kg +-25.0 °C +0.0 °C +25.0 °C +50.0 °C +75.0 °C +100.0 °C +125.0 °C +150.0 °C +175.0 °C +200.0 °C +225.0 °C +250.0 °C +275.0 °C +300.0 °C +325.0 °C +1000.0 +JkgK +1500.0 +JkgK +2000.0 +JkgK +2500.0 +JkgK +3000.0 +JkgK +3500.0 +JkgK +4000.0 +JkgK +4500.0 +JkgK +5000.0 +JkgK +5500.0 +JkgK +6000.0 +JkgK +6500.0 +JkgK +7000.0 +JkgK +7500.0 +JkgK +0.0 - +0.1 - +0.2 - +0.3 - +0.4 - +0.5 - +0.6 - +0.7 - +0.8 - +0.9 - +1.0 - +1 +2 +3 +4 +5 +6 + From 1d200af9de7949acb25b1bb690b481f55177e804 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Thu, 25 Aug 2022 17:33:00 +0200 Subject: [PATCH 054/120] Add more strucutre to clausius rankine section --- docs/basics/rankine_cycle.rst | 233 ++++++++++++++++++++++++++++++++++ docs/tutorials.rst | 29 +++-- 2 files changed, 250 insertions(+), 12 deletions(-) diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst index 54b85e1a0..c1e390cb6 100644 --- a/docs/basics/rankine_cycle.rst +++ b/docs/basics/rankine_cycle.rst @@ -19,11 +19,244 @@ Rankine Cycle Setting up the Cycle ^^^^^^^^^^^^^^^^^^^^ +We will model the cycle including the cooling water of the condenser. For this +start with the :code:`Network` set up we already know. +.. code-block:: python + + from tespy.networks import Network + + # create a network object with R134a as fluid + fluid_list = ['water'] + my_plant = Network(fluids=fluid_list) + my_plant.set_attr(T_unit='C', p_unit='bar', h_unit='kJ / kg') + +Following, we create the components and connect them. The :code:`Condenser` has +a hot side inlet and outlet as well as a cold side inlet and outlet. The hot +side is indicated by using the index 1 for the inlet and outlet :code:`in1` and +:code:`out1`, the cold side uses the index 2 (:code:`in2` and :code:`out2`). + +Again, for the closed thermodynamic cycle we have to insert a cycle closer. The +cooling water inlet and the cooling water outlet of the condenser are directly +connected to a :code:`Source` and a :code:`Sink` respectively. + +.. code-block:: python + + from tespy.components import ( + CycleCloser, Pump, Condenser, Turbine, HeatExchangerSimple, Source, Sink + ) + + cc = CycleCloser('cycle closer') + sg = HeatExchangerSimple('steam generator') + mc = Condenser('main condenser') + tu = Turbine('steam turbine') + fp = Pump('feed pump') + + cwso = Source('cooling water source') + cwsi = Sink('cooling water sink') + + from tespy.connections import Connection + + c1 = Connection(cc, 'out1', tu, 'in1', label='1') + c2 = Connection(tu, 'out1', mc, 'in1', label='2') + c3 = Connection(mc, 'out1', fp, 'in1', label='3') + c4 = Connection(fp, 'out1', sg, 'in1', label='4') + c0 = Connection(sg, 'out1', cc, 'in1', label='0') + + my_plant.add_conns(c1, c2, c3, c4, c0) + + c11 = Connection(cwso, 'out1', mc, 'in2', label='11') + c12 = Connection(mc, 'out2', cwsi, 'in1', label='12') + + my_plant.add_conns(c11, c12) + +For the parameters, we predefine the pressure losses in the heat exchangers. +For the condenser, the hot side pressure losses are neglected :code:`pr1=1`, +for the cooling water side we assume pressure loss of 2 % :code:`pr2=0.98`. The +steam generator inflicts a pressure loss of 10 %. + +The turbine and feed pump will have the isentropic efficiency specified. For +the connection parameters, the fluid has to be defined in both the main cycle +and the cooling water system. Furthermore, the live steam temperature, pressure +and mass flow are set. Lastly, we set the condensation pressure level and the +feed and return flow temperature of the cooling water as well as its feed +pressure. + +.. code-block:: python + + mc.set_attr(pr1=1, pr2=0.98) + sg.set_attr(pr=0.9) + tu.set_attr(eta_s=0.9) + fp.set_attr(eta_s=0.75) + + c11.set_attr(T=20, p=1.2, fluid={'water': 1}) + c12.set_attr(T=35) + c1.set_attr(T=600, p=150, m=10, fluid={'water': 1}) + c2.set_attr(p=0.1) + + my_plant.solve(mode='design') + my_plant.print_results() + +After running the simulation, for example, we can observe the temperature +differences at the condenser. Instead of directly setting a pressure value for +condensation, we could also set the upper terminal temperature difference +:code:`ttd_u` instead. It is defined as the condensation temperature to cooling +water return flow temperature. + +.. tip:: + + You will find the documentation of each equation of the components in the + respective seciton of the API documentation. For example, the condenser + :py:class:`tespy.components.heat_exchangers.condenser.Condenser`. + +.. code-block:: python + + mc.set_attr(pr1=1, pr2=0.98, ttd_u=4) + c2.set_attr(p=None) + + my_plant.solve(mode='design') + my_plant.print_results() + +After rerunning, we will see that the condensation temperature and pressure +are both automatically calculated by the specified terminal temperature value. + +Assess Electrical Power +^^^^^^^^^^^^^^^^^^^^^^^ +To assess the electrical power output we want to consider the power generated +by the turbine as well as the power required to drive the feed pump. It is +possible to include both of the component's power values in a single electrical +:code:`Bus`. We can do this by importing the +:py:class:`tespy.connections.bus.Bus` class, creating an instance and adding +both components to the bus. + +.. code-block:: python + + from tespy.connections import Bus + + powergen = Bus("electrical power output") + + powergen.add_comps( + {"comp": tu, "char": 0.97, "base": "component"}, + {"comp": fp, "char": 0.97, "base": "bus"}, + ) + + my_plant.add_busses(powergen) + + my_plant.solve(mode='design') + my_plant.print_results() + +.. note:: + + The :code:`Bus` can take components which either produce or consume energy. + Specifying :code:`'base': 'bus'` means, that the efficiency value is + referenced to the electrical power + + .. math:: + + \dot{W} = \dot{W}_\text{el} \cdot \eta + + while specifying :code:`'base': 'component'` (default) takes the component's + power as base value. + + .. math:: + + \dot{W}_\text{el} = \dot{W} \cdot \eta + +The results for the bus are printed separately. Observe, that the steam +turbine's electrical power production (:code:`bus value`) is lower than the +:code:`component value`, while it is inverted for the feed pump. + +You can also set the total desired power production of the system, for example +replacing the mass flow specification at connection 1: + +.. code-block:: python + + powergen.set_attr(P=-10e6) + c1.set_attr(m=None) + + my_plant.solve(mode='design') + my_plant.print_results() Analyze Efficiency and Powergeneration ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +In this section, we will analyze the power production and the efficiency +of the cycle, given constant steam mass flow and with varying values for the + +- live steam pressure, +- live steam temperature and +- cooling water temperature level. + +To do that, we are using a very similar setup as has been used in the +:ref:`heat pump tutorial `. +.. dropdown:: Click to expand to code section + + .. code-block:: python + + import matplotlib.pyplot as plt + import numpy as np + + + + fig, ax = plt.subplots(2, 3, sharey=True, sharex=True, figsize=(16, 8)) + + [a.grid() for a in ax] + + ax[0].set_ylabel('Efficiency of the rankine cycle in %') + ax[3].set_ylabel('Power of the rankine cycle in %') + plt.tight_layout() + fig.savefig('eta_power_parametric.svg') + +.. figure:: /_static/images/basics/eta_power_parametric.svg + :align: center + :alt: Parametric analysis of the efficiency and power output + + Figure: Parametric analysis of the efficiency and power output Partload Simulation ^^^^^^^^^^^^^^^^^^^ +In the partload simulation part, we are starting with a specific design of the +plant and calculate the partload perfomance with some assumptions on the +component's individual behavior. The table below summarizes the assumptions, +which we will keep as simple as possible in this moment. For more insights +have a look at the step by step +:ref:`heat pump tutorial ` or at the +:ref:`Network documentation `. + ++-----------+---------------------------+-------------------------------+ +| Component | Assumptions | Settings | ++===========+===========================+===============================+ +| Turbine | cone law applies | unset inlet pressure and | +| | | apply cone law | ++-----------+---------------------------+-------------------------------+ +| Condenser | constant heat transfer | unset terminal temperature | +| | coefficient | difference and set heat | +| | | transfer coefficient | ++-----------+---------------------------+-------------------------------+ +| Cooling | constant volumetric flow | unset return temperature | +| water | | value and set volumetric flow | ++-----------+---------------------------+-------------------------------+ + +With these specifications, the following phyics are applied to the model: + +- Due to the constant volumetric flow of water, the temperature of the cooling + water returning from the condenser will react to the total heat transferred + in the condensation: Increased heat transfer means incresing temperature, + decreased heat transfer means decreased temperature. +- The constant heat transfer coefficient of the condenser will calculate the + condensation temperature (and therefore pressure) based on the temperature + regime in the cooling water side: + - Increase in temperature for the cooling water leads to increased + condensation temperature (at constant heat transfer). + - Increase in heat transfer means increase in necessary temperature + difference at the condenser (at constant cooling water inlet temperature). +- The cone law is a mathematical model to predict the pressure at the turbine's + inlet based on the deviation from the design conditions. Generally, + increased mass flow leads to higher inlet pressure (at constant inlet + temperature and constant outlet pressure). However, this equation is more + complex, since a lot more parameters are involved compared to the other + equations applied. + +.. code-block:: python + + some code diff --git a/docs/tutorials.rst b/docs/tutorials.rst index f6d2c9a05..1acf9f042 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -3,18 +3,23 @@ ~~~~~~~~~~~~~~~~~~ Advanced Tutorials ~~~~~~~~~~~~~~~~~~ +We provide more advanced tutorials for you to better understand how to work +with more complex systems in TESPy. -We provide tutorials for you to better understand how to work -with TESPy. You will learn how to create basic models and get the idea of -designing a plant and simulating the offdesign behavior in the heat pump -tutorial. Furthermore, the starting values tutorial will help you to get a -stable simulation and faster solutions. On top of that, we created a tutorial -for the usage of the combustion chamber: It is an important component for -thermal power plants while being a source for many errors in the calculation. +At the example of different heat pump topologies, you will learn to -The last tutorial is a plant design optimization tutorial. A thermal power -plant with two extraction stages is optimized in regard of thermal efficiency -with respect to the extraction pressure levels. +- create a more complex model *step by step* and get the idea of designing a + plant and calculating the offdesign behavior. +- set up a code structure, which allows you to generate stable starting values + flexibly, helping you to make faster analyses. +- use the inbuilt exergy analysis method in a simple geothermal heat pump + setting. + +Furthermore, we introduce the coupling of TESPy with pygmo in order to create +an optimization problem, which optimizes thermal efficiency of a clausius +rankine power plant. + +- CGAM! .. toctree:: :maxdepth: 1 @@ -23,6 +28,6 @@ with respect to the extraction pressure levels. tutorials/heat_pump_steps.rst tutorials/starting_values.rst - tutorials/combustion_chamber.rst - tutorials/pygmo_optimization.rst tutorials/heat_pump_exergy.rst + tutorials/pygmo_optimization.rst + tutorials/combustion_chamber.rst From fbf87d697d178380a94ba7a6f5f6615e7e047031 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Thu, 25 Aug 2022 17:33:20 +0200 Subject: [PATCH 055/120] Fix some references and bibtex entries --- docs/benchmarks.rst | 7 +++++-- docs/development/what.rst | 2 +- docs/references.bib | 29 +++++++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/docs/benchmarks.rst b/docs/benchmarks.rst index c7a1fc79d..e69a48c48 100644 --- a/docs/benchmarks.rst +++ b/docs/benchmarks.rst @@ -1,5 +1,8 @@ Benchmarks ========== -TODO: REFERENCES TO PAPERS -TODO: UNIT TESTING STUFF +- SEGS :cite:`Witte2022` +- sCO2 :cite:`Witte2022` +- air refrigeration :cite:`Witte2022` +- CGAM :cite:`Hofmann2022`, :cite:`Valero1994`, :cite:`Bejan1996` +- UNIT TESTING STUFF diff --git a/docs/development/what.rst b/docs/development/what.rst index a0df21442..8b0a36b7b 100644 --- a/docs/development/what.rst +++ b/docs/development/what.rst @@ -33,7 +33,7 @@ Share your projects ^^^^^^^^^^^^^^^^^^^ You have used the software in your research paper or project, maybe even in a real world application? We would love to feature your project on our -:ref:`Real World Application ` page. Please reach out to +:ref:`Example Applications ` page. Please reach out to us by opening a new issue on our github page. Add new component equations diff --git a/docs/references.bib b/docs/references.bib index eac3d121f..a70bfdfc7 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -36,7 +36,7 @@ @TechReport{Lippke1995 url = {https://www.osti.gov/biblio/95571}, address = {Albuquerque}, groups = {solar-case-study}, - month = {6}, + month = jun, place = {United States}, year = {1995}, } @@ -270,7 +270,7 @@ @book{CRCHandbook2021 @article{Witte2022, doi = {10.3390/en15114087}, year = {2022}, - publisher = {The Open Journal}, + publisher = {{MDPI} {AG}}, volume = {15}, number = {11}, article-number = {4087}, @@ -279,3 +279,28 @@ @article{Witte2022 title = {Generic and Open-Source Exergy Analysis—Extending the Simulation Framework TESPy}, journal = {Energies} } + +@inproceedings{Hofmann2022, + editor = {Brian Elmegaard and Enrico Sciubba and Ana M Blanco-Marigorta and Jonas Kjær Jensen and Wiebke Brix Markussen and Wiebke Meesenburg and Nasrin Arjomand Kermani and Tingting Zhu and René Kofler}, + author = {Hofmann, Mathias and Witte, Francesco and Shawky, Karim and Tuschy, Ilja and Tsatsaronis, George}, + title = {{T}hermal {E}ngineering {S}ystems in {P}ython ({TESPy}): The implementation and validation of the chemical exergy}, + booktitle = {Proceedings of ECOS 2022}, + pages = {257--268}, + publisher = {DTU Construct}, + venue = {Copenhagen, Denmark}, + month = jul, + year = {2022}, +} + +@article{Valero1994, + doi = {10.1016/0360-5442(94)90112-0}, + year = 1994, + month = mar, + publisher = {Elsevier {BV}}, + volume = {19}, + number = {3}, + pages = {279--286}, + author = {Antonio Valero and Miguel A. Lozano and Luis Serra and George Tsatsaronis and Javier Pisa and Christos Frangopoulos and Michael R. von Spakovsky}, + title = {{CGAM} problem: Definition and conventional solution}, + journal = {Energy} +} From a7bf8dee84785fe8531dc81b1567d52fc5e65c7a Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 26 Aug 2022 13:14:08 +0200 Subject: [PATCH 056/120] Fix two typos --- docs/basics/rankine_cycle.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst index c1e390cb6..8b6319211 100644 --- a/docs/basics/rankine_cycle.rst +++ b/docs/basics/rankine_cycle.rst @@ -237,7 +237,7 @@ have a look at the step by step | water | | value and set volumetric flow | +-----------+---------------------------+-------------------------------+ -With these specifications, the following phyics are applied to the model: +With these specifications, the following physics are applied to the model: - Due to the constant volumetric flow of water, the temperature of the cooling water returning from the condenser will react to the total heat transferred @@ -246,10 +246,12 @@ With these specifications, the following phyics are applied to the model: - The constant heat transfer coefficient of the condenser will calculate the condensation temperature (and therefore pressure) based on the temperature regime in the cooling water side: + - Increase in temperature for the cooling water leads to increased condensation temperature (at constant heat transfer). - Increase in heat transfer means increase in necessary temperature difference at the condenser (at constant cooling water inlet temperature). + - The cone law is a mathematical model to predict the pressure at the turbine's inlet based on the deviation from the design conditions. Generally, increased mass flow leads to higher inlet pressure (at constant inlet From 38a8bf5ac9ce00953f979ad109dbdd42e44a157a Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 26 Aug 2022 19:03:34 +0200 Subject: [PATCH 057/120] Add parametric analysis section for rankine cycle --- ...arametric.svg => heat_pump_parametric.svg} | 0 .../images/basics/rankine_parametric.svg | 2490 +++++++++++++++++ docs/basics/heat_pump.rst | 8 +- docs/basics/rankine_cycle.rst | 81 +- docs/tutorials/starting_values.rst | 2 +- 5 files changed, 2565 insertions(+), 16 deletions(-) rename docs/_static/images/basics/{COP_parametric.svg => heat_pump_parametric.svg} (100%) create mode 100644 docs/_static/images/basics/rankine_parametric.svg diff --git a/docs/_static/images/basics/COP_parametric.svg b/docs/_static/images/basics/heat_pump_parametric.svg similarity index 100% rename from docs/_static/images/basics/COP_parametric.svg rename to docs/_static/images/basics/heat_pump_parametric.svg diff --git a/docs/_static/images/basics/rankine_parametric.svg b/docs/_static/images/basics/rankine_parametric.svg new file mode 100644 index 000000000..690c22de0 --- /dev/null +++ b/docs/_static/images/basics/rankine_parametric.svg @@ -0,0 +1,2490 @@ + + + + + + + + 2022-08-26T19:01:08.539022 + image/svg+xml + + + Matplotlib v3.4.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/basics/heat_pump.rst b/docs/basics/heat_pump.rst index ca71283aa..26ac7fbbc 100644 --- a/docs/basics/heat_pump.rst +++ b/docs/basics/heat_pump.rst @@ -204,13 +204,13 @@ plot using matplotlib. ax[0].set_ylabel('COP of the heat pump') plt.tight_layout() - fig.savefig('COP_parametric.svg') + fig.savefig('heat_pump_parametric.svg') -.. figure:: /_static/images/basics/COP_parametric.svg +.. figure:: /_static/images/basics/heat_pump_parametric.svg :align: center - :alt: Parametric analysis of the COP + :alt: Parametric analysis of the heat pump's COP - Figure: Parametric analysis of the COP + Figure: Parametric analysis of the heat pump's COP The figure shows the results of the COP analysis. The base case is at an evaporation temperature of 20 °C, the condensation temperature at 80 °C and the diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst index 8b6319211..2c8e6c026 100644 --- a/docs/basics/rankine_cycle.rst +++ b/docs/basics/rankine_cycle.rst @@ -90,7 +90,7 @@ pressure. fp.set_attr(eta_s=0.75) c11.set_attr(T=20, p=1.2, fluid={'water': 1}) - c12.set_attr(T=35) + c12.set_attr(T=30) c1.set_attr(T=600, p=150, m=10, fluid={'water': 1}) c2.set_attr(p=0.1) @@ -111,7 +111,7 @@ water return flow temperature. .. code-block:: python - mc.set_attr(pr1=1, pr2=0.98, ttd_u=4) + mc.set_attr(ttd_u=4) c2.set_attr(p=None) my_plant.solve(mode='design') @@ -187,27 +187,86 @@ of the cycle, given constant steam mass flow and with varying values for the - cooling water temperature level. To do that, we are using a very similar setup as has been used in the -:ref:`heat pump tutorial `. +:ref:`heat pump tutorial `. For the feed water +temperature level we want to set the change in temperature at the condenser +to a constant value. Also, we have to unset the power generation specification +again and use a constant mass flow instead. With :code:`iterinfo=False` we +can disable the printout of the convergence history. .. dropdown:: Click to expand to code section .. code-block:: python + my_plant.set_attr(iterinfo=False) + c1.set_attr(m=20) + powergen.set_attr(P=None) + import matplotlib.pyplot as plt import numpy as np - - - fig, ax = plt.subplots(2, 3, sharey=True, sharex=True, figsize=(16, 8)) - - [a.grid() for a in ax] + data = { + 'T_livesteam': np.linspace(450, 750, 7), + 'T_cooling': np.linspace(15, 45, 7), + 'p_livesteam': np.linspace(75, 225, 7) + } + eta = { + 'T_livesteam': [], + 'T_cooling': [], + 'p_livesteam': [] + } + power = { + 'T_livesteam': [], + 'T_cooling': [], + 'p_livesteam': [] + } + + for T in data['T_livesteam']: + c1.set_attr(T=T) + my_plant.solve('design') + eta['T_livesteam'] += [abs(powergen.P.val) / sg.Q.val * 100] + power['T_livesteam'] += [abs(powergen.P.val) / 1e6] + + # reset to base temperature + c1.set_attr(T=600) + + for T in data['T_cooling']: + c12.set_attr(T=T) + c11.set_attr(T=T - 10) + my_plant.solve('design') + eta['T_cooling'] += [abs(powergen.P.val) / sg.Q.val * 100] + power['T_cooling'] += [abs(powergen.P.val) / 1e6] + + # reset to base temperature + c12.set_attr(T=30) + c11.set_attr(T=20) + + for p in data['p_livesteam']: + c1.set_attr(p=p) + my_plant.solve('design') + eta['p_livesteam'] += [abs(powergen.P.val) / sg.Q.val * 100] + power['p_livesteam'] += [abs(powergen.P.val) / 1e6] + + + fig, ax = plt.subplots(2, 3, figsize=(16, 8), sharex='col', sharey='row') + + ax = ax.flatten() + [a.grid() for a in ax.flatten()] + + i = 0 + for key in data: + ax[i].scatter(data[key], eta[key]) + ax[i + 3].scatter(data[key], power[key]) + i += 1 ax[0].set_ylabel('Efficiency of the rankine cycle in %') - ax[3].set_ylabel('Power of the rankine cycle in %') + ax[3].set_ylabel('Power of the rankine cycle in MW') + ax[3].set_xlabel('Live steam temperature in °C') + ax[4].set_xlabel('Feed water temperature in °C') + ax[5].set_xlabel('Live steam pressure in bar') plt.tight_layout() - fig.savefig('eta_power_parametric.svg') + fig.savefig('rankine_parametric.svg') -.. figure:: /_static/images/basics/eta_power_parametric.svg +.. figure:: /_static/images/basics/rankine_parametric.svg :align: center :alt: Parametric analysis of the efficiency and power output diff --git a/docs/tutorials/starting_values.rst b/docs/tutorials/starting_values.rst index b7c4cea8b..a9e4a211c 100644 --- a/docs/tutorials/starting_values.rst +++ b/docs/tutorials/starting_values.rst @@ -491,7 +491,7 @@ building a network, that works with a variety of working fluids. .. figure:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg :align: center - :alit: Analysis of the COP using different working fluids + :alt: Analysis of the COP using different working fluids Figure: Analysis of the COP using different working fluids From 2846e082f2f14c4ae67b41c9294f89f744e2aa8f Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 26 Aug 2022 19:08:04 +0200 Subject: [PATCH 058/120] Fix sphinx future warning --- docs/conf.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 080ce709a..8d62c12a4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -63,9 +63,11 @@ bibtex_bibfiles = ['references.bib'] # links to github +github_repo_url = "https://github.com/oemof/tespy/" extlinks = { - 'issue': ('https://github.com/oemof/tespy/issues/%s', '#'), - 'pr': ('https://github.com/oemof/tespy/pull/%s', 'PR #'), + "issue": (f"{github_repo_url}/issues/%s", "#%s"), # noqa: WPS323 + "pr": (f"{github_repo_url}/pull/%s", "PR #%s"), # noqa: WPS323 + "commit": (f"{github_repo_url}/commit/%s", "%s"), # noqa: WPS323 } # -- Options for HTML output ---------------------------------------------- From 3c30e4a535b8b140b52ed31088eb93ef9f9ef2f4 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 28 Aug 2022 17:31:42 +0200 Subject: [PATCH 059/120] Finish rankine intro --- .../images/basics/rankine_parametric.svg | 1592 ++++++----------- .../images/basics/rankine_partload.svg | 1001 +++++++++++ docs/basics/rankine_cycle.rst | 214 +-- tutorial/basics/rankine.py | 180 ++ 4 files changed, 1799 insertions(+), 1188 deletions(-) create mode 100644 docs/_static/images/basics/rankine_partload.svg create mode 100755 tutorial/basics/rankine.py diff --git a/docs/_static/images/basics/rankine_parametric.svg b/docs/_static/images/basics/rankine_parametric.svg index 690c22de0..cd141324f 100644 --- a/docs/_static/images/basics/rankine_parametric.svg +++ b/docs/_static/images/basics/rankine_parametric.svg @@ -6,7 +6,7 @@ - 2022-08-26T19:01:08.539022 + 2022-08-28T17:24:56.132752 image/svg+xml @@ -30,148 +30,100 @@ z - - + - - - - - - - - + + + + + + + + - +" id="md378308c73" style="stroke:#000000;stroke-width:0.8;"/> - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + - + +" id="m4560627564" style="stroke:#000000;stroke-width:0.8;"/> - + - + - - + - + - + - + - - + - + - + - + - - + - + - + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - - - + + - + - + - - - + + - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - - - + + - + - + - - - + + - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - - - - - - - - - - - - + + + + + + + + + + + - - - + + - + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - + + - + - + - + - + - - - - - - - - - - - - - - - - - - - + - + +" id="DejaVuSans-73" transform="scale(0.015625)"/> + + + - - + - + - + - + - + - - + - + - + - + - + - - + - + - + - + - + - - + - + - + - + - + - - + - + - + - + - + - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - + + - + - + - + - + - - - - - - - - - - - - - - - - - - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + - + - + - + - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - - - + + + - + - - - + + - + - + - + - + - - - - - - - - - - - - - - - - - - - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - - - - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/docs/_static/images/basics/rankine_partload.svg b/docs/_static/images/basics/rankine_partload.svg new file mode 100644 index 000000000..f28446f52 --- /dev/null +++ b/docs/_static/images/basics/rankine_partload.svg @@ -0,0 +1,1001 @@ + + + + + + + + 2022-08-28T17:24:59.624666 + image/svg+xml + + + Matplotlib v3.4.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst index 2c8e6c026..73537add9 100644 --- a/docs/basics/rankine_cycle.rst +++ b/docs/basics/rankine_cycle.rst @@ -22,14 +22,10 @@ Setting up the Cycle We will model the cycle including the cooling water of the condenser. For this start with the :code:`Network` set up we already know. -.. code-block:: python - - from tespy.networks import Network - - # create a network object with R134a as fluid - fluid_list = ['water'] - my_plant = Network(fluids=fluid_list) - my_plant.set_attr(T_unit='C', p_unit='bar', h_unit='kJ / kg') +.. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_1] + :end-before: [sec_2] Following, we create the components and connect them. The :code:`Condenser` has a hot side inlet and outlet as well as a cold side inlet and outlet. The hot @@ -40,35 +36,10 @@ Again, for the closed thermodynamic cycle we have to insert a cycle closer. The cooling water inlet and the cooling water outlet of the condenser are directly connected to a :code:`Source` and a :code:`Sink` respectively. -.. code-block:: python - - from tespy.components import ( - CycleCloser, Pump, Condenser, Turbine, HeatExchangerSimple, Source, Sink - ) - - cc = CycleCloser('cycle closer') - sg = HeatExchangerSimple('steam generator') - mc = Condenser('main condenser') - tu = Turbine('steam turbine') - fp = Pump('feed pump') - - cwso = Source('cooling water source') - cwsi = Sink('cooling water sink') - - from tespy.connections import Connection - - c1 = Connection(cc, 'out1', tu, 'in1', label='1') - c2 = Connection(tu, 'out1', mc, 'in1', label='2') - c3 = Connection(mc, 'out1', fp, 'in1', label='3') - c4 = Connection(fp, 'out1', sg, 'in1', label='4') - c0 = Connection(sg, 'out1', cc, 'in1', label='0') - - my_plant.add_conns(c1, c2, c3, c4, c0) - - c11 = Connection(cwso, 'out1', mc, 'in2', label='11') - c12 = Connection(mc, 'out2', cwsi, 'in1', label='12') - - my_plant.add_conns(c11, c12) +.. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_2] + :end-before: [sec_3] For the parameters, we predefine the pressure losses in the heat exchangers. For the condenser, the hot side pressure losses are neglected :code:`pr1=1`, @@ -82,20 +53,10 @@ and mass flow are set. Lastly, we set the condensation pressure level and the feed and return flow temperature of the cooling water as well as its feed pressure. -.. code-block:: python - - mc.set_attr(pr1=1, pr2=0.98) - sg.set_attr(pr=0.9) - tu.set_attr(eta_s=0.9) - fp.set_attr(eta_s=0.75) - - c11.set_attr(T=20, p=1.2, fluid={'water': 1}) - c12.set_attr(T=30) - c1.set_attr(T=600, p=150, m=10, fluid={'water': 1}) - c2.set_attr(p=0.1) - - my_plant.solve(mode='design') - my_plant.print_results() +.. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_3] + :end-before: [sec_4] After running the simulation, for example, we can observe the temperature differences at the condenser. Instead of directly setting a pressure value for @@ -109,13 +70,10 @@ water return flow temperature. respective seciton of the API documentation. For example, the condenser :py:class:`tespy.components.heat_exchangers.condenser.Condenser`. -.. code-block:: python - - mc.set_attr(ttd_u=4) - c2.set_attr(p=None) - - my_plant.solve(mode='design') - my_plant.print_results() +.. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_4] + :end-before: [sec_5] After rerunning, we will see that the condensation temperature and pressure are both automatically calculated by the specified terminal temperature value. @@ -129,21 +87,10 @@ possible to include both of the component's power values in a single electrical :py:class:`tespy.connections.bus.Bus` class, creating an instance and adding both components to the bus. -.. code-block:: python - - from tespy.connections import Bus - - powergen = Bus("electrical power output") - - powergen.add_comps( - {"comp": tu, "char": 0.97, "base": "component"}, - {"comp": fp, "char": 0.97, "base": "bus"}, - ) - - my_plant.add_busses(powergen) - - my_plant.solve(mode='design') - my_plant.print_results() +.. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_5] + :end-before: [sec_6] .. note:: @@ -169,13 +116,10 @@ turbine's electrical power production (:code:`bus value`) is lower than the You can also set the total desired power production of the system, for example replacing the mass flow specification at connection 1: -.. code-block:: python - - powergen.set_attr(P=-10e6) - c1.set_attr(m=None) - - my_plant.solve(mode='design') - my_plant.print_results() +.. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_6] + :end-before: [sec_7] Analyze Efficiency and Powergeneration ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -195,76 +139,10 @@ can disable the printout of the convergence history. .. dropdown:: Click to expand to code section - .. code-block:: python - - my_plant.set_attr(iterinfo=False) - c1.set_attr(m=20) - powergen.set_attr(P=None) - - import matplotlib.pyplot as plt - import numpy as np - - data = { - 'T_livesteam': np.linspace(450, 750, 7), - 'T_cooling': np.linspace(15, 45, 7), - 'p_livesteam': np.linspace(75, 225, 7) - } - eta = { - 'T_livesteam': [], - 'T_cooling': [], - 'p_livesteam': [] - } - power = { - 'T_livesteam': [], - 'T_cooling': [], - 'p_livesteam': [] - } - - for T in data['T_livesteam']: - c1.set_attr(T=T) - my_plant.solve('design') - eta['T_livesteam'] += [abs(powergen.P.val) / sg.Q.val * 100] - power['T_livesteam'] += [abs(powergen.P.val) / 1e6] - - # reset to base temperature - c1.set_attr(T=600) - - for T in data['T_cooling']: - c12.set_attr(T=T) - c11.set_attr(T=T - 10) - my_plant.solve('design') - eta['T_cooling'] += [abs(powergen.P.val) / sg.Q.val * 100] - power['T_cooling'] += [abs(powergen.P.val) / 1e6] - - # reset to base temperature - c12.set_attr(T=30) - c11.set_attr(T=20) - - for p in data['p_livesteam']: - c1.set_attr(p=p) - my_plant.solve('design') - eta['p_livesteam'] += [abs(powergen.P.val) / sg.Q.val * 100] - power['p_livesteam'] += [abs(powergen.P.val) / 1e6] - - - fig, ax = plt.subplots(2, 3, figsize=(16, 8), sharex='col', sharey='row') - - ax = ax.flatten() - [a.grid() for a in ax.flatten()] - - i = 0 - for key in data: - ax[i].scatter(data[key], eta[key]) - ax[i + 3].scatter(data[key], power[key]) - i += 1 - - ax[0].set_ylabel('Efficiency of the rankine cycle in %') - ax[3].set_ylabel('Power of the rankine cycle in MW') - ax[3].set_xlabel('Live steam temperature in °C') - ax[4].set_xlabel('Feed water temperature in °C') - ax[5].set_xlabel('Live steam pressure in bar') - plt.tight_layout() - fig.savefig('rankine_parametric.svg') + .. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_7] + :end-before: [sec_8] .. figure:: /_static/images/basics/rankine_parametric.svg :align: center @@ -318,6 +196,38 @@ With these specifications, the following physics are applied to the model: complex, since a lot more parameters are involved compared to the other equations applied. -.. code-block:: python +In order to apply these specifications, we can use the :code:`design` and +:code:`offdesign` keywords. The keyword :code:`design` unsets the specified +data in the list in an offdesign calculation. The keyword :code:`offdesign` +automatically sets the respective parameter for the offdesign calculation. In +case the specification refers to a value, the value is taken from the design +mode calculation. In the example, the main condenser's kA value is calculated +in the design simulation and its value will be kept constant through the +offdesign simulations. + +.. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_8] + :end-before: [sec_9] + +We have to save the design state of the network and run the :code:`solve` +method with the :code:`design_path` specified. + +.. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_9] + :end-before: [sec_10] + +Finally, we can alter the mass flow from its design value of 20 kg/s to only +50 % of its value. In this example, we calculate the efficiency and plot it. + +.. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_10] + :end-before: [sec_11] + +.. figure:: /_static/images/basics/rankine_partload.svg + :align: center + :alt: Partload electric efficiency of the rankine cycle - some code + Figure: Partload electric efficiency of the rankine cycle diff --git a/tutorial/basics/rankine.py b/tutorial/basics/rankine.py new file mode 100755 index 000000000..56f497228 --- /dev/null +++ b/tutorial/basics/rankine.py @@ -0,0 +1,180 @@ +# [sec_1] +from pydoc import describe +from tkinter.tix import DECREASING +from tespy.networks import Network + +# create a network object with R134a as fluid +fluid_list = ['water'] +my_plant = Network(fluids=fluid_list) +my_plant.set_attr(T_unit='C', p_unit='bar', h_unit='kJ / kg') +# [sec_2] +from tespy.components import ( + CycleCloser, Pump, Condenser, Turbine, HeatExchangerSimple, Source, Sink +) + +cc = CycleCloser('cycle closer') +sg = HeatExchangerSimple('steam generator') +mc = Condenser('main condenser') +tu = Turbine('steam turbine') +fp = Pump('feed pump') + +cwso = Source('cooling water source') +cwsi = Sink('cooling water sink') + +from tespy.connections import Connection + +c1 = Connection(cc, 'out1', tu, 'in1', label='1') +c2 = Connection(tu, 'out1', mc, 'in1', label='2') +c3 = Connection(mc, 'out1', fp, 'in1', label='3') +c4 = Connection(fp, 'out1', sg, 'in1', label='4') +c0 = Connection(sg, 'out1', cc, 'in1', label='0') + +my_plant.add_conns(c1, c2, c3, c4, c0) + +c11 = Connection(cwso, 'out1', mc, 'in2', label='11') +c12 = Connection(mc, 'out2', cwsi, 'in1', label='12') + +my_plant.add_conns(c11, c12) +# [sec_3] +mc.set_attr(pr1=1, pr2=0.98) +sg.set_attr(pr=0.9) +tu.set_attr(eta_s=0.9) +fp.set_attr(eta_s=0.75) + +c11.set_attr(T=20, p=1.2, fluid={'water': 1}) +c12.set_attr(T=30) +c1.set_attr(T=600, p=150, m=10, fluid={'water': 1}) +c2.set_attr(p=0.1) + +my_plant.solve(mode='design') +my_plant.print_results() +# [sec_4] +mc.set_attr(ttd_u=4) +c2.set_attr(p=None) + +my_plant.solve(mode='design') +my_plant.print_results() +# [sec_5] +from tespy.connections import Bus + +powergen = Bus("electrical power output") + +powergen.add_comps( + {"comp": tu, "char": 0.97, "base": "component"}, + {"comp": fp, "char": 0.97, "base": "bus"}, +) + +my_plant.add_busses(powergen) + +my_plant.solve(mode='design') +my_plant.print_results() +# [sec_6] +powergen.set_attr(P=-10e6) +c1.set_attr(m=None) + +my_plant.solve(mode='design') +my_plant.print_results() +# [sec_7] +my_plant.set_attr(iterinfo=False) +c1.set_attr(m=20) +powergen.set_attr(P=None) +import matplotlib.pyplot as plt +import numpy as np + +# make text reasonably sized +plt.rc('font', **{'size': 18}) + +data = { + 'T_livesteam': np.linspace(450, 750, 7), + 'T_cooling': np.linspace(15, 45, 7), + 'p_livesteam': np.linspace(75, 225, 7) +} +eta = { + 'T_livesteam': [], + 'T_cooling': [], + 'p_livesteam': [] +} +power = { + 'T_livesteam': [], + 'T_cooling': [], + 'p_livesteam': [] +} + +for T in data['T_livesteam']: + c1.set_attr(T=T) + my_plant.solve('design') + eta['T_livesteam'] += [abs(powergen.P.val) / sg.Q.val * 100] + power['T_livesteam'] += [abs(powergen.P.val) / 1e6] + +# reset to base temperature +c1.set_attr(T=600) + +for T in data['T_cooling']: + c12.set_attr(T=T) + c11.set_attr(T=T - 10) + my_plant.solve('design') + eta['T_cooling'] += [abs(powergen.P.val) / sg.Q.val * 100] + power['T_cooling'] += [abs(powergen.P.val) / 1e6] + +# reset to base temperature +c12.set_attr(T=30) +c11.set_attr(T=20) + +for p in data['p_livesteam']: + c1.set_attr(p=p) + my_plant.solve('design') + eta['p_livesteam'] += [abs(powergen.P.val) / sg.Q.val * 100] + power['p_livesteam'] += [abs(powergen.P.val) / 1e6] + +# reset to base pressure +c1.set_attr(p=150) + + +fig, ax = plt.subplots(2, 3, figsize=(16, 8), sharex='col', sharey='row') + +ax = ax.flatten() +[a.grid() for a in ax.flatten()] + +i = 0 +for key in data: + ax[i].scatter(data[key], eta[key], s=100, color="#1f567d") + ax[i + 3].scatter(data[key], power[key], s=100, color="#18a999") + i += 1 + +ax[0].set_ylabel('Efficiency in %') +ax[3].set_ylabel('Power in MW') +ax[3].set_xlabel('Live steam temperature in °C') +ax[4].set_xlabel('Feed water temperature in °C') +ax[5].set_xlabel('Live steam pressure in bar') +plt.tight_layout() +fig.savefig('rankine_parametric.svg') +plt.close() +# [sec_8] +mc.set_attr(design=["ttd_u"], offdesign=["kA"]) +c11.set_attr(offdesign=["v"]) +c12.set_attr(design=["T"]) +c1.set_attr(design=["p"]) +tu.set_attr(offdesign=["cone"]) +# [sec_9] +my_plant.solve("design") +my_plant.save("rankine_design") +# [sec_10] +partload_efficiency = [] +partload_m_range = np.linspace(20, 10, 11) + +for m in partload_m_range: + c1.set_attr(m=m) + my_plant.solve("offdesign", design_path="rankine_design") + partload_efficiency += [abs(powergen.P.val) / sg.Q.val * 100] + + +fig, ax = plt.subplots(1, figsize=(16, 8)) +ax.grid() +ax.scatter(partload_m_range, partload_efficiency, s=100, color="#1f567d") +ax.set_xlabel("Mass flow in kg/s") +ax.set_ylabel("Plant electrical efficiency in %") + +plt.tight_layout() +fig.savefig('rankine_partload.svg') +plt.close() +# [sec_11] \ No newline at end of file From 7f97ded03a0a339e1478ecd557ef63a1afbc1b40 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 28 Aug 2022 18:03:40 +0200 Subject: [PATCH 060/120] Add draft notes for gas turbine basics tutorial --- docs/basics/gas_turbine.rst | 137 ++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst index eb3d0c29d..a8a027a99 100644 --- a/docs/basics/gas_turbine.rst +++ b/docs/basics/gas_turbine.rst @@ -17,14 +17,151 @@ Gas Turbine Figure: Topology of the gas turbine +This tutorial introduces a new component, the combustion chamber. You will +learn how to use the component and set up a simple open cycle gas turbine: It +compresses air and burns fuel in the combustion chamber. The hot and +pressurized flue gas expands in the turbine, which drives the compressor and +the generator. You will also learn, how to use the fluid compositon as a +variable in your simulation. Setting up the Combustion Chamber ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +We are setting up our system step by step. Especially for larger systems, it +is recommended you follow this approach, since TESPy highly relies on a set of +good starting values for good convergence. You can learn more about it in the +:ref:`advanced tutorial ` section of the online +documentation. +.. note:: + + There are two different types of combustion chambers available: + + - :py:class:`tespy.components.combustion.base.CombustionChamber` and + - :py:class:`tespy.components.combustion.diabatic.DiabaticCombustionChamber`. + + Both can handle varying fluid compositions for the air and the fuel and + calculate the fluid composition of the flue gas. Thus, it is possible to + e.g. specify the oxygen mass fraction in the flue gas in a calculation. + The difference between the components lies in the fact, that the + :code:`CombustionChamber` does **not consider heat or pressure losses**, + while :code:`DiabaticCombustionChamber` does so. + +In this tutorial, we will use the +:py:class:`tespy.components.combustion.diabatic.DiabaticCombustionChamber`. +First, we set up a network and the components. The network's fluid list must +contain all fluid components used for the combustion chamber. **These are at** +**least the fuel, oxygen, carbon-dioxide and water**. For this example we +add Nitrogen, since it is the most important fresh air component. + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_1] + :end-before: [sec_2] + +In the first step, we do not connect the inlet of the combustion chamber with +the compressor but with the air source instead. Similarly, the outlet of the +combustion chamber is directly connected to the flue gas sink. + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_2] + :end-before: [sec_3] + +There are many different specifications possible. For the combustion chamber +we will specify its air to stoichiometric air ratio lamb and the thermal input +(:math:`LHV \cdot \dot{m}_{f}`). The ambient conditions as well as the fuel +gas inlet temperature are defined in the next step. The air and the fuel gas +composition are fully be stated, the component combustion chamber can not +handle "Air" as input fluid. Then, we can run the code. + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_3] + :end-before: [sec_4] + +Of course, you can change the parametrization in any desired way. For example +instead of stating the thermal input, you could choose any of the mass flows: + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_4] + :end-before: [sec_5] + +or instead of the air to stoichiometric air ratio you could specify the flue +gas temperature. + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_5] + :end-before: [sec_6] + +It is also possible to make modifications on the fluid +composition, for example stating the oxygen content in the flue gas or to +change the fuel composition. Make sure, all desired fuels of your fuel mixture +are also within the fluid_list of the network. For the example below we added +hydrogen to the fuel mixture. + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_6] + :end-before: [sec_7] + + +.. note:: + + A warning message is prompted at the end of the simulation, if the pressure + of the inlet 2 is lower or equal to the pressure of inlet 1. + +Furthermore, we specify the efficiency +:code:`eta` of the component, which determines the heat loss as ratio of the +thermal input. :code:`eta=1` means, no heat losses, thus adiabatic behavior. +On top of that, we set the pressure ratio :code:`pr`, which describes the +ratio of the pressure at the outlet to the pressure at **the inlet 1**. The +pressure value at the inlet 2 is detached from the other pressure values, it +must be a result of a different parameter specification. In this example, we +set it directly. To match the inputs of the first tutorial, we set +:code:`pr=1` and :code:`p=1` for connection :code:`sf_comb`. + +Now, consider heat loss of the surface of the component. This is simply done by +specifying the value for :code:`eta`. We assume 4 % of thermal input as heat +loss and set that value accordingly. Furthermore, the pressure of the fuel is +set to 1.5 bar. The air inlet pressure will be the result of the specified +pressure ratio and the outlet pressure assuming 2 % pressure losses. All +other parameters stay untouched. + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_7] + :end-before: [sec_8] Setting up the Full System ^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Add remaining parts (del_conns/add_conns) + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_8] + :end-before: [sec_9] + +- Run full model +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_9] + :end-before: [sec_10] Fluid Composition Specifications ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- O2 in flue gas fraction + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_10] + :end-before: [sec_11] + +- CO2, CH4, H2 mixture, make it flexible + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_11] + :end-before: [sec_12] From 8d899272ddf0d2e01834d62105a05f9f16ca767b Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 28 Aug 2022 18:08:22 +0200 Subject: [PATCH 061/120] Add more notes to the dh basic tutorial --- docs/basics/district_heating.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/basics/district_heating.rst b/docs/basics/district_heating.rst index 70a2d02b4..a9798ac36 100644 --- a/docs/basics/district_heating.rst +++ b/docs/basics/district_heating.rst @@ -17,14 +17,20 @@ District Heating Network Figure: Topology of the district heating network +In this section we provide you with a very simple example as firsts steps in +using TESPy. The model used in this introduction is shown the figure. It +consists of a central heating plant and a consumer, represented by a heat +exchanger with a control valve. Setting up the System ^^^^^^^^^^^^^^^^^^^^^ -Calculate Heat Losses +Fixed Pipe Dimensions ^^^^^^^^^^^^^^^^^^^^^ +- Set pipe parameters, calculate heat loss and pressure loss - -Calculate Pipe Characteristics -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Calculate Pipe Dimensions +^^^^^^^^^^^^^^^^^^^^^^^^^ +- Set pipe length, pressure loss, calculate diameter +- Set max temperature change per length, calculate kA -> data for insulation From f06725e49730dd8e853a8dc6a65f6a57ed132c23 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 29 Aug 2022 20:06:01 +0200 Subject: [PATCH 062/120] Add second gas turbine section --- .../images/basics/gas_turbine_power.svg | 1504 +++++++++++++++++ docs/basics/gas_turbine.rst | 89 +- docs/tutorials.rst | 1 + tutorial/basics/gas_turbine.py | 141 ++ tutorial/basics/rankine.py | 2 +- 5 files changed, 1703 insertions(+), 34 deletions(-) create mode 100644 docs/_static/images/basics/gas_turbine_power.svg create mode 100755 tutorial/basics/gas_turbine.py diff --git a/docs/_static/images/basics/gas_turbine_power.svg b/docs/_static/images/basics/gas_turbine_power.svg new file mode 100644 index 000000000..a10cb4ad5 --- /dev/null +++ b/docs/_static/images/basics/gas_turbine_power.svg @@ -0,0 +1,1504 @@ + + + + + + + + 2022-08-29T20:02:09.486974 + image/svg+xml + + + Matplotlib v3.4.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst index a8a027a99..502e66dec 100644 --- a/docs/basics/gas_turbine.rst +++ b/docs/basics/gas_turbine.rst @@ -69,10 +69,22 @@ combustion chamber is directly connected to the flue gas sink. There are many different specifications possible. For the combustion chamber we will specify its air to stoichiometric air ratio lamb and the thermal input -(:math:`LHV \cdot \dot{m}_{f}`). The ambient conditions as well as the fuel -gas inlet temperature are defined in the next step. The air and the fuel gas -composition are fully be stated, the component combustion chamber can not -handle "Air" as input fluid. Then, we can run the code. +(:math:`LHV \cdot \dot{m}_{f}`). + +Furthermore, we specify the efficiency :code:`eta` of the component, which +determines the heat loss as ratio of the thermal input. :code:`eta=1` means, +no heat losses, thus adiabatic behavior. + +The pressure ratio :code:`pr` describes the ratio of the pressure at the +outlet to the pressure at **the inlet 1**. The pressure value at the inlet 2 +is detached from the other pressure values, it must be a result of a different +parameter specification. In this example, we set it directly. Initially, we +assume adiabatic behavior :code:`eta=1` and no pressure losses :code:`pr=1`. + +The ambient conditions as well as the fuel gas inlet temperature are defined +in the next step. The full vector for the air and the fuel gas composition +have to be defined. The component can not handle "Air" as input fluid. We can +run the code after the specifications. .. literalinclude:: /../tutorial/basics/gas_turbine.py :language: python @@ -95,61 +107,72 @@ gas temperature. :start-after: [sec_5] :end-before: [sec_6] -It is also possible to make modifications on the fluid -composition, for example stating the oxygen content in the flue gas or to -change the fuel composition. Make sure, all desired fuels of your fuel mixture -are also within the fluid_list of the network. For the example below we added -hydrogen to the fuel mixture. +It is also possible to make modifications on the fluid composition, for +example, we can add hydrogen to the fuel mixture. .. literalinclude:: /../tutorial/basics/gas_turbine.py :language: python :start-after: [sec_6] :end-before: [sec_7] - -.. note:: - - A warning message is prompted at the end of the simulation, if the pressure - of the inlet 2 is lower or equal to the pressure of inlet 1. - -Furthermore, we specify the efficiency -:code:`eta` of the component, which determines the heat loss as ratio of the -thermal input. :code:`eta=1` means, no heat losses, thus adiabatic behavior. -On top of that, we set the pressure ratio :code:`pr`, which describes the -ratio of the pressure at the outlet to the pressure at **the inlet 1**. The -pressure value at the inlet 2 is detached from the other pressure values, it -must be a result of a different parameter specification. In this example, we -set it directly. To match the inputs of the first tutorial, we set -:code:`pr=1` and :code:`p=1` for connection :code:`sf_comb`. - -Now, consider heat loss of the surface of the component. This is simply done by -specifying the value for :code:`eta`. We assume 4 % of thermal input as heat -loss and set that value accordingly. Furthermore, the pressure of the fuel is -set to 1.5 bar. The air inlet pressure will be the result of the specified -pressure ratio and the outlet pressure assuming 2 % pressure losses. All -other parameters stay untouched. +The most convenient way to access the fluid composition is to access the +results dataframe for the connections. .. literalinclude:: /../tutorial/basics/gas_turbine.py :language: python :start-after: [sec_7] :end-before: [sec_8] +.. note:: + + All component and connection results are available in the :code:`results` + dict of the :code:`Network` instance. The keys of the dictionary are the + respective class names. + Setting up the Full System ^^^^^^^^^^^^^^^^^^^^^^^^^^ -- Add remaining parts (del_conns/add_conns) +After learning more about the component, we are going to add the remaining +components: The turbine, the compressor and the generator. To do that, remove +the existing connections from the network, create the new connections and +add them to the network again. We also add a :code:`Bus` representing the +generator, assuming 98 % mechanical-electrical efficiency. .. literalinclude:: /../tutorial/basics/gas_turbine.py :language: python :start-after: [sec_8] :end-before: [sec_9] -- Run full model +Since we deleted the connection 2 and 3, all specifications for those +connections have to be added again. The air fluid composition is specified on +connection 1 with ambient pressure and temperature. The pressure after the +compressor is set to 10 bar, the turbine inlet temperature to 1400 °C. Finally, +set the gas turbine outlet pressure to ambient pressure as well as the +compressor's and turbine's efficiency. .. literalinclude:: /../tutorial/basics/gas_turbine.py :language: python :start-after: [sec_9] :end-before: [sec_10] +Note, that the pressure of the fuel is lower than the pressure of the air at +the combustion chamber as we did not change the pressure of connection 5. A +respective warning is printed after the calculation. We can fix it like so: + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_10] + :end-before: [sec_11] + +Now, we can investigate, how the efficiency value and the pressure loss at +the combustion chamber change the total power generated: + +.. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_11] + :end-before: [sec_12] + + + Fluid Composition Specifications ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - O2 in flue gas fraction diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 1acf9f042..750d1e080 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -20,6 +20,7 @@ an optimization problem, which optimizes thermal efficiency of a clausius rankine power plant. - CGAM! +- Larger dh system .. toctree:: :maxdepth: 1 diff --git a/tutorial/basics/gas_turbine.py b/tutorial/basics/gas_turbine.py new file mode 100755 index 000000000..6f0dbc365 --- /dev/null +++ b/tutorial/basics/gas_turbine.py @@ -0,0 +1,141 @@ +# [sec_1] +from tespy.networks import Network +from tespy.components import ( + DiabaticCombustionChamber, Turbine, Source, Sink, Compressor +) +from tespy.connections import Connection, Ref, Bus + +# define full fluid list for the network"s variable space +fluid_list = ["Ar", "N2", "O2", "CO2", "CH4", "H2O", "H2"] +nw = Network(fluids=fluid_list, p_unit="bar", T_unit="C") + +cp = Compressor("Compressor") +cc = DiabaticCombustionChamber("combustion chamber") +tu = Turbine("turbine") +air = Source("air source") +fuel = Source("fuel source") +fg = Sink("flue gas sink") +# [sec_2] +c2 = Connection(air, "out1", cc, "in1", label="2") +c3 = Connection(cc, "out1", fg, "in1", label="3") +c5 = Connection(fuel, "out1", cc, "in2", label="5") +nw.add_conns(c2, c3, c5) +# [sec_3] +cc.set_attr(pr=1, eta=1, lamb=1.5, ti=10e6) + +c2.set_attr( + p=1, T=20, + fluid={ + "Ar": 0.0129, "N2": 0.7553, "H2O": 0, + "CH4": 0, "CO2": 0.0004, "O2": 0.2314, "H2": 0 + } +) +c5.set_attr( + p=1, T=20, + fluid={ + "CO2": 0.04, "Ar": 0, "N2": 0, "O2": 0, + "H2O": 0, "CH4": 0.96, "H2": 0 + } +) + +nw.solve(mode="design") +nw.print_results() +# [sec_4] +cc.set_attr(ti=None) +c5.set_attr(m=1) +nw.solve(mode="design") +# [sec_5] +cc.set_attr(lamb=None) +c3.set_attr(T=1400) +nw.solve(mode="design") +# [sec_6] +c5.set_attr( + fluid={ + "CO2": 0.03, "Ar": 0, "N2": 0, "O2": 0, + "H2O": 0, "CH4": 0.92, "H2": 0.05 + } +) +nw.solve(mode="design") +# [sec_7] +print(nw.results["Connection"]) +# [sec_8] +nw.del_conns(c2, c3) +c1 = Connection(air, "out1", cp, "in1", label="1") +c2 = Connection(cp, "out1", cc, "in1", label="2") +c3 = Connection(cc, "out1", tu, "in1", label="3") +c4 = Connection(tu, "out1", fg, "in1", label="4") +nw.add_conns(c1, c2, c3, c4) + +generator = Bus("generator") +generator.add_comps( + {"comp": tu, "char": 0.98, "base": "component"}, + {"comp": cp, "char": 0.98, "base": "bus"}, +) +nw.add_busses(generator) +# [sec_9] +cp.set_attr(eta_s=0.85) +tu.set_attr(eta_s=0.90) +c1.set_attr( + p=1, T=20, + fluid={ + "Ar": 0.0129, "N2": 0.7553, "H2O": 0, + "CH4": 0, "CO2": 0.0004, "O2": 0.2314, "H2": 0 + } +) +c2.set_attr(p=10) +c3.set_attr(T=1400) +c4.set_attr(p=Ref(c1, 1, 0)) +nw.solve("design") +nw.print_results() +# [sec_10] +c5.set_attr(p=10.1) +nw.solve("design") +# [sec_11] +nw.set_attr(iterinfo=False) +import matplotlib.pyplot as plt +import numpy as np + +# make text reasonably sized +plt.rc('font', **{'size': 18}) + +data = { + 'eta': np.linspace(0.9, 1.0, 11) * 100, + 'pr': np.linspace(0.0, 0.1, 11) * 100 +} +power = { + 'eta': [], + 'pr': [] +} + +for eta in data['eta']: + cc.set_attr(eta=eta / 100) + nw.solve('design') + power['eta'] += [abs(generator.P.val) / 1e6] + +# reset to base value +cc.set_attr(eta=0.98) + +for pr in data['pr']: + cc.set_attr(pr=1 - (pr / 100)) + nw.solve('design') + power['pr'] += [abs(generator.P.val) / 1e6] + +# reset to base value +cc.set_attr(pr=0.96) + +fig, ax = plt.subplots(1, 2, figsize=(16, 8), sharey=True) + +[a.grid() for a in ax] + +i = 0 +for key in data: + ax[i].scatter(data[key], power[key], s=100, color="#1f567d") + i += 1 + +ax[0].set_ylabel('Power in MW') +ax[0].set_xlabel('Combustion chamber efficiency in %') +ax[1].set_xlabel('Combustion chamber pressure loss in %') +plt.tight_layout() +fig.savefig('gas_turbine_power.svg') +plt.close() +# [sec_12] \ No newline at end of file diff --git a/tutorial/basics/rankine.py b/tutorial/basics/rankine.py index 56f497228..67904d221 100755 --- a/tutorial/basics/rankine.py +++ b/tutorial/basics/rankine.py @@ -133,7 +133,7 @@ fig, ax = plt.subplots(2, 3, figsize=(16, 8), sharex='col', sharey='row') ax = ax.flatten() -[a.grid() for a in ax.flatten()] +[a.grid() for a in ax] i = 0 for key in data: From d35ab344f88186f93b98c1c947116d5733aa91c8 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 29 Aug 2022 20:06:20 +0200 Subject: [PATCH 063/120] Include figure --- docs/basics/gas_turbine.rst | 5 +++++ src/tespy/components/combustion/diabatic.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst index 502e66dec..bb08065ac 100644 --- a/docs/basics/gas_turbine.rst +++ b/docs/basics/gas_turbine.rst @@ -171,7 +171,12 @@ the combustion chamber change the total power generated: :start-after: [sec_11] :end-before: [sec_12] +.. figure:: /_static/images/basics/gas_turbine_power.svg + :align: center + :alt: Gas turbine performance at different pressure losses and efficiency of the combustion chamber. + Figure: Gas turbine performance at different pressure losses and + efficiency of the combustion chamber. Fluid Composition Specifications ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tespy/components/combustion/diabatic.py b/src/tespy/components/combustion/diabatic.py index 41c0ae0aa..7e57b7e57 100644 --- a/src/tespy/components/combustion/diabatic.py +++ b/src/tespy/components/combustion/diabatic.py @@ -189,7 +189,7 @@ def get_variables(self): max_val=1, min_val=0, deriv=self.energy_balance_deriv, func=self.energy_balance_func, latex=self.energy_balance_func_doc, num_eq=1), - 'Q_loss': dc_cp(max_val=0) + 'Q_loss': dc_cp(max_val=0, is_result=True) } def get_mandatory_constraints(self): From e03822397c3da0488f23b170d88d7710b1a88a5e Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 30 Aug 2022 21:39:30 +0200 Subject: [PATCH 064/120] Finalize gas turbine basic tutorial --- .../basics/gas_turbine_fuel_composition.svg | 1135 ++++++++++ .../images/basics/gas_turbine_oxygen.svg | 1100 ++++++++++ .../images/basics/gas_turbine_parametric.svg | 1903 +++++++++++++++++ .../images/basics/gas_turbine_power.svg | 1504 ------------- docs/basics/gas_turbine.rst | 86 +- tutorial/basics/gas_turbine.py | 111 +- 6 files changed, 4292 insertions(+), 1547 deletions(-) create mode 100644 docs/_static/images/basics/gas_turbine_fuel_composition.svg create mode 100644 docs/_static/images/basics/gas_turbine_oxygen.svg create mode 100644 docs/_static/images/basics/gas_turbine_parametric.svg delete mode 100644 docs/_static/images/basics/gas_turbine_power.svg diff --git a/docs/_static/images/basics/gas_turbine_fuel_composition.svg b/docs/_static/images/basics/gas_turbine_fuel_composition.svg new file mode 100644 index 000000000..71fa354b8 --- /dev/null +++ b/docs/_static/images/basics/gas_turbine_fuel_composition.svg @@ -0,0 +1,1135 @@ + + + + + + + + 2022-08-30T21:38:50.684785 + image/svg+xml + + + Matplotlib v3.4.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/gas_turbine_oxygen.svg b/docs/_static/images/basics/gas_turbine_oxygen.svg new file mode 100644 index 000000000..8bf5af372 --- /dev/null +++ b/docs/_static/images/basics/gas_turbine_oxygen.svg @@ -0,0 +1,1100 @@ + + + + + + + + 2022-08-30T21:38:39.150003 + image/svg+xml + + + Matplotlib v3.4.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/gas_turbine_parametric.svg b/docs/_static/images/basics/gas_turbine_parametric.svg new file mode 100644 index 000000000..1b5f35181 --- /dev/null +++ b/docs/_static/images/basics/gas_turbine_parametric.svg @@ -0,0 +1,1903 @@ + + + + + + + + 2022-08-30T21:38:36.540618 + image/svg+xml + + + Matplotlib v3.4.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/gas_turbine_power.svg b/docs/_static/images/basics/gas_turbine_power.svg deleted file mode 100644 index a10cb4ad5..000000000 --- a/docs/_static/images/basics/gas_turbine_power.svg +++ /dev/null @@ -1,1504 +0,0 @@ - - - - - - - - 2022-08-29T20:02:09.486974 - image/svg+xml - - - Matplotlib v3.4.2, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst index bb08065ac..1efcd5ecd 100644 --- a/docs/basics/gas_turbine.rst +++ b/docs/basics/gas_turbine.rst @@ -144,9 +144,9 @@ generator, assuming 98 % mechanical-electrical efficiency. Since we deleted the connection 2 and 3, all specifications for those connections have to be added again. The air fluid composition is specified on -connection 1 with ambient pressure and temperature. The pressure after the -compressor is set to 10 bar, the turbine inlet temperature to 1400 °C. Finally, -set the gas turbine outlet pressure to ambient pressure as well as the +connection 1 with ambient pressure and temperature. The compressor pressure +ratio is set to 15 bar, the turbine inlet temperature to 1200 °C. Finally, set +the gas turbine outlet pressure to ambient pressure as well as the compressor's and turbine's efficiency. .. literalinclude:: /../tutorial/basics/gas_turbine.py @@ -163,33 +163,73 @@ respective warning is printed after the calculation. We can fix it like so: :start-after: [sec_10] :end-before: [sec_11] -Now, we can investigate, how the efficiency value and the pressure loss at -the combustion chamber change the total power generated: +We can investigate, how the turbine inlet temperature and the compressor +pressure ratio affect thermal efficiency and power generation. Also, we +assume 2 % heat losses and 3 % pressure losses in the combustion chamber. -.. literalinclude:: /../tutorial/basics/gas_turbine.py - :language: python - :start-after: [sec_11] - :end-before: [sec_12] +.. dropdown:: Click to expand to code section + + .. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_11] + :end-before: [sec_12] -.. figure:: /_static/images/basics/gas_turbine_power.svg +.. figure:: /_static/images/basics/gas_turbine_parametric.svg :align: center - :alt: Gas turbine performance at different pressure losses and efficiency of the combustion chamber. + :alt: Gas turbine performance at different compressor pressure ratios and turbine inlet temperatures - Figure: Gas turbine performance at different pressure losses and - efficiency of the combustion chamber. + Figure: Gas turbine performance at different compressor pressure ratios + and turbine inlet temperatures. Fluid Composition Specifications ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- O2 in flue gas fraction +In this section you will learn how the fluid composition can be used as a +variable in such systems. To begin, we can impose the oxygen mass fraction on +the flue gas instead of the turbine inlet pressure, since it determines the +share of oxygen that is not required in the combustion. We can see, how the +turbine inlet temperature correlates with the oxygen mass fraction. -.. literalinclude:: /../tutorial/basics/gas_turbine.py - :language: python - :start-after: [sec_10] - :end-before: [sec_11] +.. dropdown:: Click to expand to code section -- CO2, CH4, H2 mixture, make it flexible + .. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_12] + :end-before: [sec_13] -.. literalinclude:: /../tutorial/basics/gas_turbine.py - :language: python - :start-after: [sec_11] - :end-before: [sec_12] +.. figure:: /_static/images/basics/gas_turbine_oxygen.svg + :align: center + :alt: Turbine inlet temperature at different levels of oxygen in the flue gas + + Figure: Turbine inlet temperature at different levels of oxygen in the + flue gas. + +Let us now assume, we do have an unknown shares of hydrogen and methane within +our fuel mixture. With the known mass flow of the fuel and an overall thermal +input, we can calculate both fractions by removing their respective values +from the input parameters and using the :code:`fluid_balance` keyword instead, +which automatically calculates the sum of all fluid mass fractions to be 1. + +Investigate how changing the thermal input requires a different mixture of +hydrogen and methane. + +.. attention:: + + With this setup, a thermal input below the lower heating value of methane + or above the lower heating value of hydrogen (each multiplied with the + mass flow of 1 kg/s) does not make sense as input specification. This is + individual of every fluid you use as fuel and you cannot easily abstract + the values to any other combination. + +.. dropdown:: Click to expand to code section + + .. literalinclude:: /../tutorial/basics/gas_turbine.py + :language: python + :start-after: [sec_13] + :end-before: [sec_14] + +.. figure:: /_static/images/basics/gas_turbine_fuel_composition.svg + :align: center + :alt: Mass fractions of H2 and CH4 in fuel mixture at different thermal input + + Figure: Mass fractions of H2 and CH4 in fuel mixture at varying thermal + input and constant fuel mass flow. diff --git a/tutorial/basics/gas_turbine.py b/tutorial/basics/gas_turbine.py index 6f0dbc365..bfadb0509 100755 --- a/tutorial/basics/gas_turbine.py +++ b/tutorial/basics/gas_turbine.py @@ -73,7 +73,7 @@ ) nw.add_busses(generator) # [sec_9] -cp.set_attr(eta_s=0.85) +cp.set_attr(eta_s=0.85, pr=15) tu.set_attr(eta_s=0.90) c1.set_attr( p=1, T=20, @@ -82,15 +82,17 @@ "CH4": 0, "CO2": 0.0004, "O2": 0.2314, "H2": 0 } ) -c2.set_attr(p=10) -c3.set_attr(T=1400) +c3.set_attr(T=1200) c4.set_attr(p=Ref(c1, 1, 0)) nw.solve("design") nw.print_results() # [sec_10] -c5.set_attr(p=10.1) +# unset the value, impose Referenced value instead +c5.set_attr(p=None) +c5.set_attr(p=Ref(c2, 1.05, 0)) nw.solve("design") # [sec_11] +cc.set_attr(pr=0.97, eta=0.98) nw.set_attr(iterinfo=False) import matplotlib.pyplot as plt import numpy as np @@ -99,43 +101,112 @@ plt.rc('font', **{'size': 18}) data = { - 'eta': np.linspace(0.9, 1.0, 11) * 100, - 'pr': np.linspace(0.0, 0.1, 11) * 100 + 'T_3': np.linspace(900, 1400, 11), + 'pr': np.linspace(10, 30, 11) } power = { - 'eta': [], + 'T_3': [], + 'pr': [] +} +eta = { + 'T_3': [], 'pr': [] } -for eta in data['eta']: - cc.set_attr(eta=eta / 100) +for T in data['T_3']: + c3.set_attr(T=T) nw.solve('design') - power['eta'] += [abs(generator.P.val) / 1e6] + power['T_3'] += [abs(generator.P.val) / 1e6] + eta['T_3'] += [abs(generator.P.val) / cc.ti.val * 100] # reset to base value -cc.set_attr(eta=0.98) +c3.set_attr(T=1200) for pr in data['pr']: - cc.set_attr(pr=1 - (pr / 100)) + cp.set_attr(pr=pr) nw.solve('design') power['pr'] += [abs(generator.P.val) / 1e6] + eta['pr'] += [abs(generator.P.val) / cc.ti.val * 100] # reset to base value -cc.set_attr(pr=0.96) +cp.set_attr(pr=15) -fig, ax = plt.subplots(1, 2, figsize=(16, 8), sharey=True) +fig, ax = plt.subplots(2, 2, figsize=(16, 8), sharex='col', sharey='row') +ax = ax.flatten() [a.grid() for a in ax] i = 0 for key in data: - ax[i].scatter(data[key], power[key], s=100, color="#1f567d") + ax[i].scatter(data[key], eta[key], s=100, color="#1f567d") + ax[i + 2].scatter(data[key], power[key], s=100, color="#18a999") i += 1 -ax[0].set_ylabel('Power in MW') -ax[0].set_xlabel('Combustion chamber efficiency in %') -ax[1].set_xlabel('Combustion chamber pressure loss in %') +ax[0].set_ylabel('Efficiency in %') +ax[2].set_ylabel('Power in MW') +ax[2].set_xlabel('Turbine inlet temperature °C') +ax[3].set_xlabel('Compressure pressure ratio') + +plt.tight_layout() +fig.savefig('gas_turbine_parametric.svg') +plt.close() +# [sec_12] +c3.set_attr(T=None) + + +data = np.linspace(0.025, 0.15, 6) + +T3 = [] + +for oxy in data[::-1]: + c3.set_attr(fluid={"O2": oxy}) + nw.solve('design') + T3 += [c3.T.val] + +# reset to base value +c3.fluid.val_set["O2"] = False +c3.set_attr(T=1200) + +fig, ax = plt.subplots(1, figsize=(16, 8)) + +ax.scatter(data * 100, T3, s=100, color="#1f567d") +ax.grid() + +ax.set_ylabel('Turbine inlet temperature in °C') +ax.set_xlabel('Oxygen mass fraction in flue gas in %') + +plt.tight_layout() +fig.savefig('gas_turbine_oxygen.svg') +plt.close() +# [sec_13] +# retain starting values for CH4 and H2 with this variant +c5.fluid.val_set["CH4"] = False +c5.fluid.val_set["H2"] = False +c5.set_attr(fluid_balance=True) + +data = np.linspace(50, 60, 11) + +CH4 = [] +H2 = [] + +for ti in data: + cc.set_attr(ti=ti * 1e6) + nw.solve('design') + CH4 += [c5.fluid.val["CH4"] * 100] + H2 += [c5.fluid.val["H2"] * 100] + +fig, ax = plt.subplots(1, figsize=(16, 8)) + +ax.scatter(data, CH4, s=100, color="#1f567d", label="CH4 mass fraction") +ax.scatter(data, H2, s=100, color="#18a999", label="H2 mass fraction") +ax.grid() +ax.legend() + +ax.set_ylabel('Mass fraction of the fuel in %') +ax.set_xlabel('Thermal input in MW') +ax.set_ybound([0, 100]) + plt.tight_layout() -fig.savefig('gas_turbine_power.svg') +fig.savefig('gas_turbine_fuel_composition.svg') plt.close() -# [sec_12] \ No newline at end of file +# [sec_14] From f93870a3957d6b0915fd28dd99b207e70bc50a09 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 30 Aug 2022 21:45:16 +0200 Subject: [PATCH 065/120] Fix some typos --- docs/development/how.rst | 2 +- docs/development/what.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/development/how.rst b/docs/development/how.rst index 37c0cf3cd..f7b1c388c 100644 --- a/docs/development/how.rst +++ b/docs/development/how.rst @@ -17,7 +17,7 @@ repository and install development requirements with pip. .. code:: bash - git clone https://github.com/YOUR_GITHUB_USERNAME/tespy.git + git clone https://github.com/YOUR_GITHUB_USERNAME/tespy.git cd tespy pip install -e .[dev] diff --git a/docs/development/what.rst b/docs/development/what.rst index 8b0a36b7b..1e60844cb 100644 --- a/docs/development/what.rst +++ b/docs/development/what.rst @@ -52,5 +52,5 @@ coefficients etc.. The component characteristics represent large added value for your calculation. If you have detailed information on components offdesign behavior - even for specific cases - it will improve the results. Every user can benefit from this -knowlegde and thus we are very happy to discuss about the implementation of new +knowledge and thus we are very happy to discuss about the implementation of new characteristics. From cd6087e59400a9d8debf2ba31d9da60ad688ab45 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 30 Aug 2022 22:12:15 +0200 Subject: [PATCH 066/120] Remove unused imports --- tutorial/basics/rankine.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tutorial/basics/rankine.py b/tutorial/basics/rankine.py index 67904d221..fd1dc8173 100755 --- a/tutorial/basics/rankine.py +++ b/tutorial/basics/rankine.py @@ -1,6 +1,4 @@ # [sec_1] -from pydoc import describe -from tkinter.tix import DECREASING from tespy.networks import Network # create a network object with R134a as fluid From 60b80fc2287c08e3b80d4e8f72442721db798747 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 31 Aug 2022 21:28:53 +0200 Subject: [PATCH 067/120] Finish heating system basic tutorial --- .../images/basics/district_heating.svg | 127 +- .../basics/district_heating_darkmode.svg | 177 +- .../basics/district_heating_partload.svg | 2292 +++++++++++++++++ docs/basics/district_heating.rst | 110 +- docs/basics/gas_turbine.rst | 6 +- tutorial/basics/district_heating.py | 147 ++ tutorial/basics/rankine.py | 2 +- 7 files changed, 2715 insertions(+), 146 deletions(-) create mode 100644 docs/_static/images/basics/district_heating_partload.svg create mode 100755 tutorial/basics/district_heating.py diff --git a/docs/_static/images/basics/district_heating.svg b/docs/_static/images/basics/district_heating.svg index a44f4990f..893635671 100644 --- a/docs/_static/images/basics/district_heating.svg +++ b/docs/_static/images/basics/district_heating.svg @@ -1,23 +1,22 @@ + viewBox="0 0 150.19051 84.269693" + height="84.269691mm" + width="150.19051mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + inkscape:bbox-paths="false" + inkscape:snap-object-midpoints="true"> + originx="-61.999997" + originy="-32.639067" /> @@ -103,7 +103,6 @@ image/svg+xml - @@ -111,7 +110,7 @@ id="layer1" inkscape:groupmode="layer" inkscape:label="Ebene 1" - transform="translate(-62.09365,-32.614957)"> + transform="translate(-61.99998,-32.639073)"> + + + + d="m 74.999983,85.000005 v 9" + id="path984-0-9-9-9-7-0-1-5-0-8-4-7-5-5" /> + + - feed pump sink - source + y="81.84124" + x="85.355713" + id="tspan1023-6-9-1-6-2-8-3-2-0-7" + sodipodi:role="line">heat source 1 + 0 + viewBox="0 0 150.19051 84.269693" + height="84.269691mm" + width="150.19051mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + inkscape:bbox-paths="false" + inkscape:snap-object-midpoints="true"> + originx="-61.999997" + originy="-32.639067" /> @@ -103,7 +103,6 @@ image/svg+xml - @@ -111,7 +110,7 @@ id="layer1" inkscape:groupmode="layer" inkscape:label="Ebene 1" - transform="translate(-62.09365,-32.614957)"> + transform="translate(-61.99998,-32.639073)"> + + + + d="m 74.999983,85.000005 v 9" + id="path984-0-9-9-9-7-0-1-5-0-8-4-7-5-5" /> + + - feed pump sink - source + style="stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;fill:#ffffff;fill-opacity:1" + y="81.84124" + x="85.355713" + id="tspan1023-6-9-1-6-2-8-3-2-0-7" + sodipodi:role="line">heat source 1 + style="stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;fill:#ffffff;fill-opacity:1">1 + 0 2 + style="stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;fill:#ffffff;fill-opacity:1">2 3 + style="stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;fill:#ffffff;fill-opacity:1">3 4 + style="stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;fill:#ffffff;fill-opacity:1">4 5 + style="stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;fill:#ffffff;fill-opacity:1">5 6 + style="stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;fill:#ffffff;fill-opacity:1">6 diff --git a/docs/_static/images/basics/district_heating_partload.svg b/docs/_static/images/basics/district_heating_partload.svg new file mode 100644 index 000000000..afff99f3f --- /dev/null +++ b/docs/_static/images/basics/district_heating_partload.svg @@ -0,0 +1,2292 @@ + + + + + + + + 2022-08-31T21:27:43.253372 + image/svg+xml + + + Matplotlib v3.4.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/basics/district_heating.rst b/docs/basics/district_heating.rst index a9798ac36..984e75d91 100644 --- a/docs/basics/district_heating.rst +++ b/docs/basics/district_heating.rst @@ -17,20 +17,108 @@ District Heating Network Figure: Topology of the district heating network -In this section we provide you with a very simple example as firsts steps in -using TESPy. The model used in this introduction is shown the figure. It -consists of a central heating plant and a consumer, represented by a heat -exchanger with a control valve. +The model used in this example is shown the figure. It consists of a central +heating plant and a consumer, represented by a heat exchanger with a control +valve. A much more complex district heating system is included in the +advanced tutorials section. Setting up the System ^^^^^^^^^^^^^^^^^^^^^ +For this model we have to import the :code:`Network` and :code:`Connection` +classes as well as the respective components. After setting up the network we +can create the components, connect them to the network (as shown in the other) +examples. +.. dropdown:: Click to expand to code section -Fixed Pipe Dimensions -^^^^^^^^^^^^^^^^^^^^^ -- Set pipe parameters, calculate heat loss and pressure loss + .. literalinclude:: /../tutorial/basics/district_heating.py + :language: python + :start-after: [sec_1] + :end-before: [sec_2] + +In the first step, we assume we have a specific heat demand of the consumer +and constant pressure and thermal losses in the pipes. Furthermore, the pump +produces a constant pressure at the feed part of the system. With the control +valve in place the pressure of the return part of the system is then decoupled +from that value. Therefore, we need to impose a pressure value at the sink as +well, which should be equal to the pressure at the pump's inlet. The pressure +drop in the valve will then be the residual pressure drop between the feed and +the return part of the system. Lastly, we fix the feed flow and the return +flow (at connection 4) temperature values. + +.. literalinclude:: /../tutorial/basics/district_heating.py + :language: python + :start-after: [sec_2] + :end-before: [sec_3] + +Design Pipe Dimensions +^^^^^^^^^^^^^^^^^^^^^^ +In the second step we will design the pipe's dimensions. There are two tasks +for this: + +- Calculate the necessary pipe diameter given a target pressure loss as well + as length and pipe roughness. +- Calculate the necessary insulation of the pipe based on assumptions + regarding the heat loss at a given ambient temperature value. + +For the first step, we impose lengths and roughness of the pipe and set the +diameter to :code:`"var"`, indicating the diameter of the pipe should be a +variable value in the calculation. + +.. literalinclude:: /../tutorial/basics/district_heating.py + :language: python + :start-after: [sec_3] + :end-before: [sec_4] + +In the second step we can fix the diameter to its resulting value and +therefore unset the desired pressure loss first. Then, we impose the ambient +temperature of the pipes (we assume the temperature of the ambient is not +affected by the heat loss of the pipe). With the given heat loss, the +:code:`kA` value can be calculated. It is the area independent heat transfer +coefficient. + +.. literalinclude:: /../tutorial/basics/district_heating.py + :language: python + :start-after: [sec_4] + :end-before: [sec_5] + +.. note:: + + In the results you can see, that the pipes' pressure losses are still at + the desired value after remove the pressure ration specification and using + the calculated value of the diameter instead. + +Changing Operation Conditions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Next, we want to investigate what happens, in case the + +- ambient temperature changes. +- heat load varies. +- overall temperature level in the heating system is reduced. + +To do that, we will use similar setups as show in the rankine cycle +introduction. The :code:`KA` value of both pipes is assumed to be fixed, the +efficiency of the pump and pressure losses in consumer and heat source are +constant as well. + +.. dropdown:: Click to expand to code section + + .. literalinclude:: /../tutorial/basics/district_heating.py + :language: python + :start-after: [sec_5] + :end-before: [sec_6] + +.. figure:: /_static/images/basics/district_heating_partload.svg + :align: center + :alt: Performance of the district heating system at changing operating conditions + + Figure: Performance of the district heating system at changing operating conditions. + +.. note:: + + The efficiency value is defined as ratio of the heat delivered to the + consumer to the heat production in the central heating plant. + + .. math:: -Calculate Pipe Dimensions -^^^^^^^^^^^^^^^^^^^^^^^^^ -- Set pipe length, pressure loss, calculate diameter -- Set max temperature change per length, calculate kA -> data for insulation + \eta = \frac{\dot{Q}_\text{consumer}}{\dot{Q}_\text{production}} diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst index 1efcd5ecd..872641cfb 100644 --- a/docs/basics/gas_turbine.rst +++ b/docs/basics/gas_turbine.rst @@ -179,7 +179,7 @@ assume 2 % heat losses and 3 % pressure losses in the combustion chamber. :alt: Gas turbine performance at different compressor pressure ratios and turbine inlet temperatures Figure: Gas turbine performance at different compressor pressure ratios - and turbine inlet temperatures. + and turbine inlet temperatures Fluid Composition Specifications ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -201,7 +201,7 @@ turbine inlet temperature correlates with the oxygen mass fraction. :alt: Turbine inlet temperature at different levels of oxygen in the flue gas Figure: Turbine inlet temperature at different levels of oxygen in the - flue gas. + flue gas Let us now assume, we do have an unknown shares of hydrogen and methane within our fuel mixture. With the known mass flow of the fuel and an overall thermal @@ -232,4 +232,4 @@ hydrogen and methane. :alt: Mass fractions of H2 and CH4 in fuel mixture at different thermal input Figure: Mass fractions of H2 and CH4 in fuel mixture at varying thermal - input and constant fuel mass flow. + input and constant fuel mass flow diff --git a/tutorial/basics/district_heating.py b/tutorial/basics/district_heating.py new file mode 100755 index 000000000..44efe0fb9 --- /dev/null +++ b/tutorial/basics/district_heating.py @@ -0,0 +1,147 @@ +# [sec_1] +from tespy.components.basics.cycle_closer import CycleCloser +from tespy.networks import Network +from tespy.components import ( + CycleCloser, Pipe, Pump, Valve, HeatExchangerSimple +) +from tespy.connections import Connection + +fluid_list = ['water'] +nw = Network(fluids=fluid_list) +nw.set_attr(T_unit='C', p_unit='bar', h_unit='kJ / kg') + +# central heating plant +hs = HeatExchangerSimple('heat source') +cc = CycleCloser('cycle closer') +pu = Pump('feed pump') + +# consumer +cons = HeatExchangerSimple('consumer') +val = Valve('control valve') + +# pipes +pipe_feed = Pipe('feed pipe') +pipe_return = Pipe('return pipe') + +# connections +c0 = Connection(cc, "out1", hs, "in1", label="0") +c1 = Connection(hs, "out1", pu, "in1", label="1") +c2 = Connection(pu, "out1", pipe_feed, "in1", label="2") +c3 = Connection(pipe_feed, "out1", cons, "in1", label="3") +c4 = Connection(cons, "out1", val, "in1", label="4") +c5 = Connection(val, "out1", pipe_return, "in1", label="5") +c6 = Connection(pipe_return, "out1", cc, "in1", label="6") +nw.add_conns(c0, c1, c2, c3, c4, c5, c6) +# [sec_2] +cons.set_attr(Q=-10000, pr=0.98) +hs.set_attr(pr=1) +pu.set_attr(eta_s=0.75) +pipe_feed.set_attr(Q=-250, pr=0.98) +pipe_return.set_attr(Q=-200, pr=0.98) + +c1.set_attr(T=90, p=10, fluid={'water': 1}) +c2.set_attr(p=13) +c4.set_attr(T=65) + +nw.solve(mode="design") +nw.print_results() +# [sec_3] +pipe_feed.set_attr( + ks=0.0005, # pipe's roughness in meters + L=100, # length in m + D="var", # diameter in m +) +pipe_return.set_attr( + ks=0.0005, # pipe's roughness in meters + L=100, # length in m + D="var", # diameter in m +) +nw.solve(mode="design") +nw.print_results() +# [sec_4] +pipe_feed.set_attr(D=pipe_feed.D.val, pr=None) +pipe_return.set_attr(D=pipe_return.D.val, pr=None) +pipe_feed.set_attr( + Tamb=0, # ambient temperature level in network's temperature unit + kA="var" # area independent heat transfer coefficient +) +pipe_return.set_attr( + Tamb=0, # ambient temperature level in network's temperature unit + kA="var" # area independent heat transfer coefficient +) +nw.solve(mode="design") +nw.print_results() +# [sec_5] +nw.set_attr(iterinfo=False) +pipe_feed.set_attr(Tamb=0, kA=pipe_feed.kA.val, Q=None) +pipe_return.set_attr(Tamb=0, kA=pipe_return.kA.val, Q=None) + +import matplotlib.pyplot as plt +import numpy as np + +# make text reasonably sized +plt.rc('font', **{'size': 18}) + +data = { + 'T_ambient': np.linspace(-10, 20, 7), + 'heat_load': np.linspace(3, 12, 10), + 'T_level': np.linspace(90, 60, 7) +} +eta = { + 'T_ambient': [], + 'heat_load': [], + 'T_level': [] +} +heat_loss = { + 'T_ambient': [], + 'heat_load': [], + 'T_level': [] +} + +for T in data['T_ambient']: + pipe_feed.set_attr(Tamb=T) + pipe_return.set_attr(Tamb=T) + nw.solve('design') + eta['T_ambient'] += [abs(cons.Q.val) / hs.Q.val * 100] + heat_loss['T_ambient'] += [abs(pipe_feed.Q.val + pipe_return.Q.val)] + +# reset to base temperature +pipe_feed.set_attr(Tamb=0) +pipe_return.set_attr(Tamb=0) + +for Q in data['heat_load']: + cons.set_attr(Q=-1e3 * Q) + nw.solve('design') + eta['heat_load'] += [abs(cons.Q.val) / hs.Q.val * 100] + heat_loss['heat_load'] += [abs(pipe_feed.Q.val + pipe_return.Q.val)] + +# reset to base temperature +cons.set_attr(Q=-10e3) + +for T in data['T_level']: + c1.set_attr(T=T) + c4.set_attr(T=T - 20) # return flow temperature assumed 20 °C lower than feed + nw.solve('design') + eta['T_level'] += [abs(cons.Q.val) / hs.Q.val * 100] + heat_loss['T_level'] += [abs(pipe_feed.Q.val + pipe_return.Q.val)] + +fig, ax = plt.subplots(2, 3, figsize=(16, 8), sharex='col', sharey='row') + +ax = ax.flatten() +[a.grid() for a in ax] + +i = 0 +for key in data: + ax[i].scatter(data[key], eta[key], s=100, color="#1f567d") + ax[i + 3].scatter(data[key], heat_loss[key], s=100, color="#18a999") + i += 1 + +ax[0].set_ylabel('Efficiency in %') +ax[3].set_ylabel('Heat losses in W') +ax[3].set_xlabel('Ambient temperature in °C') +ax[4].set_xlabel('Consumer heat load in kW') +ax[5].set_xlabel('District heating temperature level in °C') +plt.tight_layout() +fig.savefig('district_heating_partload.svg') +plt.close() +# [sec_6] diff --git a/tutorial/basics/rankine.py b/tutorial/basics/rankine.py index fd1dc8173..b9ce6e7f3 100755 --- a/tutorial/basics/rankine.py +++ b/tutorial/basics/rankine.py @@ -175,4 +175,4 @@ plt.tight_layout() fig.savefig('rankine_partload.svg') plt.close() -# [sec_11] \ No newline at end of file +# [sec_11] From a20581918a1cd267573ab98f7e53363c9cd65585 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Thu, 1 Sep 2022 17:06:20 +0200 Subject: [PATCH 068/120] Uplaod heat pump code --- docs/whats_new/v0-0-3.rst | 2 +- tutorial/basics/heat_pump.py | 105 +++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tutorial/basics/heat_pump.py diff --git a/docs/whats_new/v0-0-3.rst b/docs/whats_new/v0-0-3.rst index 3d3b538cd..512f872ac 100644 --- a/docs/whats_new/v0-0-3.rst +++ b/docs/whats_new/v0-0-3.rst @@ -16,7 +16,7 @@ Documentation ############# - internal adjustments for links in the documentation and API. - added a tutorial for the combustion chamber and moved tutorials to the :ref:`appropriate section ` (`8c0034d `_, `fd7a8e7 `_, `e887478 `_). -- added installation guide for :ref:`windows ` windows (`ca5eaa1 `_). +- added installation guide for :ref:`windows ` windows (`ca5eaa1 `_). Testing ####### diff --git a/tutorial/basics/heat_pump.py b/tutorial/basics/heat_pump.py new file mode 100644 index 000000000..8a8c530b3 --- /dev/null +++ b/tutorial/basics/heat_pump.py @@ -0,0 +1,105 @@ + + +from tespy.networks import Network + +# create a network object with R134a as fluid +fluid_list = ['R134a'] +my_plant = Network(fluids=fluid_list) + +# set the unitsystem for temperatures to °C and for pressure to bar +my_plant.set_attr(T_unit='C', p_unit='bar', h_unit='kJ / kg') + +from tespy.components import ( + CycleCloser, Compressor, Valve, HeatExchangerSimple +) + +cc = CycleCloser('cycle closer') + +# heat sink +co = HeatExchangerSimple('condenser') +# heat source +ev = HeatExchangerSimple('evaporator') + +va = Valve('expansion valve') +cp = Compressor('compressor') + +from tespy.connections import Connection + +# connections of heat pump +c1 = Connection(cc, 'out1', ev, 'in1', label='1') +c2 = Connection(ev, 'out1', cp, 'in1', label='2') +c3 = Connection(cp, 'out1', co, 'in1', label='3') +c4 = Connection(co, 'out1', va, 'in1', label='4') +c0 = Connection(va, 'out1', cc, 'in1', label='0') + +# this line is crutial: you have to add all connections to your network +my_plant.add_conns(c1, c2, c3, c4, c0) + +co.set_attr(pr=0.98, Q=-1e6) +ev.set_attr(pr=0.98) +cp.set_attr(eta_s=0.85) + +c2.set_attr(T=20, x=1, fluid={'R134a': 1}) +c4.set_attr(T=80, x=0) + +my_plant.solve(mode='design') +my_plant.print_results() +print(f'COP = {abs(co.Q.val) / cp.P.val}') + + +import matplotlib.pyplot as plt +import numpy as np + + +data = { + 'T_source': np.linspace(0, 40, 11), + 'T_sink': np.linspace(60, 100, 11), + 'eta_s': np.linspace(0.75, 0.95, 11) * 100 +} +COP = { + 'T_source': [], + 'T_sink': [], + 'eta_s': [] +} +description = { + 'T_source': 'Evaporation temperature in °C', + 'T_sink': 'Condensation temperature in °C', + 'eta_s': 'Isentropic efficiency in %' +} + +for T in data['T_source']: + c2.set_attr(T=T) + my_plant.solve('design') + COP['T_source'] += [abs(co.Q.val) / cp.P.val] + +# reset to base temperature +c2.set_attr(T=20) + +for T in data['T_sink']: + c4.set_attr(T=T) + my_plant.solve('design') + COP['T_sink'] += [abs(co.Q.val) / cp.P.val] + +# reset to base temperature +c4.set_attr(T=80) + +for eta_s in data['eta_s']: + cp.set_attr(eta_s=eta_s / 100) + my_plant.solve('design') + COP['eta_s'] += [abs(co.Q.val) / cp.P.val] + +fig, ax = plt.subplots(1, 3, sharey=True, figsize=(16, 8)) + +[a.grid() for a in ax] + +i = 0 +for key in data: + ax[i].scatter(data[key], COP[key]) + ax[i].set_xlabel(description[key]) + i += 1 + +ax[0].set_ylabel('COP of the heat pump') + +plt.tight_layout() + +fig.savefig('COP_parametric.svg') From cbce5b44a0692da1165f7cc505a5a94804d91c5e Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Thu, 1 Sep 2022 21:31:54 +0200 Subject: [PATCH 069/120] Finishing touches for basic tutorials --- .../images/basics/heat_pump_parametric.svg | 3813 ++++++++--------- docs/basics/district_heating.rst | 3 + docs/basics/gas_turbine.rst | 3 + docs/basics/heat_pump.rst | 102 +- docs/basics/intro.rst | 77 +- docs/basics/rankine_cycle.rst | 3 + tutorial/basics/district_heating.py | 12 +- tutorial/basics/gas_turbine.py | 28 +- tutorial/basics/heat_pump.py | 47 +- tutorial/basics/rankine.py | 22 +- 10 files changed, 1910 insertions(+), 2200 deletions(-) diff --git a/docs/_static/images/basics/heat_pump_parametric.svg b/docs/_static/images/basics/heat_pump_parametric.svg index ecf808191..35cf888a6 100644 --- a/docs/_static/images/basics/heat_pump_parametric.svg +++ b/docs/_static/images/basics/heat_pump_parametric.svg @@ -1,2029 +1,1784 @@ - - - - - - - - 2022-08-24T17:08:18.698999 - image/svg+xml - - - Matplotlib v3.5.1, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + 2022-09-01T21:28:12.795768 + image/svg+xml + + + Matplotlib v3.4.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/basics/district_heating.rst b/docs/basics/district_heating.rst index 984e75d91..45152ca0a 100644 --- a/docs/basics/district_heating.rst +++ b/docs/basics/district_heating.rst @@ -22,6 +22,9 @@ heating plant and a consumer, represented by a heat exchanger with a control valve. A much more complex district heating system is included in the advanced tutorials section. +Download the full script here: +:download:`district_heating.py ` + Setting up the System ^^^^^^^^^^^^^^^^^^^^^ For this model we have to import the :code:`Network` and :code:`Connection` diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst index 872641cfb..77581f995 100644 --- a/docs/basics/gas_turbine.rst +++ b/docs/basics/gas_turbine.rst @@ -24,6 +24,9 @@ pressurized flue gas expands in the turbine, which drives the compressor and the generator. You will also learn, how to use the fluid compositon as a variable in your simulation. +Download the full script here: +:download:`gas_turbine.py ` + Setting up the Combustion Chamber ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ We are setting up our system step by step. Especially for larger systems, it diff --git a/docs/basics/heat_pump.rst b/docs/basics/heat_pump.rst index 26ac7fbbc..794f12b7c 100644 --- a/docs/basics/heat_pump.rst +++ b/docs/basics/heat_pump.rst @@ -23,6 +23,9 @@ specification options and modeling flexibility in TESPy as well as some typical errors, that might occur when using the software. Then we will make a simple analysis of the COP of the heat pump based on several input parameters. +Download the full script here: +:download:`heat_pump.py ` + Flexibility in Modeling ^^^^^^^^^^^^^^^^^^^^^^^ In TESPy the specifications for components and/or connections are @@ -34,13 +37,10 @@ the mass flow :code:`m` of the refrigerant. To unset a parameter you need to set it to :code:`None`. To replace the specification, set the mass flow of connection c1 to 5 kg/s: -.. code-block:: python - - co.set_attr(Q=None) - c1.set_attr(m=5) - - my_plant.solve('design') - my_plant.print_results() +.. literalinclude:: /../tutorial/basics/heat_pump.py + :language: python + :start-after: [sec_7] + :end-before: [sec_8] You can observe, that the heat transferred by the condenser now is a result of the mass flow imposed. We could do similar things, for example with the heat @@ -49,26 +49,19 @@ a compressor with a fixed output to input pressure ratio. In that case, we cannot choose the condensation temperature but it will be a result of that specification: -.. code-block:: python - - cp.set_attr(pr=4) - c4.set_attr(T=None) - - my_plant.solve('design') - my_plant.print_results() +.. literalinclude:: /../tutorial/basics/heat_pump.py + :language: python + :start-after: [sec_8] + :end-before: [sec_9] Or, we have a plant running with data observation running. It tells us the compressor outlet temperature and we want to know what the efficiency of the compressor would be, in case we measure :code:`T=97.3` at connection 3. -.. code-block:: python - - cp.set_attr(pr=None, eta_s=None) - c3.set_attr(T=97.3) - c4.set_attr(T=80) - - my_plant.solve('design') - my_plant.print_results() +.. literalinclude:: /../tutorial/basics/heat_pump.py + :language: python + :start-after: [sec_9] + :end-before: [sec_10] Typical Errors ^^^^^^^^^^^^^^ @@ -76,6 +69,11 @@ If you over- or underdetermine the system by specifying too few or too many parameters, you will get an error message. We could set the heat demand and the mass flow at the same time. +.. attention:: + + The two code examples in this section are not included in the downloadable + script! + .. code-block:: python co.set_attr(Q=-1e6) @@ -149,62 +147,10 @@ plot using matplotlib. .. dropdown:: Click to expand to code section - .. code-block:: python - - import matplotlib.pyplot as plt - import numpy as np - - - data = { - 'T_source': np.linspace(0, 40, 11), - 'T_sink': np.linspace(60, 100, 11), - 'eta_s': np.linspace(0.75, 0.95, 11) * 100 - } - COP = { - 'T_source': [], - 'T_sink': [], - 'eta_s': [] - } - description = { - 'T_source': 'Evaporation temperature in °C', - 'T_sink': 'Condensation temperature in °C', - 'eta_s': 'Isentropic efficiency in %' - } - - for T in data['T_source']: - c2.set_attr(T=T) - my_plant.solve('design') - COP['T_source'] += [abs(co.Q.val) / cp.P.val] - - # reset to base temperature - c2.set_attr(T=20) - - for T in data['T_sink']: - c4.set_attr(T=T) - my_plant.solve('design') - COP['T_sink'] += [abs(co.Q.val) / cp.P.val] - - # reset to base temperature - c4.set_attr(T=80) - - for eta_s in data['eta_s']: - cp.set_attr(eta_s=eta_s / 100) - my_plant.solve('design') - COP['eta_s'] += [abs(co.Q.val) / cp.P.val] - - fig, ax = plt.subplots(1, 3, sharey=True, figsize=(16, 8)) - - [a.grid() for a in ax] - - i = 0 - for key in data: - ax[i].scatter(data[key], COP[key]) - ax[i].set_xlabel(description[key]) - i += 1 - - ax[0].set_ylabel('COP of the heat pump') - plt.tight_layout() - fig.savefig('heat_pump_parametric.svg') + .. literalinclude:: /../tutorial/basics/heat_pump.py + :language: python + :start-after: [sec_10] + :end-before: [sec_11] .. figure:: /_static/images/basics/heat_pump_parametric.svg :align: center diff --git a/docs/basics/intro.rst b/docs/basics/intro.rst index 30937c6a6..4de5f6234 100644 --- a/docs/basics/intro.rst +++ b/docs/basics/intro.rst @@ -24,22 +24,19 @@ calculation in your plant. For more information on the fluid properties go to the :ref:`corresponding section ` in the documentation. -.. code-block:: python - - from tespy.networks import Network - - # create a network object with R134a as fluid - fluid_list = ['R134a'] - my_plant = Network(fluids=fluid_list) +.. literalinclude:: /../tutorial/basics/heat_pump.py + :language: python + :start-after: [sec_1] + :end-before: [sec_2] On top of that, it is possible to specify a unit system and value ranges for the network's variables. If you do not specify these, TESPy will use SI-units. We will thus only specify the unit systems, in this case. -.. code-block:: python - - # set the unitsystem for temperatures to °C and for pressure to bar - my_plant.set_attr(T_unit='C', p_unit='bar', h_unit='kJ / kg') +.. literalinclude:: /../tutorial/basics/heat_pump.py + :language: python + :start-after: [sec_2] + :end-before: [sec_3] Now you can start to create the components of the network. @@ -64,21 +61,10 @@ valve two (simple) heat exchangers and a so called cycle closer. specify. You can find all equations in each component's documentation as well. -.. code-block:: python - - from tespy.components import ( - CycleCloser, Compressor, Valve, HeatExchangerSimple - ) - - cc = CycleCloser('cycle closer') - - # heat sink - co = HeatExchangerSimple('condenser') - # heat source - ev = HeatExchangerSimple('evaporator') - - va = Valve('expansion valve') - cp = Compressor('compressor') +.. literalinclude:: /../tutorial/basics/heat_pump.py + :language: python + :start-after: [sec_3] + :end-before: [sec_4] After creating the components the next step is to connect them in order to form @@ -112,19 +98,10 @@ After creating the connections, we need to add them to the network. As the connections hold the information, which components are connected in which way, we do not need to pass the components to the network. -.. code-block:: python - - from tespy.connections import Connection - - # connections of the network - c1 = Connection(cc, 'out1', ev, 'in1', label='1') - c2 = Connection(ev, 'out1', cp, 'in1', label='2') - c3 = Connection(cp, 'out1', co, 'in1', label='3') - c4 = Connection(co, 'out1', va, 'in1', label='4') - c0 = Connection(va, 'out1', cc, 'in1', label='0') - - # this line is crutial: you have to add all connections to your network - my_plant.add_conns(c1, c2, c3, c4, c0) +.. literalinclude:: /../tutorial/basics/heat_pump.py + :language: python + :start-after: [sec_4] + :end-before: [sec_5] .. note:: @@ -163,14 +140,10 @@ fully saturated liqud (:code:`x=0`). On top of that, we want to impose the condensation and the evaporation temperature levels. Last, we have to specify the fluid vector at one point in our network. -.. code-block:: python - - co.set_attr(pr=0.98, Q=-1e6) - ev.set_attr(pr=0.98) - cp.set_attr(eta_s=0.85) - - c2.set_attr(T=20, x=1, fluid={'R134a': 1}) - c4.set_attr(T=75, x=0) +.. literalinclude:: /../tutorial/basics/heat_pump.py + :language: python + :start-after: [sec_5] + :end-before: [sec_6] .. note:: @@ -185,12 +158,10 @@ After building your network, the components and the connections, add the following line at the end of your script and run it. You can calculate the COP with the respective component parameters. -.. code-block:: python - - my_plant.solve(mode='design') - my_plant.print_results() - - print(f'COP = {abs(co.Q.val) / cp.P.val}') +.. literalinclude:: /../tutorial/basics/heat_pump.py + :language: python + :start-after: [sec_6] + :end-before: [sec_7] Next steps ---------- diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst index 73537add9..6adbcdbb9 100644 --- a/docs/basics/rankine_cycle.rst +++ b/docs/basics/rankine_cycle.rst @@ -17,6 +17,9 @@ Rankine Cycle Figure: Topology of the rankine cycle +Download the full script here: +:download:`rankine.py ` + Setting up the Cycle ^^^^^^^^^^^^^^^^^^^^ We will model the cycle including the cooling water of the condenser. For this diff --git a/tutorial/basics/district_heating.py b/tutorial/basics/district_heating.py index 44efe0fb9..5f34c2d77 100755 --- a/tutorial/basics/district_heating.py +++ b/tutorial/basics/district_heating.py @@ -1,4 +1,4 @@ -# [sec_1] +# %%[sec_1] from tespy.components.basics.cycle_closer import CycleCloser from tespy.networks import Network from tespy.components import ( @@ -32,7 +32,7 @@ c5 = Connection(val, "out1", pipe_return, "in1", label="5") c6 = Connection(pipe_return, "out1", cc, "in1", label="6") nw.add_conns(c0, c1, c2, c3, c4, c5, c6) -# [sec_2] +# %%[sec_2] cons.set_attr(Q=-10000, pr=0.98) hs.set_attr(pr=1) pu.set_attr(eta_s=0.75) @@ -45,7 +45,7 @@ nw.solve(mode="design") nw.print_results() -# [sec_3] +# %%[sec_3] pipe_feed.set_attr( ks=0.0005, # pipe's roughness in meters L=100, # length in m @@ -58,7 +58,7 @@ ) nw.solve(mode="design") nw.print_results() -# [sec_4] +# %%[sec_4] pipe_feed.set_attr(D=pipe_feed.D.val, pr=None) pipe_return.set_attr(D=pipe_return.D.val, pr=None) pipe_feed.set_attr( @@ -71,7 +71,7 @@ ) nw.solve(mode="design") nw.print_results() -# [sec_5] +# %%[sec_5] nw.set_attr(iterinfo=False) pipe_feed.set_attr(Tamb=0, kA=pipe_feed.kA.val, Q=None) pipe_return.set_attr(Tamb=0, kA=pipe_return.kA.val, Q=None) @@ -144,4 +144,4 @@ plt.tight_layout() fig.savefig('district_heating_partload.svg') plt.close() -# [sec_6] +# %%[sec_6] diff --git a/tutorial/basics/gas_turbine.py b/tutorial/basics/gas_turbine.py index bfadb0509..4c64224e2 100755 --- a/tutorial/basics/gas_turbine.py +++ b/tutorial/basics/gas_turbine.py @@ -1,4 +1,4 @@ -# [sec_1] +# %%[sec_1] from tespy.networks import Network from tespy.components import ( DiabaticCombustionChamber, Turbine, Source, Sink, Compressor @@ -15,12 +15,12 @@ air = Source("air source") fuel = Source("fuel source") fg = Sink("flue gas sink") -# [sec_2] +# %%[sec_2] c2 = Connection(air, "out1", cc, "in1", label="2") c3 = Connection(cc, "out1", fg, "in1", label="3") c5 = Connection(fuel, "out1", cc, "in2", label="5") nw.add_conns(c2, c3, c5) -# [sec_3] +# %%[sec_3] cc.set_attr(pr=1, eta=1, lamb=1.5, ti=10e6) c2.set_attr( @@ -40,15 +40,15 @@ nw.solve(mode="design") nw.print_results() -# [sec_4] +# %%[sec_4] cc.set_attr(ti=None) c5.set_attr(m=1) nw.solve(mode="design") -# [sec_5] +# %%[sec_5] cc.set_attr(lamb=None) c3.set_attr(T=1400) nw.solve(mode="design") -# [sec_6] +# %%[sec_6] c5.set_attr( fluid={ "CO2": 0.03, "Ar": 0, "N2": 0, "O2": 0, @@ -56,9 +56,9 @@ } ) nw.solve(mode="design") -# [sec_7] +# %%[sec_7] print(nw.results["Connection"]) -# [sec_8] +# %%[sec_8] nw.del_conns(c2, c3) c1 = Connection(air, "out1", cp, "in1", label="1") c2 = Connection(cp, "out1", cc, "in1", label="2") @@ -72,7 +72,7 @@ {"comp": cp, "char": 0.98, "base": "bus"}, ) nw.add_busses(generator) -# [sec_9] +# %%[sec_9] cp.set_attr(eta_s=0.85, pr=15) tu.set_attr(eta_s=0.90) c1.set_attr( @@ -86,12 +86,12 @@ c4.set_attr(p=Ref(c1, 1, 0)) nw.solve("design") nw.print_results() -# [sec_10] +# %%[sec_10] # unset the value, impose Referenced value instead c5.set_attr(p=None) c5.set_attr(p=Ref(c2, 1.05, 0)) nw.solve("design") -# [sec_11] +# %%[sec_11] cc.set_attr(pr=0.97, eta=0.98) nw.set_attr(iterinfo=False) import matplotlib.pyplot as plt @@ -150,7 +150,7 @@ plt.tight_layout() fig.savefig('gas_turbine_parametric.svg') plt.close() -# [sec_12] +# %%[sec_12] c3.set_attr(T=None) @@ -178,7 +178,7 @@ plt.tight_layout() fig.savefig('gas_turbine_oxygen.svg') plt.close() -# [sec_13] +# %%[sec_13] # retain starting values for CH4 and H2 with this variant c5.fluid.val_set["CH4"] = False c5.fluid.val_set["H2"] = False @@ -209,4 +209,4 @@ plt.tight_layout() fig.savefig('gas_turbine_fuel_composition.svg') plt.close() -# [sec_14] +# %%[sec_14] diff --git a/tutorial/basics/heat_pump.py b/tutorial/basics/heat_pump.py index 8a8c530b3..462275893 100644 --- a/tutorial/basics/heat_pump.py +++ b/tutorial/basics/heat_pump.py @@ -1,14 +1,13 @@ - - +# %%[sec_1] from tespy.networks import Network # create a network object with R134a as fluid fluid_list = ['R134a'] my_plant = Network(fluids=fluid_list) - +# %%[sec_2] # set the unitsystem for temperatures to °C and for pressure to bar my_plant.set_attr(T_unit='C', p_unit='bar', h_unit='kJ / kg') - +# %%[sec_3] from tespy.components import ( CycleCloser, Compressor, Valve, HeatExchangerSimple ) @@ -22,7 +21,7 @@ va = Valve('expansion valve') cp = Compressor('compressor') - +# %%[sec_4] from tespy.connections import Connection # connections of heat pump @@ -34,22 +33,51 @@ # this line is crutial: you have to add all connections to your network my_plant.add_conns(c1, c2, c3, c4, c0) - +# %%[sec_5] co.set_attr(pr=0.98, Q=-1e6) ev.set_attr(pr=0.98) cp.set_attr(eta_s=0.85) c2.set_attr(T=20, x=1, fluid={'R134a': 1}) c4.set_attr(T=80, x=0) - +# %%[sec_6] my_plant.solve(mode='design') my_plant.print_results() + print(f'COP = {abs(co.Q.val) / cp.P.val}') +# %%[sec_7] +co.set_attr(Q=None) +c1.set_attr(m=5) +my_plant.solve('design') +my_plant.print_results() +# %%[sec_8] +cp.set_attr(pr=4) +c4.set_attr(T=None) + +my_plant.solve('design') +my_plant.print_results() +# %%[sec_9] +cp.set_attr(pr=None, eta_s=None) +c3.set_attr(T=97.3) +c4.set_attr(T=80) + +my_plant.solve('design') +my_plant.print_results() +# %%[sec_10] +# first go back to the original state of the specifications +co.set_attr(Q=-1e6) +cp.set_attr(pr=None, eta_s=0.85) +c1.set_attr(m=None) +c3.set_attr(T=None) +c4.set_attr(T=80) import matplotlib.pyplot as plt import numpy as np +# make text reasonably sized +plt.rc('font', **{'size': 18}) + data = { 'T_source': np.linspace(0, 40, 11), @@ -94,7 +122,7 @@ i = 0 for key in data: - ax[i].scatter(data[key], COP[key]) + ax[i].scatter(data[key], COP[key], s=100, color="#1f567d") ax[i].set_xlabel(description[key]) i += 1 @@ -102,4 +130,5 @@ plt.tight_layout() -fig.savefig('COP_parametric.svg') +fig.savefig('heat_pump_parametric.svg') +# %%[sec_11] diff --git a/tutorial/basics/rankine.py b/tutorial/basics/rankine.py index b9ce6e7f3..0e9cb137c 100755 --- a/tutorial/basics/rankine.py +++ b/tutorial/basics/rankine.py @@ -1,11 +1,11 @@ -# [sec_1] +# %%[sec_1] from tespy.networks import Network # create a network object with R134a as fluid fluid_list = ['water'] my_plant = Network(fluids=fluid_list) my_plant.set_attr(T_unit='C', p_unit='bar', h_unit='kJ / kg') -# [sec_2] +# %%[sec_2] from tespy.components import ( CycleCloser, Pump, Condenser, Turbine, HeatExchangerSimple, Source, Sink ) @@ -33,7 +33,7 @@ c12 = Connection(mc, 'out2', cwsi, 'in1', label='12') my_plant.add_conns(c11, c12) -# [sec_3] +# %%[sec_3] mc.set_attr(pr1=1, pr2=0.98) sg.set_attr(pr=0.9) tu.set_attr(eta_s=0.9) @@ -46,13 +46,13 @@ my_plant.solve(mode='design') my_plant.print_results() -# [sec_4] +# %%[sec_4] mc.set_attr(ttd_u=4) c2.set_attr(p=None) my_plant.solve(mode='design') my_plant.print_results() -# [sec_5] +# %%[sec_5] from tespy.connections import Bus powergen = Bus("electrical power output") @@ -66,13 +66,13 @@ my_plant.solve(mode='design') my_plant.print_results() -# [sec_6] +# %%[sec_6] powergen.set_attr(P=-10e6) c1.set_attr(m=None) my_plant.solve(mode='design') my_plant.print_results() -# [sec_7] +# %%[sec_7] my_plant.set_attr(iterinfo=False) c1.set_attr(m=20) powergen.set_attr(P=None) @@ -147,16 +147,16 @@ plt.tight_layout() fig.savefig('rankine_parametric.svg') plt.close() -# [sec_8] +# %%[sec_8] mc.set_attr(design=["ttd_u"], offdesign=["kA"]) c11.set_attr(offdesign=["v"]) c12.set_attr(design=["T"]) c1.set_attr(design=["p"]) tu.set_attr(offdesign=["cone"]) -# [sec_9] +# %%[sec_9] my_plant.solve("design") my_plant.save("rankine_design") -# [sec_10] +# %%[sec_10] partload_efficiency = [] partload_m_range = np.linspace(20, 10, 11) @@ -175,4 +175,4 @@ plt.tight_layout() fig.savefig('rankine_partload.svg') plt.close() -# [sec_11] +# %%[sec_11] From c2891e4a9396f2141ae290469f178a0965fac859 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Thu, 1 Sep 2022 21:58:38 +0200 Subject: [PATCH 070/120] Start work on stepwise heat pump --- tutorial/step_1.py | 103 +++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 59 deletions(-) diff --git a/tutorial/step_1.py b/tutorial/step_1.py index 0b8a79c6e..46531f20e 100644 --- a/tutorial/step_1.py +++ b/tutorial/step_1.py @@ -1,77 +1,62 @@ -# -*- coding: utf-8 -*- +# %%[sec_1] +from tespy.networks import Network + +# %% network +nw = Network( + fluids=["water", "NH3"], + T_unit="C", p_unit="bar", h_unit="kJ / kg", m_unit="kg / s" +) +# %%[sec_2] from tespy.components import Condenser from tespy.components import CycleCloser from tespy.components import HeatExchangerSimple from tespy.components import Pump from tespy.components import Sink from tespy.components import Source -from tespy.connections import Connection -from tespy.networks import Network - -# %% network - -nw = Network(fluids=['water', 'NH3'], T_unit='C', p_unit='bar', - h_unit='kJ / kg', m_unit='kg / s') - -# %% components # sources & sinks - -c_in = Source('coolant in') -cons_closer = CycleCloser('consumer cycle closer') - -va = Sink('valve') - -# consumer system - -cd = Condenser('condenser') -rp = Pump('recirculation pump') -cons = HeatExchangerSimple('consumer') - -# %% connections +c_in = Source("coolant in") +cons_closer = CycleCloser("consumer cycle closer") +va = Sink("valve") # consumer system +cd = Condenser("condenser") +rp = Pump("recirculation pump") +cons = HeatExchangerSimple("consumer") +# %%[sec_3] +from tespy.connections import Connection -c_in_cd = Connection(c_in, 'out1', cd, 'in1') - -close_rp = Connection(cons_closer, 'out1', rp, 'in1') -rp_cd = Connection(rp, 'out1', cd, 'in2') -cd_cons = Connection(cd, 'out2', cons, 'in1') -cons_close = Connection(cons, 'out1', cons_closer, 'in1') - -nw.add_conns(c_in_cd, close_rp, rp_cd, cd_cons, cons_close) - -# connection condenser - evaporator system - -cd_va = Connection(cd, 'out1', va, 'in1') - -nw.add_conns(cd_va) - -# %% component parametrization - -cd.set_attr(pr1=0.99, pr2=0.99, ttd_u=5, design=['pr2', 'ttd_u'], - offdesign=['zeta2', 'kA_char']) -rp.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) -cons.set_attr(pr=0.99, design=['pr'], offdesign=['zeta']) - -# %% connection parametrization - -c_in_cd.set_attr(T=170, fluid={'water': 0, 'NH3': 1}) -close_rp.set_attr(T=60, p=10, fluid={'water': 1, 'NH3': 0}) -cd_cons.set_attr(T=90) - -# %% key paramter - +c0 = Connection(c_in, "out1", cd, "in1", label="0") +c1 = Connection(cd, "out1", va, "in1", label="1") + +c20 = Connection(cons_closer, "out1", rp, "in1", label="20") +c21 = Connection(rp, "out1", cd, "in2", label="21") +c22 = Connection(cd, "out2", cons, "in1", label="22") +c23 = Connection(cons, "out1", cons_closer, "in1", label="23") + +nw.add_conns(c0, c1, c20, c21, c22, c23) +# %%[sec_4] +cd.set_attr( + pr1=0.99, pr2=0.99, ttd_u=5, + design=["pr2", "ttd_u"], offdesign=["zeta2", "kA_char"] +) +rp.set_attr(eta_s=0.8, design=["eta_s"], offdesign=["eta_s_char"]) +cons.set_attr(pr=0.99, design=["pr"], offdesign=["zeta"]) +# %%[sec_5] +c0.set_attr(T=170, fluid={"water": 0, "NH3": 1}) +c20.set_attr(T=60, p=2, fluid={"water": 1, "NH3": 0}) +c22.set_attr(T=90) + +# key design paramter cons.set_attr(Q=-230e3) - -# %% Calculation - -nw.solve('design') +# %%[sec_6] +nw.solve("design") nw.print_results() -nw.save('condenser') +nw.save("condenser") cons.set_attr(Q=-200e3) -nw.solve('offdesign', design_path='condenser') +nw.solve("offdesign", design_path="condenser") nw.print_results() +# %%[sec_7] From 826ce1c6648822c3f90a7069ca3332ebb1679127 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Thu, 1 Sep 2022 21:59:18 +0200 Subject: [PATCH 071/120] Rename/move file --- tutorial/{step_1.py => advanced/stepwise.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tutorial/{step_1.py => advanced/stepwise.py} (100%) diff --git a/tutorial/step_1.py b/tutorial/advanced/stepwise.py similarity index 100% rename from tutorial/step_1.py rename to tutorial/advanced/stepwise.py From 28aa3ad3d0a857d9ee922f5f6b7515a247185899 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Thu, 1 Sep 2022 23:06:18 +0200 Subject: [PATCH 072/120] Add a lot of new stuff for stepwise tutorial --- docs/tutorials/heat_pump_steps.rst | 554 ++++++++++++++--------------- docs/tutorials/starting_values.rst | 4 +- tutorial/advanced/stepwise.py | 78 +++- 3 files changed, 335 insertions(+), 301 deletions(-) diff --git a/docs/tutorials/heat_pump_steps.rst b/docs/tutorials/heat_pump_steps.rst index 96a22abb4..a39b8a251 100644 --- a/docs/tutorials/heat_pump_steps.rst +++ b/docs/tutorials/heat_pump_steps.rst @@ -1,20 +1,31 @@ .. _tespy_tutorial_heat_pump_label: -Heat pump tutorial ------------------- +Build a Heat Pump Stepwise +-------------------------- + +We provide the full script presented in this tutorial here: +:download:`stepwise.py ` + +.. figure:: /_static/images/tutorials/heat_pump_stepwise/flowsheet.svg + :align: center + :alt: Topology of the heat pump system + :figclass: only-light + + Figure: Topology of the heat pump system + +.. figure:: /_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg + :align: center + :alt: Topology of the heat pump system + :figclass: only-dark + + Figure: Topology of the heat pump system Task ^^^^ - This tutorial introduces you in how to model a heat pump in TESPy. You can see the plants topology in the figure. Also, you will find a fully working model in the last chapter of this tutorial. -.. figure:: /api/_images/tutorial_heat_pump.svg - :align: center - - Figure: Topology of the heat pump. - The main purpose of the heat pump is to deliver heat e.g. for the consumers of a heating system. Thus, the heat pump's parameters will be set in a way, which supports this target. @@ -26,67 +37,65 @@ last element. Each new section will be appended to the existing ones. Set up a Network ^^^^^^^^^^^^^^^^ - -In order to simulate our heat pump we have to create an instance of the +First, we have to create an instance of the :py:class:`tespy.networks.network.Network` class. The network is the main container of the model and will be required in all following sections. First, it is necessary to specify a list of the fluids used in the plant. In this example we will work with water (H\ :sub:`2`\O) and ammonia (NH\ :sub:`3`\). -Water is used for the cold side of the heat exchanger, for the consumer and for -the hot side of the environmental temperature. Ammonia is used as coolant +Water is used for the cold side of the heat exchanger, for the consumer and +for the hot side of the environmental temperature. Ammonia is used as coolant within the heat pump circuit. If you don’t specify the unit system, the variables are set to SI-Units. -.. code-block:: python - - from tespy.networks import Network - - nw = Network(fluids=['water', 'NH3'], - T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s') +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_1] + :end-before: [sec_2] We will use °C, bar and kJ/kg as units for temperature and enthalpy. Modeling the heat pump: Consumer system ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. figure:: /_static/images/tutorials/heat_pump_stepwise/flowsheet_p1.svg + :align: center + :alt: First part of the system + :figclass: only-light + + Figure: First part of the system + +.. figure:: /_static/images/tutorials/heat_pump_stepwise/flowsheet_p1_darkmode.svg + :align: center + :alt: First part of the system + :figclass: only-dark + + Figure: First part of the system + Components ++++++++++ - We will start with the consumer as the plant will be designed to deliver a -specific heat flow. From figure 1 you can determine the components of the -consumer system: condenser, pump and the consumer ( +specific heat flow. From the figure above you can determine the components of +the consumer system: condenser, pump and the consumer ( :py:class:`tespy.components.heat_exchangers.simple.HeatExchangerSimple` ). Additionally we need a source and a sink for the consumer and the heat pump circuit respectively. We will import all necessary components already in the first step, so the imports will not need further adjustment. -We label the sink for the coolant "valve", as for our next calculation the -valve (labeled "valve") will be attached there. In this way, the fluid -properties can be initialized by .csv at the interface-connection, too. - -.. code-block:: python +.. tip:: - from tespy.components import ( - Source, Sink, CycleCloser, Valve, Drum, Pump, Compressor, - Condenser, HeatExchangerSimple, HeatExchanger) + We label the sink for the coolant :code:`"valve"`, as for our next + calculation the valve will be attached there instead of the sink. In this + way, the fluid properties can be initialized at the interface-connection, + too. - # sources & sinks - - c_in = Source('coolant in') - cons_closer = CycleCloser('consumer cycle closer') - - va = Sink('valve') - - # consumer system - - cd = Condenser('condenser') - rp = Pump('recirculation pump') - cons = HeatExchangerSimple('consumer') +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_2] + :end-before: [sec_3] Connections +++++++++++ - -In the next steps we will connect the components in order to form a network. +In the next steps we will connect the components in order to form the network. Every connection requires the source, the source id, the target and the target id as arguments: the source is the component from which the connection originates, the source id is the outlet id of that component. This applies @@ -95,48 +104,32 @@ up the class documentation of the respective component. An overview of the components available and the class documentations is provided in the :ref:`TESPy modules overview `. The :py:class:`tespy.connections.connection.Ref` class is used specify fluid -property values by referencing fluid properties of different connections. It is -used in a later step. - -.. code-block:: python +property values by referencing fluid properties of different connections. It +is used in a later step. - from tespy.connections import Connection, Ref +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_3] + :end-before: [sec_4] - # consumer system +.. seealso:: - c_in_cd = Connection(c_in, 'out1', cd, 'in1') - - close_rp = Connection(cons_closer, 'out1', rp, 'in1') - rp_cd = Connection(rp, 'out1', cd, 'in2') - cd_cons = Connection(cd, 'out2', cons, 'in1') - cons_close = Connection(cons, 'out1', cons_closer, 'in1') - - nw.add_conns(c_in_cd, close_rp, rp_cd, cd_cons, cons_close) - - # connection condenser - evaporator system - - cd_va = Connection(cd, 'out1', va, 'in1') - - nw.add_conns(cd_va) - -.. note:: - - Instead of just connecting the consumers outlet to the pumps inlet, we must - make use of an auxiliary component: Closing a cycle without further + As we learned in the :ref:`basic introduction ` + instead of just connecting the consumer's outlet to the pump's inlet, we + must make use of the CycleCloser. Closing a cycle without further adjustments will always result in a linear dependency in the fluid and the - mass flow equations. We therefore need implement a CycleCloser. The - :py:class:`tespy.components.basics.cycle_closer.CycleCloser` component makes - sure, the fluid properties pressure and enthalpy are identical at the inlet - and the outlet. The component will prompt a warning, if the mass flow or - the fluid composition at its outlet are different to those at its inlet. A - different solution to this problem, is adding a merge and a splitter at - some point of your network and connect the second inlet/outlet to a - source/sink. This causes residual mass flow and residual fluids to + mass flow equations. The + :py:class:`tespy.components.basics.cycle_closer.CycleCloser` component + makes sure, the fluid properties pressure and enthalpy are identical at + the inlet and the outlet. The component will prompt a warning, if the mass + flow or the fluid composition at its outlet are different to those at its + inlet. A different solution to this problem, is adding a merge and a + splitter at some point of your network and connect the second inlet/outlet + to a source/sink. This causes residual mass flow and residual fluids to emerge/drain there. Parametrization +++++++++++++++ - For the condenser we set pressure ratios on hot and cold side and additionally we set a value for the upper terminal temperature difference as design parameter and the heat transfer coefficient as offdesign parameter. The @@ -146,14 +139,13 @@ characteristic function. Thus, we set the efficiency as design parameter and the characteristic function as offdesign parameter. In offdesign calculation the consumer's pressure ratio will be a function of the mass flow, thus as offdesign parameter we select zeta. The most important parameter is the -consumers heat demand. We marked this setting as "key parameter". - -.. code-block:: python +consumer's heat demand since it decides the overall mass flow in the systems. +We marked this setting as :code:`"key parameter"`. - cd.set_attr(pr1=1, pr2=0.99, ttd_u=5, design=['pr2', 'ttd_u'], - offdesign=['zeta2', 'kA_char']) - rp.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) - cons.set_attr(pr=0.99, design=['pr'], offdesign=['zeta']) +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_4] + :end-before: [sec_5] In order to calculate this network further parametrization is necessary, as e.g. the fluids are not determined yet: At the hot inlet of the condenser we @@ -162,20 +154,13 @@ fluid's state at this point, an information on the pressure is required. This is achieved by setting the terminal temperature difference (see above). The same needs to be done for the consumer cycle. We suggest to set the parameters at the pump's inlet. On top, we assume that the consumer requires a constant -inlet temperature. The CycleCloser automatically makes sure, that the fluid's -state at the consumer's outlet is the same as at the pump's inlet. - -.. code-block:: python - - c_in_cd.set_attr(T=170, fluid={'water': 0, 'NH3': 1}) - close_rp.set_attr(T=60, p=10, fluid={'water': 1, 'NH3': 0}) - cd_cons.set_attr(T=90) - -.. code-block:: python +inlet temperature. The :code:`CycleCloser` automatically makes sure, that the +fluid's state at the consumer's outlet is the same as at the pump's inlet. - # %% key parameter - - cons.set_attr(Q=-230e3) +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_5] + :end-before: [sec_6] .. note:: @@ -197,250 +182,220 @@ state at the consumer's outlet is the same as at the pump's inlet. Solve +++++ - After creating the system, we want to solve our network. First, we calculate -the design case and directly after we can perform the offdesign calculation at -a different value for our key parameter. For general information on the solving -process in TESPy and available parameters check the corresponding section in -the :ref:`TESPy modules introduction `. - -.. code-block:: python +the design case and directly after we can perform the offdesign calculation. +Before finishing the full network, we do this without changing the value of +any parameters to test, if the calculation actually works. All results have +to be identical to the design case results, if no value was modified. - nw.solve('design') - nw.print_results() - nw.save('condenser') +.. seealso:: - cons.set_attr(Q=-200e3) + For general information on the solving process in TESPy and available + parameters check the corresponding section in the + :ref:`TESPy modules introduction `. - nw.solve('offdesign', design_path='condenser') - nw.print_results() +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_6] + :end-before: [sec_7] Valve and evaporator system ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Next we will add the valve and the evaporator system to our existing network. +The figure below indicates the sections we will append in this step. This part +contains of a valve followed by an evaporator with a drum (separating +saturated liquid from saturated gas) and a superheater. -Components -++++++++++ - -This part contains of a valve followed by a drum with evaporator in forced flow -and a superheater. Do not forget to change the old sink labeled "valve" to an -actual valve and the sink used in the previous calculation will represent the -first compressor, labeled "compressor 1". Add the following components to the -script. - -.. code-block:: python +.. figure:: /_static/images/tutorials/heat_pump_stepwise/flowsheet_p2.svg + :align: center + :alt: Second part of the system + :figclass: only-light - # sources & sinks + Figure: Second part of the system - amb_in = Source('source ambient') - amb_out = Sink('sink ambient') +.. figure:: /_static/images/tutorials/heat_pump_stepwise/flowsheet_p2_darkmode.svg + :align: center + :alt: Second part of the system + :figclass: only-dark - cp1 = Sink('compressor 1') + Figure: Second part of the system - # evaporator system +Components +++++++++++ +First, we need to import the new components, which are +:py:class:`tespy.components.nodes.drum.Drum`, +:py:class:`tespy.components.heat_exchangers.base.HeatExchanger` and +:py:class:`tespy.components.piping.valve.Valve`. We will add these components +to the script. - va = Valve('valve') - dr = Drum('drum') - ev = HeatExchanger('evaporator') - su = HeatExchanger('superheater') - pu = Pump('pump evaporator') +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_7] + :end-before: [sec_8] Connections +++++++++++ - -As we already redefined our variable "va" to be a valve instead of a sink (see -above), we do not need any adjustments to the connection between the condenser -and the former sink "cd_va". The valve connects to the drum at the inlet 'in1'. -The pump of the forced flow evaporation system connects to the drum's outlet -'out1', the evaporator's cold side connects to the drum's inlet 'in2' and the -superheater's cold side connects to the drum's outlet 'out2'. This will add the -following connections to the model: - -.. code-block:: python - - # evaporator system - - va_dr = Connection(va, 'out1', dr, 'in1') - dr_pu = Connection(dr, 'out1', pu, 'in1') - pu_ev = Connection(pu, 'out1', ev, 'in2') - ev_dr = Connection(ev, 'out2', dr, 'in2') - dr_su = Connection(dr, 'out2', su, 'in2') - - nw.add_conns(va_dr, dr_pu, pu_ev, ev_dr, dr_su) - - amb_in_su = Connection(amb_in, 'out1', su, 'in1') - su_ev = Connection(su, 'out1', ev, 'in1') - ev_amb_out = Connection(ev, 'out1', amb_out, 'in1') - - nw.add_conns(amb_in_su, su_ev, ev_amb_out) - - # connection evaporator system - compressor system - - su_cp1 = Connection(su, 'out2', cp1, 'in1') - - nw.add_conns(su_cp1) +Since the old connection :code:`1` lead to a sink, we have to replace this +connection in the network. We can do that by using the method +:code:`del_conns` passing :code:`c1`. After that, we can create the new +connections and add them to the network as we did before. + +The valve connects to the drum at the inlet :code:`'in1'`. The drum's outlet +:code:`'out1'` is saturated liquid and connects to the evaporator's cold side +inlet :code:`'in2'`. The inlet reconnects to the drum's inlet :code:`'in2'`. +The superheater's cold side connects to the drum's outlet :code:`'out2'`. +On the ambient side we simply connect the source to the superheater to the +evaporator and finally to the ambient sink. This will add the following +connections to the model: + +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_8] + :end-before: [sec_9] + +.. attention:: + + The drum is special component, it has an inbuilt CycleCloser, therefore + although we are technically forming a cycle at the drum's outlet 1 to its + inlet 2, we do not need to include a CycleCloser here. Parametrization +++++++++++++++ - Previous parametrization stays untouched. Regarding the evaporator, we specify -pressure ratios on hot and cold side as well as the lower terminal temperature -difference. We use the hot side pressure ratio and the lower terminal -temperature (similar to pinch point layout for waste heat steam generators) -difference as design parameters and choose zeta as well as the area independent -heat transfer coefficient as its offdesign parameters. - -On top of that, the characteristic function of the evaporator should follow the -default characteristic line of 'EVAPORATING FLUID' on the cold side and the -default line 'DEFAULT' on the hot side. These lines are defined in the -:ref:`tespy_data_label`. If you want to learn more about handling -characteristic functions you should have a glance at the -:ref:`TESPy components section `. The superheater -will also use the pressure ratios on hot and cold side. Further we set a value -for the upper terminal temperature difference. For the pump we set the -isentropic efficiency. For offdesign and design parameter specification of -these components the same logic as for the evaporator and the already existing -part of the network is applied. The system designer has to answer the question: -Which parameters are design point parameters and how does the component perform -at a different operation point. - -.. code-block:: python - - from tespy.tools.characteristics import CharLine - from tespy.tools.characteristics import load_default_char as ldc - # evaporator system - - kA_char1 = ldc('heat exchanger', 'kA_char1', 'DEFAULT', CharLine) - kA_char2 = ldc('heat exchanger', 'kA_char2', 'EVAPORATING FLUID', CharLine) - - ev.set_attr(pr1=0.99, pr2=0.99, ttd_l=5, - kA_char1=kA_char1, kA_char2=kA_char2, - design=['pr1', 'ttd_l'], offdesign=['zeta1', 'kA_char']) - su.set_attr(pr1=0.99, pr2=0.99, ttd_u=2, design=['pr1', 'pr2', 'ttd_u'], - offdesign=['zeta1', 'zeta2', 'kA_char']) - pu.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) +pressure ratios on hot side as well as the lower terminal temperature +difference. This specification is similar to pinch point layout for waste heat +steam generators. The pressure ratio of the cold side *MUST NOT* be specified +in this setup as the drum imposes pressure equality for all inlets and outlets. + +We use the hot side pressure ratio and the lower terminal temperature +difference as design parameters and choose zeta as well as a characteristic +function referring to the area independent heat transfer coefficient as its +offdesign parameters. + +On top of that, the characteristic function of the evaporator should follow +the default characteristic line of 'EVAPORATING FLUID' on the cold side and +the default line 'DEFAULT' on the hot side. These lines are defined in the +:ref:`tespy_data_label`. + +The superheater will also use the pressure ratios on hot and cold side. +Further we set a value for the upper terminal temperature difference. For +offdesign and design parameter specification the same logic as for the +evaporator and the already existing part of the network is applied. The system +designer has to answer the question: Which parameters are design point +parameters and how does the component perform at a different operation point. + +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_9] + :end-before: [sec_10] + +.. seealso:: + + If you want to learn more about handling characteristic functions you + should have a glance at the + :ref:`TESPy components section `. Next step is the connection parametrization: The pressure in the drum and the enthalpy of the wet steam reentering the drum need to be determined. For the enthalpy we can specify a reference of the circulating mass flow to the main cycle mass flow. The pressure is achieved through the given lower terminal temperature difference of the evaporator and its hot side outlet temperature. -As we have specified a terminal temperature difference at the evaporator's cold -side inlet (:code:`ttd_l`), it might be necessary to state a starting value for -the pressure or the state of the fluid (gaseous), as we are near to the -wo-phase region. On the hot side inlet of the superheater we define the -temperature, pressure and the fluid. Since the pressure between superheater and -first compressor will be a result of the pressure losses in the superheater and -we set the terminal temperature difference there, bad starting values will lead -to a linear dependency, as a temperature and a pressure are set while the -fluid's state could be within the two phase region. Thus, we choose to specify -:code:`state='g'`, so the solver will keep the fluid in gaseous state at all -times. At last we have to fully determine the state of the incoming fluid at -the superheater's hot side. - -.. note:: +As we have specified a terminal temperature difference at the evaporator's +cold side inlet (:code:`ttd_l`), it might be necessary to state a starting +value for the pressure or the state of the fluid (gaseous), as we are near to +the two-phase region. On the hot side inlet of the superheater we define the +temperature, pressure and the fluid. Since the pressure between superheater +and first compressor will be a result of the pressure losses in the +superheater and we set the terminal temperature difference there, bad starting +values will lead to a linear dependency, as a temperature and a pressure are +set while the fluid's state could be within the two phase region. Thus, we +choose to specify :code:`state="g"`, so the solver will keep the fluid in +gaseous state at all times. At last we have to fully determine the state of +the incoming fluid at the superheater's hot side. + +.. attention:: Do only use the :code:`state` keyword if you know the fluid's state prior to the simulation. If you specify the fluid to be gaseous but the correct result of the simulation would be within the two-phase region, your calculation most likely will not converge. -.. code-block:: python - - # evaporator system cold side - - pu_ev.set_attr(m=Ref(va_dr, 0.75, 0)) - su_cp1.set_attr(state='g') - - # evaporator system hot side - - amb_in_su.set_attr(T=12, p=1, fluid={'water': 1, 'NH3': 0}) - ev_amb_out.set_attr(T=9) +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_10] + :end-before: [sec_11] Solve +++++ +We can again run a simulation after adding these parts. This step is not +required, but in larger, more complex networks, it is recommended to achieve +better convergence. -Again, you should calculate your network after you added these parts. As we -have already calculated one part of our network, this time we can use the -:code:`init_path` for the design calculation and load the results from the -previous network. This step is not required, but in larger, more complex -networks, it might help, to achieve better convergence. - +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_11] + :end-before: [sec_12] Compressor system ^^^^^^^^^^^^^^^^^ - To complete the heat pump, we will add the compressor system to our existing -network. - -Components -++++++++++ - -This part contains two compressors with an intercooler between them. The cold -side of the intercooler requires a source and a sink. Again, remember -redefining the former sink :code:`"cp1"` to a compressor. We will now replace -the source for the coolant :code:`c_in` at the condenser with another cycle -closer (:code:`cool_closer`), to make sure the fluid properties after the -second compressor are identical to the fluid properties at the condenser inlet. - -.. note:: - - The intercooling leads to a lower COP but may be necessary depending on - your temperature level requirement on the consumer's side. In a single - stage compression, the outlet temperature of the coolant might violated - technical boundary conditions of the real-world component. - -.. code-block:: python - - # sources & sinks +network. This requires to change the connections 0, 6 and 13. The connection 6 +has to be changed to include the compressor. After the last compressor stage, +connection 0 has to redefined, since we need to include the CycleCloser of the +working fluid's cycle. The connection 13 has to be connected to the heat +exchanger for intermittent cooling and finally with a pump to make the water +from the ambient heat source flow through the heat exchangers. + +.. figure:: /_static/images/tutorials/heat_pump_stepwise/flowsheet.svg + :align: center + :alt: Topology of the heat pump system + :figclass: only-light - ic_in = Source('source intercool') - ic_out = Sink('sink intercool') + Figure: Topology of the heat pump system - cool_closer = CycleCloser('coolant cycle closer') +.. figure:: /_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg + :align: center + :alt: Topology of the heat pump system + :figclass: only-dark - # compressor-system + Figure: Topology of the heat pump system - cp1 = Compressor('compressor 1') - cp2 = Compressor('compressor 2') - he = HeatExchanger('intercooler') +Components +++++++++++ +This part contains two compressors with intermittent cooling between them. The +cold side of the heat exchanger will be connected to a pump upstream and to +the superheater downstream. We will also replace the source for the coolant +of :code:`c0` at the condenser with another CycleCloser (:code:`cool_closer`), +to make sure the fluid properties after the second compressor are identical to +the fluid properties at the condenser's inlet. + +.. tip:: + + The intermittent cooling extracts heat from the cycle. As this heat is + however used to increase the evaporation pressure of the working fluid due + to the higher temperature level of the heat source, the reduction is very + limited. We use a two stage compressor, because in a single stage + compression, the outlet temperature of the coolant might violate technical + boundary conditions of the real-world component. + +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_12] + :end-before: [sec_13] Connections +++++++++++ - Consequently to the addition of the cycle closer we have to adjust the -connection definition touching the new cycle closer. Replace - -.. code-block:: python - - c_in_cd = Connection(c_in, 'out1', cd, 'in1') +connection definition touching the new cycle closer. -with - -.. code-block:: python - - c_in_cd = Connection(cool_closer, 'out1', cd, 'in1') - -Of course, do not forget to add the new connections to the script. - -.. code-block:: python - - # compressor-system - - cp1_he = Connection(cp1, 'out1', he, 'in1') - he_cp2 = Connection(he, 'out1', cp2, 'in1') - cp2_close = Connection(cp2, 'out1', cool_closer, 'in1') - - ic_in_he = Connection(ic_in, 'out1', he, 'in2') - he_ic_out = Connection(he, 'out2', ic_out, 'in1') - - nw.add_conns(cp1_he, he_cp2, ic_in_he, he_ic_out, cp2_close) +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_13] + :end-before: [sec_14] Parametrization +++++++++++++++ - For the two compressor we defined an isentropic efficiency and for the offdesign calculation a generic characteristic line for the isentropic efficiency will be applied. The first compressor has a fixed pressure ratio, @@ -448,6 +403,11 @@ the seconds compressor pressure ratio will result from the required pressure at the condenser. The heat exchanger comes with pressure ratios on both sides. The parametrization of all other components remains identical. +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_14] + :end-before: [sec_15] + .. code-block:: python cp1.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) @@ -469,6 +429,11 @@ existing model: As the enthalpy at the outlet of the second compressor is a result of the given pressure ratio and the isentropic efficiency, it is not allowed to set the temperature at the condenser's hot inlet anymore. +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_15] + :end-before: [sec_16] + .. code-block:: python # condenser system @@ -489,22 +454,25 @@ favorable, but with manually adjusted starting values and the :code:`state` specifier, the calculation should still converge. If you want to use the previous part to initialise start the solver with +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_16] + :end-before: [sec_17] + .. code-block:: python nw.solve('design', init_path='condenser') +Explore Partload Performance +++++++++++++++++++++++++++++ + Further tasks ^^^^^^^^^^^^^ - After successfully modeling the heat pump in design and offdesign cases, you can now start using your model for further calculations. For example, if you have a time series of required heat flow of your consumer, you can loop over the series and perform offdesign calculation adjusting the heat flow every -time. Of course, this is possible with every offdesign parameter. We provide -the scripts after each of the three steps of the tutorial: -:download:`Step 1 `, -:download:`Step 2 `, -:download:`Step 3 `. +time. Of course, this is possible with every offdesign parameter. Have fun working with TESPy! diff --git a/docs/tutorials/starting_values.rst b/docs/tutorials/starting_values.rst index a9e4a211c..a21ed364c 100644 --- a/docs/tutorials/starting_values.rst +++ b/docs/tutorials/starting_values.rst @@ -1,7 +1,7 @@ .. _tespy_tutorial_starting_values_label: -Stable starting values for subcritical heat pumps -------------------------------------------------- +How to Generate Stable Starting Values +-------------------------------------- Applying numerical algorithms and methods, the starting value of a variable is the value used for the first iteration. With more complex TESPy models diff --git a/tutorial/advanced/stepwise.py b/tutorial/advanced/stepwise.py index 46531f20e..7f0b8bd3d 100644 --- a/tutorial/advanced/stepwise.py +++ b/tutorial/advanced/stepwise.py @@ -1,8 +1,6 @@ # %%[sec_1] from tespy.networks import Network -# %% network - nw = Network( fluids=["water", "NH3"], T_unit="C", p_unit="bar", h_unit="kJ / kg", m_unit="kg / s" @@ -53,10 +51,78 @@ # %%[sec_6] nw.solve("design") nw.print_results() -nw.save("condenser") - -cons.set_attr(Q=-200e3) +nw.save("consumer_part") -nw.solve("offdesign", design_path="condenser") +# run an offdesign test: without modifying any value it should give you +# the same results as the design calculation +nw.solve("offdesign", design_path="consumer_part") nw.print_results() # %%[sec_7] +from tespy.components import Valve, Drum, HeatExchanger + +# ambient heat source +amb_in = Source("source ambient") +amb_out = Sink("sink ambient") + +# evaporator system +va = Valve("valve") +dr = Drum("drum") +ev = HeatExchanger("evaporator") +su = HeatExchanger("superheater") + +# virtual source +cp1 = Sink("compressor 1") +# %%[sec_8] +nw.del_conns(c1) + +# evaporator system +c1 = Connection(cd, "out1", va, "in1", label="1") +c2 = Connection(va, "out1", dr, "in1", label="2") +c3 = Connection(dr, "out1", ev, "in2", label="3") +c4 = Connection(ev, "out2", dr, "in2", label="4") +c5 = Connection(dr, "out2", su, "in2", label="5") +c6 = Connection(su, "out2", cp1, "in1", label="6") + +nw.add_conns(c1, c2, c3, c4, c5, c6) + +c13 = Connection(amb_in, "out1", su, "in1", label="13") +c14 = Connection(su, "out1", ev, "in1", label="14") +c15 = Connection(ev, "out1", amb_out, "in1", label="15") + +nw.add_conns(c13, c14, c15) +# %%[sec_9] +from tespy.tools.characteristics import CharLine +from tespy.tools.characteristics import load_default_char as ldc +# evaporator system + +kA_char1 = ldc('heat exchanger', 'kA_char1', 'DEFAULT', CharLine) +kA_char2 = ldc('heat exchanger', 'kA_char2', 'EVAPORATING FLUID', CharLine) + +ev.set_attr( + pr1=0.99, ttd_l=5, kA_char1=kA_char1, kA_char2=kA_char2, + design=['pr1', 'ttd_l'], offdesign=['zeta1', 'kA_char'] +) +su.set_attr( + pr1=0.99, pr2=0.99, ttd_u=2, + design=['pr1', 'pr2', 'ttd_u'], offdesign=['zeta1', 'zeta2', 'kA_char'] +) +# %%[sec_10] +from tespy.connections import Ref +# evaporator system cold side +c3.set_attr(m=Ref(c2, 0.75, 0)) +# we provide this keyword for numerical stability +c6.set_attr(state="g") + +# evaporator system hot side +c13.set_attr(T=15, fluid={'water': 1, 'NH3': 0}) +c15.set_attr(T=9, p=1.013) +# %%[sec_11] +nw.solve("design") +nw.print_results() +nw.save("evaporator_part") + +# run the offdesign test +nw.solve("offdesign", design_path="evaporator_part") +nw.print_results() +# %%[sec_12] + From 20e2de0032729efe9566b45ec0113c6ff1472c16 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 3 Sep 2022 13:43:52 +0200 Subject: [PATCH 073/120] Finalize stepwise heat pump tutorial --- .../heat_pump_stepwise/flowsheet.svg | 261 +++-- .../heat_pump_stepwise/flowsheet_darkmode.svg | 373 +++++--- .../heat_pump_stepwise/flowsheet_p1.svg | 900 ++++++++++++++++++ .../flowsheet_p1_darkmode.svg | 900 ++++++++++++++++++ .../heat_pump_stepwise/flowsheet_p2.svg | 880 +++++++++++++++++ .../flowsheet_p2_darkmode.svg | 880 +++++++++++++++++ docs/tutorials/heat_pump_steps.rst | 297 +++--- tutorial/advanced/stepwise.py | 179 +++- 8 files changed, 4256 insertions(+), 414 deletions(-) create mode 100644 docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p1.svg create mode 100644 docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p1_darkmode.svg create mode 100644 docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2.svg create mode 100644 docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2_darkmode.svg diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg index 77a664358..271f54355 100644 --- a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg @@ -1,23 +1,22 @@ + viewBox="0 0 250.61694 134.23955" + height="134.23955mm" + width="250.61693mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + originx="-38.012091" + originy="-8.1672054" /> @@ -103,7 +102,6 @@ image/svg+xml - @@ -111,18 +109,18 @@ id="layer1" inkscape:groupmode="layer" inkscape:label="Ebene 1" - transform="translate(-37.99277,-2.7500075)"> + transform="translate(-38.012063,-8.167212)"> @@ -159,7 +157,7 @@ @@ -224,7 +222,7 @@ inkscape:connector-curvature="0" sodipodi:nodetypes="ccc" style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 182.49997,125.00001 h 42.00001 l 0,-7.2646" + d="m 182.49997,125.00001 h 42.00001 v -7.2646" id="path984-0-9-9-9-7-6-9" /> 6 @@ -567,7 +565,7 @@ id="path984-0-9-9-9-7-0-1-5-0-8-4-7-7-8" /> @@ -579,15 +577,27 @@ id="path984-0-9-9-9-7-6-4-1" /> + + 7 8 9 11 12 14 + 15 + 16 + 17 + 13 14 + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">18 15 + style="fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">19 superheater compressor 2 + + + diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg index f0bf94073..ab595d35c 100644 --- a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg @@ -1,23 +1,22 @@ + viewBox="0 0 250.61694 134.23955" + height="134.23955mm" + width="250.61693mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + originx="-38.012091" + originy="-8.1672054" /> @@ -103,7 +102,6 @@ image/svg+xml - @@ -111,18 +109,18 @@ id="layer1" inkscape:groupmode="layer" inkscape:label="Ebene 1" - transform="translate(-37.99277,-2.7500075)"> + transform="translate(-38.012063,-8.167212)"> @@ -159,7 +157,7 @@ + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> 1 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">1 6 + x="218.41196" + y="51.797832" + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">6 20 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">20 21 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">21 22 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">22 23 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">23 + transform="translate(26.000002,-3.020648e-5)"> + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> + transform="translate(41.000002,59.99997)"> @@ -581,15 +577,27 @@ id="path984-0-9-9-9-7-6-4-1" /> + + 0 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">0 2 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">2 3 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">3 4 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">4 5 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">5 7 + x="193.43727" + y="51.800247" + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">7 8 + x="158.43004" + y="51.797832" + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">8 9 + x="128.44693" + y="51.797832" + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">9 11 + x="131.81429" + y="16.800245" + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">11 12 + x="161.83359" + y="16.832802" + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">12 13 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">14 15 + 16 + 17 + 13 + 14 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">18 15 + style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round">19 superheater compressor 2 + + + diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p1.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p1.svg new file mode 100644 index 000000000..21bdd05e4 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p1.svg @@ -0,0 +1,900 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + compressor 1 + condenser + evaporator + expansion valve + 1 + 6 + + + + + + + + consumer + 20 + 21 + 22 + + + 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 2 + 3 + 4 + 5 + 7 + 8 + 9 + 11 + 12 + 14 + 15 + 16 + 17 + 13 + 18 + 19 + superheater + compressor 2 + + + + + diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p1_darkmode.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p1_darkmode.svg new file mode 100644 index 000000000..233b3e646 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p1_darkmode.svg @@ -0,0 +1,900 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + compressor 1 + condenser + evaporator + expansion valve + 1 + 6 + + + + + + + + consumer + 20 + 21 + 22 + + + 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 2 + 3 + 4 + 5 + 7 + 8 + 9 + 11 + 12 + 14 + 15 + 16 + 17 + 13 + 18 + 19 + superheater + compressor 2 + + + + + diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2.svg new file mode 100644 index 000000000..592049ea3 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2.svg @@ -0,0 +1,880 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + compressor 1 + condenser + evaporator + expansion valve + 1 + 6 + + + + + + + + consumer + 20 + 21 + 22 + + + 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 2 + 3 + 4 + 5 + 7 + 8 + 9 + 11 + 12 + 14 + 15 + 16 + 17 + 13 + 18 + 19 + superheater + compressor 2 + + + + + diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2_darkmode.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2_darkmode.svg new file mode 100644 index 000000000..47c421658 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2_darkmode.svg @@ -0,0 +1,880 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + compressor 1 + condenser + evaporator + expansion valve + 1 + 6 + + + + + + + + consumer + 20 + 21 + 22 + + + 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 2 + 3 + 4 + 5 + 7 + 8 + 9 + 11 + 12 + 14 + 15 + 16 + 17 + 13 + 18 + 19 + superheater + compressor 2 + + + + + diff --git a/docs/tutorials/heat_pump_steps.rst b/docs/tutorials/heat_pump_steps.rst index a39b8a251..6814f8d33 100644 --- a/docs/tutorials/heat_pump_steps.rst +++ b/docs/tutorials/heat_pump_steps.rst @@ -23,17 +23,19 @@ We provide the full script presented in this tutorial here: Task ^^^^ This tutorial introduces you in how to model a heat pump in TESPy. You can see -the plants topology in the figure. Also, you will find a fully working model in -the last chapter of this tutorial. +the plants topology in the figure. The main purpose of the heat pump is to deliver heat e.g. for the consumers of a heating system. Thus, the heat pump's parameters will be set in a way, which -supports this target. -Generally, if systems are getting more complex, it is highly recommended to set -up your plant in incremental steps. This tutorial divides the plant in three -sections: The consumer part, the valve and the evaporator and the compressor as -last element. Each new section will be appended to the existing ones. +supports this target. Generally, if systems are getting more complex, it is +highly recommended to set up your plant in incremental steps. This tutorial +divides the plant in three sections: The consumer part, the valve and the +evaporator and the compressor as last element. Each new section will be +appended to the existing ones. +The system will be built up in a way, that independent of what working fluid +we use, we will be able to generate stable starting values. After achieving +that, the final parameters are specified instead of the initial values. Set up a Network ^^^^^^^^^^^^^^^^ @@ -45,7 +47,8 @@ example we will work with water (H\ :sub:`2`\O) and ammonia (NH\ :sub:`3`\). Water is used for the cold side of the heat exchanger, for the consumer and for the hot side of the environmental temperature. Ammonia is used as coolant within the heat pump circuit. If you don’t specify the unit system, the -variables are set to SI-Units. +variables are set to SI-Units. We also keep the working fluid a variable to +make reusing the script with a different working fluid easy. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python @@ -130,17 +133,18 @@ is used in a later step. Parametrization +++++++++++++++ -For the condenser we set pressure ratios on hot and cold side and additionally -we set a value for the upper terminal temperature difference as design -parameter and the heat transfer coefficient as offdesign parameter. The -consumer will have pressure losses, too. Further we set the isentropic -efficiency for the pump, the offdesign efficiency is calculated with a -characteristic function. Thus, we set the efficiency as design parameter and -the characteristic function as offdesign parameter. In offdesign calculation -the consumer's pressure ratio will be a function of the mass flow, thus as -offdesign parameter we select zeta. The most important parameter is the -consumer's heat demand since it decides the overall mass flow in the systems. -We marked this setting as :code:`"key parameter"`. +For the condenser we set pressure ratios on hot and cold side. The consumer +will have pressure losses, too. Further we set the isentropic efficiency for +the pump. The most important parameter is the consumer's heat demand since it +decides the overall mass flow in the systems. + +.. tip:: + + In this tutorial we will first build the system with parameters that + ensure stable starting values for a simulation, which in the end will be + switched to reasonable values for the individual parts of the system. For + example, instead of the evaporation pressure we will use the terminal + temperature difference at the condenser instead. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python @@ -149,27 +153,32 @@ We marked this setting as :code:`"key parameter"`. In order to calculate this network further parametrization is necessary, as e.g. the fluids are not determined yet: At the hot inlet of the condenser we -define the temperature and the fluid vector. In order to fully determine the -fluid's state at this point, an information on the pressure is required. This -is achieved by setting the terminal temperature difference (see above). The -same needs to be done for the consumer cycle. We suggest to set the parameters -at the pump's inlet. On top, we assume that the consumer requires a constant -inlet temperature. The :code:`CycleCloser` automatically makes sure, that the -fluid's state at the consumer's outlet is the same as at the pump's inlet. +define the temperature, pressure and the fluid vector. A good guess for +pressure can be obtained from CoolProp's PropsSI function. We know that the +condensation temperature must be higher than the consumer's feed flow +temperature. Therefore we can set the pressure to a slightly higher value of +that temperature's corresponding condensation pressure. + +The same needs to be done for the consumer cycle. We suggest to set +the parameters at the pump's inlet. On top, we assume that the consumer +requires a constant inlet temperature. The :code:`CycleCloser` automatically +makes sure, that the fluid's state at the consumer's outlet is the same as at +the pump's inlet. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python :start-after: [sec_5] :end-before: [sec_6] +Solve ++++++ +After creating the system, we want to solve our network. Until we have not +set up the full system we will run design case calculations. + .. note:: In TESPy there are two different types of calculations: design point and - offdesign calculation. All parameters specified in the design attribute of - a component or connection, will be unset in a offdesign calculation, all - parameters specified in the offdesign attribute of a component or - connection will be set for the offdesign calculation. The value for these - parameters is the value derived from the design-calculation. + offdesign calculation. Generally, the design calculation is used for designing your system in the way you want it to look like. This means, that you might want to specify a @@ -178,15 +187,8 @@ fluid's state at the consumer's outlet is the same as at the pump's inlet. offdesign calculations with TESPy. The offdesign calculation is used to predict the system's behavior at different points of operation. For this case, this might be different ambient temperature, different feed flow - temperature, or partial load. - -Solve -+++++ -After creating the system, we want to solve our network. First, we calculate -the design case and directly after we can perform the offdesign calculation. -Before finishing the full network, we do this without changing the value of -any parameters to test, if the calculation actually works. All results have -to be identical to the design case results, if no value was modified. + temperature, or partial load. Add the end of this tutorial, you will learn + how to run the offdesign calculation. .. seealso:: @@ -263,63 +265,28 @@ connections to the model: Parametrization +++++++++++++++ Previous parametrization stays untouched. Regarding the evaporator, we specify -pressure ratios on hot side as well as the lower terminal temperature -difference. This specification is similar to pinch point layout for waste heat -steam generators. The pressure ratio of the cold side *MUST NOT* be specified -in this setup as the drum imposes pressure equality for all inlets and outlets. - -We use the hot side pressure ratio and the lower terminal temperature -difference as design parameters and choose zeta as well as a characteristic -function referring to the area independent heat transfer coefficient as its -offdesign parameters. - -On top of that, the characteristic function of the evaporator should follow -the default characteristic line of 'EVAPORATING FLUID' on the cold side and -the default line 'DEFAULT' on the hot side. These lines are defined in the -:ref:`tespy_data_label`. +pressure ratios on hot side as well as the evaporation pressure, for which we +can obtain a good initial guess based on the ambient temperature level using +CoolProp. From this specification the pinch point layout will be a result, +similar as in waste heat steam generators. The pressure ratio of the cold side +*MUST NOT* be specified in this setup as the drum imposes pressure equality +for all inlets and outlets. The superheater will also use the pressure ratios on hot and cold side. -Further we set a value for the upper terminal temperature difference. For -offdesign and design parameter specification the same logic as for the -evaporator and the already existing part of the network is applied. The system -designer has to answer the question: Which parameters are design point -parameters and how does the component perform at a different operation point. +Further we set a value for the enthalpy at the working fluid side outlet. This +determines the degree of overheating and is again based on a good guess. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python :start-after: [sec_9] :end-before: [sec_10] -.. seealso:: - - If you want to learn more about handling characteristic functions you - should have a glance at the - :ref:`TESPy components section `. - Next step is the connection parametrization: The pressure in the drum and the enthalpy of the wet steam reentering the drum need to be determined. For the -enthalpy we can specify a reference of the circulating mass flow to the main -cycle mass flow. The pressure is achieved through the given lower terminal -temperature difference of the evaporator and its hot side outlet temperature. -As we have specified a terminal temperature difference at the evaporator's -cold side inlet (:code:`ttd_l`), it might be necessary to state a starting -value for the pressure or the state of the fluid (gaseous), as we are near to -the two-phase region. On the hot side inlet of the superheater we define the -temperature, pressure and the fluid. Since the pressure between superheater -and first compressor will be a result of the pressure losses in the -superheater and we set the terminal temperature difference there, bad starting -values will lead to a linear dependency, as a temperature and a pressure are -set while the fluid's state could be within the two phase region. Thus, we -choose to specify :code:`state="g"`, so the solver will keep the fluid in -gaseous state at all times. At last we have to fully determine the state of -the incoming fluid at the superheater's hot side. - -.. attention:: - - Do only use the :code:`state` keyword if you know the fluid's state prior - to the simulation. If you specify the fluid to be gaseous but the correct - result of the simulation would be within the two-phase region, your - calculation most likely will not converge. +enthalpy we can specify the vapor mass fraction :code:`x` determining the +degree of evaporation. On the hot side inlet of the superheater we define the +temperature, pressure and the fluid. At last we have to fully determine the +state of the incoming fluid at the superheater's hot side. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python @@ -340,12 +307,11 @@ better convergence. Compressor system ^^^^^^^^^^^^^^^^^ To complete the heat pump, we will add the compressor system to our existing -network. This requires to change the connections 0, 6 and 13. The connection 6 +network. This requires to change the connections 0, 6 and 17. The connection 6 has to be changed to include the compressor. After the last compressor stage, connection 0 has to redefined, since we need to include the CycleCloser of the -working fluid's cycle. The connection 13 has to be connected to the heat -exchanger for intermittent cooling and finally with a pump to make the water -from the ambient heat source flow through the heat exchangers. +working fluid's cycle. The connection 17 has to be connected to the heat +exchanger for intermittent cooling as well as the bypass. .. figure:: /_static/images/tutorials/heat_pump_stepwise/flowsheet.svg :align: center @@ -365,10 +331,11 @@ Components ++++++++++ This part contains two compressors with intermittent cooling between them. The cold side of the heat exchanger will be connected to a pump upstream and to -the superheater downstream. We will also replace the source for the coolant -of :code:`c0` at the condenser with another CycleCloser (:code:`cool_closer`), -to make sure the fluid properties after the second compressor are identical to -the fluid properties at the condenser's inlet. +the superheater downstream. The bypass is used to give the system flexibility +in the temperature levels between the heat exchangers. We will also replac +the source for the coolant of :code:`c0` at the condenser with another +CycleCloser to make sure the fluid properties after the second compressor are +identical to the fluid properties at the condenser's inlet. .. tip:: @@ -386,8 +353,8 @@ the fluid properties at the condenser's inlet. Connections +++++++++++ -Consequently to the addition of the cycle closer we have to adjust the -connection definition touching the new cycle closer. +We remove connections 0, 6 and 13 from the network, define the new connections +and add them again. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python @@ -396,79 +363,125 @@ connection definition touching the new cycle closer. Parametrization +++++++++++++++ -For the two compressor we defined an isentropic efficiency and for the -offdesign calculation a generic characteristic line for the isentropic -efficiency will be applied. The first compressor has a fixed pressure ratio, -the seconds compressor pressure ratio will result from the required pressure -at the condenser. The heat exchanger comes with pressure ratios on both sides. -The parametrization of all other components remains identical. +For the first compressor we set the pressure ratio to the square root of the +full pressure ration between condensation and evaporation. In the first step, +we do not impose isentropic efficiency, because the respective equations are +quite sensitive to good starting value. We will set these values after the +full system has been calculated. The pump's isentropic efficiency value is not +as critical, therefore we set this value. The intermittent cooling imposes +pressure losses on both sides. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python :start-after: [sec_14] :end-before: [sec_15] -.. code-block:: python +Regarding the connections we set enthalpy values for all working fluid side +connections. After the superheater and intermittent cooling the value will be +near saturation (enthalpy value of connection c5), after the compressors it +will be higher. - cp1.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) - cp2.set_attr(eta_s=0.8, pr=5, design=['eta_s'], offdesign=['eta_s_char']) - he.set_attr(pr1=0.99, pr2=0.98, design=['pr1', 'pr2'], - offdesign=['zeta1', 'zeta2', 'kA_char']) +For the ambient side, we set temperature, pressure and fluid +at connection 11. On top of that, we can specify the temperature of the +ambient water after leaving the intermittent cooler. -Regarding the connections, on the hot side after the intercooler we set the -temperature. For the cold side of the heat exchanger we set the temperature, -the pressure and the fluid on the inlet flow, at the outlet we specify the -temperature as a design parameter. In offdesign calculation, this will be a -result from the given heat transfer coefficient (see parametrisation of -intercooler, kA_char is an offdesign parameter). Last, make sure the fluid -properties after the compressor outlet are identical to those at the condenser -inlet using the references. - -The last step leads to a necessary redefinition of the parametrization of the -existing model: As the enthalpy at the outlet of the second compressor is a -result of the given pressure ratio and the isentropic efficiency, it is not -allowed to set the temperature at the condenser's hot inlet anymore. +With readding of connection 0 we have to set the fluid and the pressure again, +but not the temperature value, because this value will be a result of the +condensation pressure and the given enthalpy at the compressor's outlet. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python :start-after: [sec_15] :end-before: [sec_16] -.. code-block:: python +Solve and Set Final System Parameters ++++++++++++++++++++++++++++++++++++++ +Now we solve again. After that, we can exchange our good guesses with actual +useful parameters: - # condenser system +The condensation and evaporation pressure levels will be replaced by terminal +temperature values of the condenser and the evaporator respectively. The lower +terminal temperature value of the evaporator :code:`ttd_l` defines the pinch +point. The upper terminal temperature value :code:`ttd_u` of the condenser +defines the condensation pressure. - c_in_cd.set_attr(fluid={'water': 0, 'NH3': 1}) +The degree of superheating in the superheater will be determined by the upper +terminal temperature instead of the enthalpy value at connection 6. The outlet +enthalpies after both compressors are replaced by the isentropic efficiency +values. Finally, the enthalpy after the intermittent cooling is replaced by +the temperature difference to the boiling point. With this we can ensure, the +working fluid does not start to condensate at the intermittent cooler. - # compressor-system +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_16] + :end-before: [sec_17] - he_cp2.set_attr(T=40, p0=10) - ic_in_he.set_attr(p=5, T=20, fluid={'water': 1, 'NH3': 0}) - he_ic_out.set_attr(T=30, design=['T']) +Calculate Partload Performance +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +After setting up the full system, we want to predict partload operation at +different values for the consumer's heat demand. Some of the values utilized +in the previous setup will change, if a component is not operated at its +design point. This is individual to every system, so the designer has to +answer the question: Which parameters are design point parameters and how does +the component perform at a different operation point. -Solve -+++++ +.. tip:: + + To make the necessary changes to the model, we can specify a design and an + offdesign attribute, both lists containing component or connection + parameter names. All parameters specified in the design attribute of a + component or connection, will be unset in a offdesign calculation, all + parameters specified in the offdesign attribute of a component or + connection will be set for the offdesign calculation. The value for these + parameters is the value derived from the design-calculation. -Here again, using the saved results from previous calculations is always -favorable, but with manually adjusted starting values and the :code:`state` -specifier, the calculation should still converge. If you want to use the -previous part to initialise start the solver with +The changes we want to apply can be summarized as follows: + +- All heat exchangers should be calculated based on their heat transfer + coefficient with a characteristic for correction of that value depending + on the change of mass flow (:code:`kA_char`). Therefore terminal temperature + value specifications need to be added to the design parameters. Also, the + temperature at connection 14 cannot be specified anymore, since it will be a + result of the intermittent cooler's characteristics. +- Pumps and compressors will have a characteristic function for their + isentropic efficiency instead of a constant value (:code:`eta_s_char`). +- Pressure drops in components will be a result of the changing mass flow + through that component given the diameter in the design. The pressure ratio + will therefore be replaced by :code:`zeta` for all heat exchangers. The zeta + value is a geometry independent value. + +On top of that, for the evaporator the characteristic function of the heat +transfer coefficient should follow different data than the default +characteristic. The name of that line is 'EVAPORATING FLUID' for the cold +side. The default line 'DEFAULT' will be kept for the hot side. These lines +are available in the :ref:`tespy.data ` module. + +.. attention:: + + If you run the offdesign simulation without any changes in the + specification values, the results must be identical as in the respective + design case! If they are not, it is likely, something went wrong. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python - :start-after: [sec_16] - :end-before: [sec_17] + :start-after: [sec_17] + :end-before: [sec_18] -.. code-block:: python +.. seealso:: - nw.solve('design', init_path='condenser') + If you want to learn more about handling characteristic functions you + should have a glance at the + :ref:`TESPy components section `. +Finally, we can change the heat demand and run several offdesign calculations +to calculate the partload COP value. -Explore Partload Performance -++++++++++++++++++++++++++++ +.. literalinclude:: /../tutorial/advanced/stepwise.py + :language: python + :start-after: [sec_18] + :end-before: [sec_19] -Further tasks -^^^^^^^^^^^^^ After successfully modeling the heat pump in design and offdesign cases, you can now start using your model for further calculations. For example, if you have a time series of required heat flow of your consumer, you can loop over diff --git a/tutorial/advanced/stepwise.py b/tutorial/advanced/stepwise.py index 7f0b8bd3d..7c850fe0d 100644 --- a/tutorial/advanced/stepwise.py +++ b/tutorial/advanced/stepwise.py @@ -1,8 +1,9 @@ # %%[sec_1] from tespy.networks import Network +working_fluid = "NH3" nw = Network( - fluids=["water", "NH3"], + fluids=["water", working_fluid], T_unit="C", p_unit="bar", h_unit="kJ / kg", m_unit="kg / s" ) # %%[sec_2] @@ -35,15 +36,14 @@ nw.add_conns(c0, c1, c20, c21, c22, c23) # %%[sec_4] -cd.set_attr( - pr1=0.99, pr2=0.99, ttd_u=5, - design=["pr2", "ttd_u"], offdesign=["zeta2", "kA_char"] -) -rp.set_attr(eta_s=0.8, design=["eta_s"], offdesign=["eta_s_char"]) -cons.set_attr(pr=0.99, design=["pr"], offdesign=["zeta"]) +cd.set_attr(pr1=0.99, pr2=0.99) +rp.set_attr(eta_s=0.75) +cons.set_attr(pr=0.99) # %%[sec_5] -c0.set_attr(T=170, fluid={"water": 0, "NH3": 1}) -c20.set_attr(T=60, p=2, fluid={"water": 1, "NH3": 0}) +from CoolProp.CoolProp import PropsSI as PSI +p_cond = PSI("P", "Q", 1, "T", 273.15 + 95, working_fluid) / 1e5 +c0.set_attr(T=170, p=p_cond, fluid={"water": 0, working_fluid: 1}) +c20.set_attr(T=60, p=2, fluid={"water": 1, working_fluid: 0}) c22.set_attr(T=90) # key design paramter @@ -51,12 +51,6 @@ # %%[sec_6] nw.solve("design") nw.print_results() -nw.save("consumer_part") - -# run an offdesign test: without modifying any value it should give you -# the same results as the design calculation -nw.solve("offdesign", design_path="consumer_part") -nw.print_results() # %%[sec_7] from tespy.components import Valve, Drum, HeatExchanger @@ -85,44 +79,139 @@ nw.add_conns(c1, c2, c3, c4, c5, c6) -c13 = Connection(amb_in, "out1", su, "in1", label="13") -c14 = Connection(su, "out1", ev, "in1", label="14") -c15 = Connection(ev, "out1", amb_out, "in1", label="15") +c17 = Connection(amb_in, "out1", su, "in1", label="17") +c18 = Connection(su, "out1", ev, "in1", label="18") +c19 = Connection(ev, "out1", amb_out, "in1", label="19") -nw.add_conns(c13, c14, c15) +nw.add_conns(c17, c18, c19) # %%[sec_9] -from tespy.tools.characteristics import CharLine -from tespy.tools.characteristics import load_default_char as ldc -# evaporator system - -kA_char1 = ldc('heat exchanger', 'kA_char1', 'DEFAULT', CharLine) -kA_char2 = ldc('heat exchanger', 'kA_char2', 'EVAPORATING FLUID', CharLine) - -ev.set_attr( - pr1=0.99, ttd_l=5, kA_char1=kA_char1, kA_char2=kA_char2, - design=['pr1', 'ttd_l'], offdesign=['zeta1', 'kA_char'] -) -su.set_attr( - pr1=0.99, pr2=0.99, ttd_u=2, - design=['pr1', 'pr2', 'ttd_u'], offdesign=['zeta1', 'zeta2', 'kA_char'] -) +ev.set_attr(pr1=0.99) +su.set_attr(pr1=0.99, pr2=0.99) # %%[sec_10] -from tespy.connections import Ref # evaporator system cold side -c3.set_attr(m=Ref(c2, 0.75, 0)) -# we provide this keyword for numerical stability -c6.set_attr(state="g") +p_evap = PSI("P", "Q", 1, "T", 273.15 + 5, working_fluid) / 1e5 +c4.set_attr(x=0.9, p=p_evap) + +h_sat = PSI("H", "Q", 1, "T", 273.15 + 15, working_fluid) / 1e3 +c6.set_attr(h=h_sat) # evaporator system hot side -c13.set_attr(T=15, fluid={'water': 1, 'NH3': 0}) -c15.set_attr(T=9, p=1.013) +c17.set_attr(T=15, fluid={"water": 1, working_fluid: 0}) +c19.set_attr(T=9, p=1.013) # %%[sec_11] nw.solve("design") nw.print_results() -nw.save("evaporator_part") - -# run the offdesign test -nw.solve("offdesign", design_path="evaporator_part") -nw.print_results() # %%[sec_12] +from tespy.components import Compressor, Splitter, Merge + +cp1 = Compressor("compressor 1") +cp2 = Compressor("compressor 2") + +ic = HeatExchanger("intermittent cooling") +hsp = Pump("heat source pump") + +sp = Splitter("splitter") +me = Merge("merge") +cv = Valve("control valve") + +hs = Source("ambient intake") +cc = CycleCloser("heat pump cycle closer") +# %%[sec_13] +nw.del_conns(c0, c6, c17) + +c6 = Connection(su, "out2", cp1, "in1", label="6") +c7 = Connection(cp1, "out1", ic, "in1", label="7") +c8 = Connection(ic, "out1", cp2, "in1", label="8") +c9 = Connection(cp2, "out1", cc, "in1", label="9") +c0 = Connection(cc, "out1", cd, "in1", label="0") + +c11 = Connection(hs, "out1", hsp, "in1", label="11") +c12 = Connection(hsp, "out1", sp, "in1", label="12") +c13 = Connection(sp, "out1", ic, "in2", label="13") +c14 = Connection(ic, "out2", me, "in1", label="14") +c15 = Connection(sp, "out2", cv, "in1", label="15") +c16 = Connection(cv, "out1", me, "in2", label="16") +c17 = Connection(me, "out1", su, "in1", label="17") + +nw.add_conns(c6, c7, c8, c9, c0, c11, c12, c13, c14, c15, c16, c17) +# %%[sec_14] +pr = (c1.p.val / c5.p.val) ** 0.5 +cp1.set_attr(pr=pr) +ic.set_attr(pr1=0.99, pr2=0.98) +hsp.set_attr(eta_s=0.75) +# %%[sec_15] +c0.set_attr(p=p_cond, fluid={"water": 0, working_fluid: 1}) + +c6.set_attr(h=c5.h.val + 10) +c8.set_attr(h=c5.h.val + 10) + +c7.set_attr(h=c5.h.val * 1.2) +c9.set_attr(h=c5.h.val * 1.2) + +c11.set_attr(p=1.013, T=15, fluid={"water": 1, working_fluid: 0}) +c14.set_attr(T=30) +# %% [sec_16] +nw.solve("design") +c0.set_attr(p=None) +cd.set_attr(ttd_u=5) + +c4.set_attr(p=None) +ev.set_attr(ttd_l=5) + +c6.set_attr(h=None) +su.set_attr(ttd_u=5) + +c7.set_attr(h=None) +cp1.set_attr(eta_s=0.8) + +c9.set_attr(h=None) +cp2.set_attr(eta_s=0.8) + +c8.set_attr(h=None, Td_bp=4) +nw.solve("design") +nw.save("system_design") +# %% [sec_17] +cp1.set_attr(design=["eta_s"], offdesign=["eta_s_char"]) +cp2.set_attr(design=["eta_s"], offdesign=["eta_s_char"]) +rp.set_attr(design=["eta_s"], offdesign=["eta_s_char"]) +hsp.set_attr(design=["eta_s"], offdesign=["eta_s_char"]) + +cons.set_attr(design=["pr"], offdesign=["zeta"]) + +cd.set_attr( + design=["pr2", "ttd_u"], offdesign=["zeta2", "kA_char"] +) + +from tespy.tools.characteristics import CharLine +from tespy.tools.characteristics import load_default_char as ldc + +kA_char1 = ldc("heat exchanger", "kA_char1", "DEFAULT", CharLine) +kA_char2 = ldc("heat exchanger", "kA_char2", "EVAPORATING FLUID", CharLine) +ev.set_attr( + kA_char1=kA_char1, kA_char2=kA_char2, + design=["pr1", "ttd_l"], offdesign=["zeta1", "kA_char"] +) + +su.set_attr( + design=["pr1", "pr2", "ttd_u"], offdesign=["zeta1", "zeta2", "kA_char"] +) + +ic.set_attr( + design=["pr1", "pr2"], offdesign=["zeta1", "zeta2", "kA_char"] +) +c14.set_attr(design=["T"]) +nw.solve("offdesign", design_path="system_design") +nw.print_results() +# %% [sec_18] +import numpy as np +nw.set_attr(iterinfo=False) + +for Q in np.linspace(1, 0.6, 5) * cons.Q.val: + cons.set_attr(Q=Q) + nw.solve("offdesign", design_path="system_design") + print( + "COP:", + abs(cons.Q.val) / (cp1.P.val + cp2.P.val + hsp.P.val + rp.P.val) + ) +# %% [sec_19] From 5190960817127d43d01d743401d1a6712dad38d1 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 3 Sep 2022 13:44:17 +0200 Subject: [PATCH 074/120] Clean up some residuals --- .../images/advanced/exergy/flowsheet.svg | 502 +++++++++--------- .../images/basics/district_heating.svg | 14 +- .../basics/district_heating_darkmode.svg | 14 +- docs/_static/images/basics/gas_turbine.svg | 10 +- .../images/basics/gas_turbine_darkmode.svg | 10 +- docs/_static/images/basics/heat_pump.svg | 12 +- .../images/basics/heat_pump_darkmode.svg | 12 +- .../images/basics/modeling_concept.svg | 12 +- docs/_static/images/basics/rankine_cycle.svg | 16 +- .../images/basics/rankine_cycle_darkmode.svg | 16 +- docs/_static/images/logo_tespy_big.svg | 2 +- .../images/logo_tespy_big_darkmode.svg | 2 +- .../images/logo_tespy_big_editable_font.svg | 2 +- docs/_static/images/logo_tespy_mid.svg | 2 +- .../images/logo_tespy_mid_darkmode.svg | 2 +- .../images/logo_tespy_mid_editable_font.svg | 2 +- docs/_static/images/logo_tespy_small.svg | 2 +- .../tutorials/heat_pump_exergy/flowsheet.svg | 24 +- .../heat_pump_exergy/flowsheet_darkmode.svg | 24 +- .../heat_pump_starting_values/flowsheet.svg | 32 +- .../flowsheet_darkmode.svg | 32 +- 21 files changed, 372 insertions(+), 372 deletions(-) diff --git a/docs/_static/images/advanced/exergy/flowsheet.svg b/docs/_static/images/advanced/exergy/flowsheet.svg index 8fdb0e9f4..812580de7 100644 --- a/docs/_static/images/advanced/exergy/flowsheet.svg +++ b/docs/_static/images/advanced/exergy/flowsheet.svg @@ -127,7 +127,7 @@ @@ -145,56 +145,56 @@ @@ -442,21 +442,21 @@ sodipodi:nodetypes="cc" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\meinm\Documents\1 Uni\8. Semester SS20\1 Bachelorarbeit\Inhalt\Abbildungen\SEGSvi_Tespy.png" + id="path976-3-0" d="M 75.000013,182 H 85" style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> @@ -464,21 +464,21 @@ sodipodi:nodetypes="cc" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\meinm\Documents\1 Uni\8. Semester SS20\1 Bachelorarbeit\Inhalt\Abbildungen\SEGSvi_Tespy.png" + id="path1060" d="m 68.999586,49.98381 49.934144,0.05203" style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> @@ -486,21 +486,21 @@ sodipodi:nodetypes="cc" inkscape:export-ydpi="1012" inkscape:export-xdpi="1012" - inkscape:export-filename="C:\Users\meinm\Documents\1 Uni\8. Semester SS20\1 Bachelorarbeit\Inhalt\Abbildungen\SEGSvi_Tespy.png" + id="path1069" d="M 239.06605,50.030067 264.00008,50" style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> @@ -2251,7 +2251,7 @@ x="295.95529" style="font-style:normal;font-weight:normal;font-size:3.29975px;line-height:1.25;font-family:sans-serif;fill:#ffb400;fill-opacity:1;stroke:none;stroke-width:0.176772" xml:space="preserve" - inkscape:export-filename="C:\Users\meinm\Documents\1 Uni\8. Semester SS20\1 Bachelorarbeit\Inhalt\Abbildungen\SEGSvi_Tespy.png" + inkscape:export-xdpi="1012" inkscape:export-ydpi="1012"> @@ -2280,7 +2280,7 @@ x="105.57789" style="font-style:normal;font-weight:normal;font-size:3.29975px;line-height:1.25;font-family:sans-serif;fill:#ffb400;fill-opacity:1;stroke:none;stroke-width:0.176772" xml:space="preserve" - inkscape:export-filename="C:\Users\meinm\Documents\1 Uni\8. Semester SS20\1 Bachelorarbeit\Inhalt\Abbildungen\SEGSvi_Tespy.png" + inkscape:export-xdpi="1012" inkscape:export-ydpi="1012"> @@ -2529,7 +2529,7 @@ x="251.82637" y="191.95308" id="text1317-3-5-2-9" - inkscape:export-filename="C:\Users\meinm\Documents\1 Uni\8. Semester SS20\1 Bachelorarbeit\Inhalt\Abbildungen\SEGSvi_Tespy.png" + inkscape:export-xdpi="1012" inkscape:export-ydpi="1012"> @@ -2780,7 +2780,7 @@ x="341.53827" style="font-style:normal;font-weight:normal;font-size:3.29975px;line-height:1.25;font-family:sans-serif;fill:#ffb400;fill-opacity:1;stroke:none;stroke-width:0.176772" xml:space="preserve" - inkscape:export-filename="C:\Users\meinm\Documents\1 Uni\8. Semester SS20\1 Bachelorarbeit\Inhalt\Abbildungen\SEGSvi_Tespy.png" + inkscape:export-xdpi="1012" inkscape:export-ydpi="1012"> @@ -265,7 +265,7 @@ @@ -265,7 +265,7 @@ @@ -247,7 +247,7 @@ @@ -266,7 +266,7 @@ @@ -266,7 +266,7 @@ @@ -265,7 +265,7 @@ @@ -265,7 +265,7 @@ @@ -259,7 +259,7 @@ @@ -568,7 +568,7 @@ @@ -259,7 +259,7 @@ @@ -568,7 +568,7 @@ Date: Sat, 3 Sep 2022 14:07:10 +0200 Subject: [PATCH 075/120] Finalize starting value tutorial --- .../heat_pump_starting_values/COP_by_wf.svg | 2417 ++++++++--------- docs/tutorials/starting_values.rst | 434 +-- tutorial/advanced/starting_values.py | 319 +++ 3 files changed, 1548 insertions(+), 1622 deletions(-) create mode 100644 tutorial/advanced/starting_values.py diff --git a/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg b/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg index bc7f3b70f..bf9935c84 100644 --- a/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg +++ b/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg @@ -1,1273 +1,1180 @@ - - - - - - - - 2022-08-14T11:47:38.613328 - image/svg+xml - - - Matplotlib v3.5.1, https://matplotlib.org/ - - - - - - - - - - - - + + + + + + + + 2022-09-03T14:01:02.045537 + image/svg+xml + + + Matplotlib v3.4.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + - - + + + + + + + + + - - + + + + + + + - - + + + + + + + + + - - + + + + + + + - - + + + + + + + + + - - + + + + + + + - - + + + + + + + + + - - + + + + + + + - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + diff --git a/docs/tutorials/starting_values.rst b/docs/tutorials/starting_values.rst index a21ed364c..8cd8c3eaa 100644 --- a/docs/tutorials/starting_values.rst +++ b/docs/tutorials/starting_values.rst @@ -2,24 +2,24 @@ How to Generate Stable Starting Values -------------------------------------- - Applying numerical algorithms and methods, the starting value of a variable is the value used for the first iteration. With more complex TESPy models -it can happen that the simulation does not converge easily due to a combination -of "bad" starting values. The solver is especially vulnerable if the specified -parameters trigger complex equations with respect to the primary variables. +it can happen that the simulation does not converge easily due to a +combination of "bad" starting values. The solver is especially vulnerable if +the specified parameters trigger complex equations with respect to the primary +variables. The primary variables of TESPy are mass flow, pressure, enthalpy and fluid composition. If such a value is directly specified by the user, the solver has a solution for this value before starting the first iteration. Therefore, -specifying a set of parameters largely including primary variables will improve -the convergence significantly. Based on the converged solution of a initial -simulation, it is then possible to adjust the parameters, for example, unsetting -pressure values and specifying efficiencies instead. +specifying a set of parameters largely including primary variables will +improve the convergence significantly. Based on the converged solution of a +initial simulation, it is then possible to adjust the parameters, for example, +unsetting pressure values and specifying efficiencies instead. -Here we provide a short tutorial for you to better understand, how this process -could look like at the example of a subcritical heat pump with different working -fluids. +Here we provide a short tutorial for you to better understand, how this +process could look like at the example of a subcritical heat pump with +different working fluids. .. note:: @@ -29,9 +29,8 @@ fluids. Topology of the heat pump ^^^^^^^^^^^^^^^^^^^^^^^^^ - -Following the first tutorial a slightly different topology for a heat pump with -internal heat exchangers is considered instead of dumping the heat to the +Following the first tutorial a slightly different topology for a heat pump +with internal heat exchangers is considered instead of dumping the heat to the ambient. You can see the plant topology in the figure below. .. figure:: /_static/images/tutorials/heat_pump_starting_values/flowsheet.svg @@ -52,92 +51,29 @@ The system consists of a consumer system, a valve, an evaporator system, a compressor and additionally an internal heat exchanger. In order to simulate this heat pump, the TESPy model has to be built up. First, the network has to be initialized and the refrigerants used have to be specified. This example -shows how to make the heat pump model work with a variety of working fluids with -water on both the heat source and heat sink side of the system. +shows how to make the heat pump model work with a variety of working fluids +with water on both the heat source and heat sink side of the system. Running into errors ^^^^^^^^^^^^^^^^^^^ - As always, we start by importing the necessary TESPy classes. -.. code-block:: python - - from tespy.networks import Network - - from tespy.components import ( - Condenser, Compressor, CycleCloser, HeatExchanger, - HeatExchangerSimple, Pump, Sink, Source, Valve - ) - - from tespy.connections import Connection, Ref, Bus +.. literalinclude:: /../tutorial/advanced/starting_values.py + :language: python + :start-after: [sec_1] + :end-before: [sec_2] Then, we can build the network by defining components and connections. The working fluid will be set with the variable `wf`, `"NH3"` is used in the first -setup. This way, we will be able to change the working fluid in a flexible way. - -.. code-block:: python - - wf = 'NH3' - - # network - nw = Network( - fluids=['water', wf], - T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s' - ) - - # components - cycle_closer = CycleCloser('Refrigerant Cycle Closer') - - # heat source - heatsource_feedflow = Source('Heat Source Feed Flow') - heatsource_pump = Pump('Heat Source Recirculation Pump') - heatsource_evaporator = HeatExchanger('Heat Source Evaporator') - heatsource_backflow = Sink('Heat Source Back Flow') - - # compression - compressor = Compressor('Compressor') - - # heat sink - cons_pump = Pump('Heat Sink Recirculation Pump') - condenser = Condenser('Heat Sink Condenser') - cons_heatsink = HeatExchangerSimple('Heat Consumer') - cons_cycle_closer = CycleCloser('Consumer Feed Flow') - - # internal heat exchange - int_heatex = HeatExchanger('Internal Heat Exchanger') - - # expansion - valve = Valve('Expansion Valve') - - # connections - # main cycle - cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0') - hs_eva2int_heatex = Connection(heatsource_evaporator, 'out2', int_heatex, 'in2', label='1') - int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='2') - comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='3') - cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='4') - int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='5') - valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='6') - - nw.add_conns( - cc2hs_eva, hs_eva2int_heatex, int_heatex2comp, comp2cond, cond2int_heatex, - int_heatex2valve, valve2cc - ) - - # heat source - hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='11') - hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='12') - hs_eva2hs_back = Connection(heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='13') - - nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back) +setup. This way, we will be able to change the working fluid in a flexible +way. - # heat sink - cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='21') - cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='22') - cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='23') - cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='24') +.. dropdown:: Display source code of the full code - nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed) + .. literalinclude:: /../tutorial/advanced/starting_values.py + :language: python + :start-after: [sec_2] + :end-before: [sec_3] After setting up the topology, the system's parameters should be set in the following way: @@ -155,48 +91,12 @@ following way: - Pressure losses in all heat exchangers (`pr1`, `pr2`, `pr`) - Consumer heat demand (`Q`) -.. code-block:: python - - # parametrization connections - # set feedflow and backflow temperature of heat source and consumer - T_hs_bf = 10 - T_hs_ff = 15 - T_cons_bf = 50 - T_cons_ff = 90 - - # consumer cycle - cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, wf: 0}) - cons_hs2cons_feed.set_attr(T=T_cons_bf) - - # heat source cycle - hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, wf: 0}) - hs_eva2hs_back.set_attr(T=T_hs_bf, p=1) - - # evaporation to fully saturated gas - hs_eva2int_heatex.set_attr(x=1, fluid={'water': 0, wf: 1}) - # degree of overheating after internal heat exchanger (evaporation side) - int_heatex2comp.set_attr(Td_bp=10) - - # parametrization components - # isentropic efficiency - cons_pump.set_attr(eta_s=0.8) - heatsource_pump.set_attr(eta_s=0.8) - compressor.set_attr(eta_s=0.85) - - # pressure ratios - condenser.set_attr(pr1=0.98, pr2=0.98) - heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98) - cons_heatsink.set_attr(pr=0.99) - int_heatex.set_attr(pr1=0.98, pr2=0.98) - - # temperature differences - heatsource_evaporator.set_attr(ttd_l=5) - condenser.set_attr(ttd_u=5) - - # consumer heat demand - cons_heatsink.set_attr(Q=-1e6) +.. dropdown:: Display source code of the full code - nw.solve('design') + .. literalinclude:: /../tutorial/advanced/starting_values.py + :language: python + :start-after: [sec_3] + :end-before: [sec_4] The system should be well defined with the parameter settings, however no solution can be found. We might run in some error, like @@ -244,256 +144,56 @@ which you can see in the figure below. Figure: Logph diagram of ammonia -A rough estimation of the evaporation and condensation pressure can be obtained -and will be used to replace the temperature differences at the evaporator and -the condenser for the starting value generator. After condensation, the working -fluid is in saturated liquid state. We can retrieve the condensation pressure -corresponding to a temperature slightly below the heat sink temperature by using -the CoolProp `PropsSI` interface with the respective inputs. The same step can -be carried out on the heat source side. For the internal heat exchanger, an -enthalpy value is specified instead of the temperature difference to the boiling -point as well. It is important to note that the PropertySI function (PropsSI) is -used with SI units, which differ from the units defined in the network. - -The temperature difference values are unset and pressure and enthalpy values are -set instead. - -.. code-block:: python - - import CoolProp.CoolProp as CP - - # evaporation point - p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-5 - hs_eva2int_heatex.set_attr(p=p_eva) - heatsource_evaporator.set_attr(ttd_l=None) - - # condensation point - p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273.15, wf) * 1e-5 - cond2int_heatex.set_attr(p=p_cond) - condenser.set_attr(ttd_u=None) - - # internal heat exchanger to compressor enthalpy - h_evap = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-3 - int_heatex2comp.set_attr(Td_bp=None, h=h_evap * 1.01) - - # solve the network again - nw.solve('design') - +A rough estimation of the evaporation and condensation pressure can be +obtained and will be used to replace the temperature differences at the +evaporator and the condenser for the starting value generator. After +condensation, the working fluid is in saturated liquid state. We can retrieve +the condensation pressure corresponding to a temperature slightly below the +heat sink temperature by using the CoolProp `PropsSI` interface with the +respective inputs. The same step can be carried out on the heat source side. +For the internal heat exchanger, an enthalpy value is specified instead of the +temperature difference to the boiling point as well. It is important to note +that the PropertySI function (PropsSI) is used with SI units, which differ +from the units defined in the network. + +The temperature difference values are unset and pressure and enthalpy values +are set instead. + +.. literalinclude:: /../tutorial/advanced/starting_values.py + :language: python + :start-after: [sec_4] + :end-before: [sec_5] The model was solved successfully and has stored the starting values for any follow-up. Therefore, we can undo our recent changes and restart the simulation. For example, the COP is then calculated. -.. code-block:: python - - # evaporation point - hs_eva2int_heatex.set_attr(p=None) - heatsource_evaporator.set_attr(ttd_l=5) - - # condensation point - cond2int_heatex.set_attr(p=None) - condenser.set_attr(ttd_u=5) - - # internal heat exchanger superheating - int_heatex2comp.set_attr(Td_bp=5, h=None) - - # solve the network again - nw.solve('design') - - # calculate the COP - cop = abs( - cons_heatsink.Q.val - / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val) - ) +.. literalinclude:: /../tutorial/advanced/starting_values.py + :language: python + :start-after: [sec_5] + :end-before: [sec_6] Expand fix to any working fluids ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Finally, using this strategy, it is possible to build a generic function, building a network, that works with a variety of working fluids. .. dropdown:: Display source code of the full code - .. code-block:: python - - import matplotlib.pyplot as plt - import pandas as pd - - from tespy.networks import Network - from tespy.components import ( - Condenser, Compressor, CycleCloser, HeatExchanger, - HeatExchangerSimple, Pump, Sink, Source, Valve - ) - from tespy.connections import Connection, Ref, Bus - import CoolProp.CoolProp as CP - - - def generate_starting_values(wf): - - # network - nw = Network( - fluids=['water', wf], - T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s', - iterinfo=False - ) - - # components - cycle_closer = CycleCloser('Refrigerant Cycle Closer') - - # heat source - heatsource_feedflow = Source('Heat Source Feed Flow') - heatsource_pump = Pump('Heat Source Recirculation Pump') - heatsource_evaporator = HeatExchanger('Heat Source Evaporator') - heatsource_backflow = Sink('Heat Source Back Flow') - - # compression - compressor = Compressor('Compressor') - - # heat sink - cons_pump = Pump('Heat Sink Recirculation Pump') - condenser = Condenser('Heat Sink Condenser') - cons_heatsink = HeatExchangerSimple('Heat Consumer') - cons_cycle_closer = CycleCloser('Consumer Feed Flow') - - # internal heat exchange - int_heatex = HeatExchanger('Internal Heat Exchanger') - - # expansion - valve = Valve('Expansion Valve') - - # connections - # main cycle - cc2hs_eva = Connection(cycle_closer, 'out1', heatsource_evaporator, 'in2', label='0') - hs_eva2int_heatex = Connection(heatsource_evaporator, 'out2', int_heatex, 'in2', label='1') - int_heatex2comp = Connection(int_heatex, 'out2', compressor, 'in1', label='2') - comp2cond = Connection(compressor, 'out1', condenser, 'in1', label='3') - cond2int_heatex = Connection(condenser, 'out1', int_heatex, 'in1', label='4') - int_heatex2valve = Connection(int_heatex, 'out1', valve, 'in1', label='5') - valve2cc = Connection(valve, 'out1', cycle_closer, 'in1', label='6') - - nw.add_conns( - cc2hs_eva, hs_eva2int_heatex, int_heatex2comp, comp2cond, cond2int_heatex, - int_heatex2valve, valve2cc - ) - - # heat source - hs_feed2hs_pump = Connection(heatsource_feedflow, 'out1', heatsource_pump, 'in1', label='11') - hs_pump2hs_eva = Connection(heatsource_pump, 'out1', heatsource_evaporator, 'in1', label='12') - hs_eva2hs_back = Connection(heatsource_evaporator, 'out1', heatsource_backflow, 'in1', label='13') - - nw.add_conns(hs_feed2hs_pump, hs_pump2hs_eva, hs_eva2hs_back) - - # heat sink - cons_back2cons_pump = Connection(cons_cycle_closer, 'out1', cons_pump, 'in1', label='20') - cons_pump2cond = Connection(cons_pump, 'out1', condenser, 'in2', label='21') - cond2cons_hs = Connection(condenser, 'out2', cons_heatsink, 'in1', label='22') - cons_hs2cons_feed = Connection(cons_heatsink, 'out1', cons_cycle_closer, 'in1', label='23') - - nw.add_conns(cons_back2cons_pump, cons_pump2cond, cond2cons_hs, cons_hs2cons_feed) - - # set feedflow and backflow temperature of heat source and consumer - T_hs_bf = 10 - T_hs_ff = 15 - T_cons_bf = 50 - T_cons_ff = 90 - - # consumer cycle - cond2cons_hs.set_attr(T=T_cons_ff, p=10, fluid={'water': 1, wf: 0}) - cons_hs2cons_feed.set_attr(T=T_cons_bf) - - # heat source cycle - hs_feed2hs_pump.set_attr(T=T_hs_ff, p=1, fluid={'water': 1, wf: 0}) - hs_eva2hs_back.set_attr(T=T_hs_bf, p=1) - - # evaporation to fully saturated gas - hs_eva2int_heatex.set_attr(x=1, fluid={'water': 0, wf: 1}) - - # parametrization components - # isentropic efficiency - cons_pump.set_attr(eta_s=0.8) - heatsource_pump.set_attr(eta_s=0.8) - compressor.set_attr(eta_s=0.85) - - # pressure ratios - condenser.set_attr(pr1=0.98, pr2=0.98) - heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98) - cons_heatsink.set_attr(pr=0.99) - int_heatex.set_attr(pr1=0.98, pr2=0.98) - - # evaporation point - p_eva = CP.PropsSI('P', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-5 - hs_eva2int_heatex.set_attr(p=p_eva) - - # condensation point - p_cond = CP.PropsSI('P', 'Q', 0, 'T', T_cons_ff + 5 + 273.15, wf) * 1e-5 - cond2int_heatex.set_attr(p=p_cond) - - # internal heat exchanger to compressor enthalpy - h_evap = CP.PropsSI('H', 'Q', 1, 'T', T_hs_bf - 5 + 273.15, wf) * 1e-3 - int_heatex2comp.set_attr(h=h_evap * 1.01) + .. literalinclude:: /../tutorial/advanced/starting_values.py + :language: python + :start-after: [sec_6] + :end-before: [sec_7] - # consumer heat demand - cons_heatsink.set_attr(Q=-1e6) +We can run that function for different working fluids and plot the results: - power_bus = Bus('Total power input') - heat_bus = Bus('Total heat production') - power_bus.add_comps( - {'comp': compressor, 'base': 'bus'}, - {'comp': cons_pump, 'base': 'bus'}, - {'comp': heatsource_pump, 'base': 'bus'}, - ) - heat_bus.add_comps({'comp': cons_heatsink}) +.. literalinclude:: /../tutorial/advanced/starting_values.py + :language: python + :start-after: [sec_7] + :end-before: [sec_8] - nw.add_busses(power_bus, heat_bus) - - nw.solve('design') - - # evaporation point - hs_eva2int_heatex.set_attr(p=None) - heatsource_evaporator.set_attr(ttd_l=5) - - # condensation point - cond2int_heatex.set_attr(p=None) - condenser.set_attr(ttd_u=5) - - # internal heat exchanger superheating - int_heatex2comp.set_attr(Td_bp=5, h=None) - - # solve the network again - nw.solve('design') - - return nw - - - cop = pd.DataFrame(columns=["COP"]) - - for wf in ['NH3', 'R22', 'R134a', 'R152a', 'R290', 'R718']: - nw = generate_starting_values(wf) - - power = nw.busses['Total power input'].P.val - heat = abs(nw.busses['Total heat production'].P.val) - cop.loc[wf] = heat / power - - - fig, ax = plt.subplots(1) - - cop.plot.bar(ax=ax, legend=False) - - ax.set_axisbelow(True) - ax.yaxis.grid(linestyle='dashed') - ax.set_xlabel('Name of working fluid') - ax.set_ylabel('Coefficicent of performance') - ax.set_title('Coefficicent of performance for different working fluids') - plt.tight_layout() - - fig.savefig('COP_by_wf.svg') - - - .. figure:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg - :align: center - :alt: Analysis of the COP using different working fluids - - Figure: Analysis of the COP using different working fluids +.. figure:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg + :align: center + :alt: Analysis of the COP using different working fluids -Of course, there are different strategies, which include building the plant -step by step and successively adding more and more components. + Figure: Analysis of the COP using different working fluids diff --git a/tutorial/advanced/starting_values.py b/tutorial/advanced/starting_values.py new file mode 100644 index 000000000..00f5036a7 --- /dev/null +++ b/tutorial/advanced/starting_values.py @@ -0,0 +1,319 @@ +# %%[sec_1] +from tespy.networks import Network + +from tespy.components import ( + Condenser, Compressor, CycleCloser, HeatExchanger, + HeatExchangerSimple, Pump, Sink, Source, Valve + ) + +from tespy.connections import Connection, Ref, Bus +# %%[sec_2] +wf = "NH3" + +# network +nw = Network( + fluids=["water", wf], + T_unit="C", p_unit="bar", h_unit="kJ / kg", m_unit="kg / s" + ) + +# components +cycle_closer = CycleCloser("Refrigerant Cycle Closer") + +# heat source +heatsource_feedflow = Source("Heat Source Feed Flow") +heatsource_pump = Pump("Heat Source Recirculation Pump") +heatsource_evaporator = HeatExchanger("Heat Source Evaporator") +heatsource_backflow = Sink("Heat Source Back Flow") + +# compression +compressor = Compressor("Compressor") + +# heat sink +cons_pump = Pump("Heat Sink Recirculation Pump") +condenser = Condenser("Heat Sink Condenser") +cons_heatsink = HeatExchangerSimple("Heat Consumer") +cons_cycle_closer = CycleCloser("Consumer Feed Flow") + +# internal heat exchange +int_heatex = HeatExchanger("Internal Heat Exchanger") + +# expansion +valve = Valve("Expansion Valve") + +# connections +# main cycle +c0 = Connection(cycle_closer, "out1", heatsource_evaporator, "in2", label="0") +c1 = Connection(heatsource_evaporator, "out2", int_heatex, "in2", label="1") +c2 = Connection(int_heatex, "out2", compressor, "in1", label="2") +c3 = Connection(compressor, "out1", condenser, "in1", label="3") +c4 = Connection(condenser, "out1", int_heatex, "in1", label="4") +c5 = Connection(int_heatex, "out1", valve, "in1", label="5") +c6 = Connection(valve, "out1", cycle_closer, "in1", label="6") + +nw.add_conns( + c0, c1, c2, c3, c4, + c5, c6 + ) + +# heat source +c11 = Connection(heatsource_feedflow, "out1", heatsource_pump, "in1", label="11") +c12 = Connection(heatsource_pump, "out1", heatsource_evaporator, "in1", label="12") +c13 = Connection(heatsource_evaporator, "out1", heatsource_backflow, "in1", label="13") + +nw.add_conns(c11, c12, c13) + +# heat sink +c21 = Connection(cons_cycle_closer, "out1", cons_pump, "in1", label="21") +c22 = Connection(cons_pump, "out1", condenser, "in2", label="22") +c23 = Connection(condenser, "out2", cons_heatsink, "in1", label="23") +c24 = Connection(cons_heatsink, "out1", cons_cycle_closer, "in1", label="24") + +nw.add_conns(c21, c22, c23, c24) +# %%[sec_3] +# parametrization connections +# set feedflow and backflow temperature of heat source and consumer +T_hs_bf = 10 +T_hs_ff = 15 +T_cons_bf = 50 +T_cons_ff = 90 + +# consumer cycle +c23.set_attr(T=T_cons_ff, p=10, fluid={"water": 1, wf: 0}) +c24.set_attr(T=T_cons_bf) + +# heat source cycle +c11.set_attr(T=T_hs_ff, p=1, fluid={"water": 1, wf: 0}) +c13.set_attr(T=T_hs_bf, p=1) + +# evaporation to fully saturated gas +c1.set_attr(x=1, fluid={"water": 0, wf: 1}) +# degree of overheating after internal heat exchanger (evaporation side) +c2.set_attr(Td_bp=10) + +# parametrization components +# isentropic efficiency +cons_pump.set_attr(eta_s=0.8) +heatsource_pump.set_attr(eta_s=0.8) +compressor.set_attr(eta_s=0.85) + +# pressure ratios +condenser.set_attr(pr1=0.98, pr2=0.98) +heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98) +cons_heatsink.set_attr(pr=0.99) +int_heatex.set_attr(pr1=0.98, pr2=0.98) + +# temperature differences +heatsource_evaporator.set_attr(ttd_l=5) +condenser.set_attr(ttd_u=5) + +# consumer heat demand +cons_heatsink.set_attr(Q=-1e6) + +try: + nw.solve("design") +except ValueError as e: + print(e) +# %%[sec_4] +import CoolProp.CoolProp as CP + +# evaporation point +p_eva = CP.PropsSI("P", "Q", 1, "T", T_hs_bf - 5 + 273.15, wf) * 1e-5 +c1.set_attr(p=p_eva) +heatsource_evaporator.set_attr(ttd_l=None) + +# condensation point +p_cond = CP.PropsSI("P", "Q", 0, "T", T_cons_ff + 5 + 273.15, wf) * 1e-5 +c4.set_attr(p=p_cond) +condenser.set_attr(ttd_u=None) + +# internal heat exchanger to compressor enthalpy +h_evap = CP.PropsSI("H", "Q", 1, "T", T_hs_bf - 5 + 273.15, wf) * 1e-3 +c2.set_attr(Td_bp=None, h=h_evap * 1.01) + +# solve the network again +nw.solve("design") +# %%[sec_5] +# evaporation point +c1.set_attr(p=None) +heatsource_evaporator.set_attr(ttd_l=5) + +# condensation point +c4.set_attr(p=None) +condenser.set_attr(ttd_u=5) + +# internal heat exchanger superheating +c2.set_attr(Td_bp=5, h=None) + +# solve the network again +nw.solve("design") + +# calculate the COP +cop = abs( + cons_heatsink.Q.val + / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val) +) +# %%[sec_6] +def generate_network_with_starting_values(wf): + # network + nw = Network( + fluids=["water", wf], + T_unit="C", p_unit="bar", h_unit="kJ / kg", m_unit="kg / s", + iterinfo=False + ) + + # components + cycle_closer = CycleCloser("Refrigerant Cycle Closer") + + # heat source + heatsource_feedflow = Source("Heat Source Feed Flow") + heatsource_pump = Pump("Heat Source Recirculation Pump") + heatsource_evaporator = HeatExchanger("Heat Source Evaporator") + heatsource_backflow = Sink("Heat Source Back Flow") + + # compression + compressor = Compressor("Compressor") + + # heat sink + cons_pump = Pump("Heat Sink Recirculation Pump") + condenser = Condenser("Heat Sink Condenser") + cons_heatsink = HeatExchangerSimple("Heat Consumer") + cons_cycle_closer = CycleCloser("Consumer Feed Flow") + + # internal heat exchange + int_heatex = HeatExchanger("Internal Heat Exchanger") + + # expansion + valve = Valve("Expansion Valve") + + # connections + # main cycle + c0 = Connection(cycle_closer, "out1", heatsource_evaporator, "in2", label="0") + c1 = Connection(heatsource_evaporator, "out2", int_heatex, "in2", label="1") + c2 = Connection(int_heatex, "out2", compressor, "in1", label="2") + c3 = Connection(compressor, "out1", condenser, "in1", label="3") + c4 = Connection(condenser, "out1", int_heatex, "in1", label="4") + c5 = Connection(int_heatex, "out1", valve, "in1", label="5") + c6 = Connection(valve, "out1", cycle_closer, "in1", label="6") + + nw.add_conns( + c0, c1, c2, c3, c4, + c5, c6 + ) + + # heat source + c11 = Connection(heatsource_feedflow, "out1", heatsource_pump, "in1", label="11") + c12 = Connection(heatsource_pump, "out1", heatsource_evaporator, "in1", label="12") + c13 = Connection(heatsource_evaporator, "out1", heatsource_backflow, "in1", label="13") + + nw.add_conns(c11, c12, c13) + + # heat sink + c21 = Connection(cons_cycle_closer, "out1", cons_pump, "in1", label="20") + c22 = Connection(cons_pump, "out1", condenser, "in2", label="21") + c23 = Connection(condenser, "out2", cons_heatsink, "in1", label="22") + c24 = Connection(cons_heatsink, "out1", cons_cycle_closer, "in1", label="23") + + nw.add_conns(c21, c22, c23, c24) + + # set feedflow and backflow temperature of heat source and consumer + T_hs_bf = 10 + T_hs_ff = 15 + T_cons_bf = 50 + T_cons_ff = 90 + + # consumer cycle + c23.set_attr(T=T_cons_ff, p=10, fluid={"water": 1, wf: 0}) + c24.set_attr(T=T_cons_bf) + + # heat source cycle + c11.set_attr(T=T_hs_ff, p=1, fluid={"water": 1, wf: 0}) + c13.set_attr(T=T_hs_bf, p=1) + + # evaporation to fully saturated gas + c1.set_attr(x=1, fluid={"water": 0, wf: 1}) + + # parametrization components + # isentropic efficiency + cons_pump.set_attr(eta_s=0.8) + heatsource_pump.set_attr(eta_s=0.8) + compressor.set_attr(eta_s=0.85) + + # pressure ratios + condenser.set_attr(pr1=0.98, pr2=0.98) + heatsource_evaporator.set_attr(pr1=0.98, pr2=0.98) + cons_heatsink.set_attr(pr=0.99) + int_heatex.set_attr(pr1=0.98, pr2=0.98) + + # evaporation point + p_eva = CP.PropsSI("P", "Q", 1, "T", T_hs_bf - 5 + 273.15, wf) * 1e-5 + c1.set_attr(p=p_eva) + + # condensation point + p_cond = CP.PropsSI("P", "Q", 0, "T", T_cons_ff + 5 + 273.15, wf) * 1e-5 + c4.set_attr(p=p_cond) + + # internal heat exchanger to compressor enthalpy + h_evap = CP.PropsSI("H", "Q", 1, "T", T_hs_bf - 5 + 273.15, wf) * 1e-3 + c2.set_attr(h=h_evap * 1.01) + + # consumer heat demand + cons_heatsink.set_attr(Q=-1e6) + + power_bus = Bus("Total power input") + heat_bus = Bus("Total heat production") + power_bus.add_comps( + {"comp": compressor, "base": "bus"}, + {"comp": cons_pump, "base": "bus"}, + {"comp": heatsource_pump, "base": "bus"}, + ) + heat_bus.add_comps({"comp": cons_heatsink}) + + nw.add_busses(power_bus, heat_bus) + + nw.solve("design") + + # evaporation point + c1.set_attr(p=None) + heatsource_evaporator.set_attr(ttd_l=5) + + # condensation point + c4.set_attr(p=None) + condenser.set_attr(ttd_u=5) + + # internal heat exchanger superheating + c2.set_attr(Td_bp=5, h=None) + + # solve the network again + nw.solve("design") + + return nw +# %%[sec_7] +import matplotlib.pyplot as plt +import pandas as pd + + +# make text reasonably sized +plt.rc("font", **{"size": 18}) + +cop = pd.DataFrame(columns=["COP"]) + +for wf in ["NH3", "R22", "R134a", "R152a", "R290", "R718"]: + nw = generate_network_with_starting_values(wf) + + power = nw.busses["Total power input"].P.val + heat = abs(nw.busses["Total heat production"].P.val) + cop.loc[wf] = heat / power + +fig, ax = plt.subplots(1, figsize=(16, 8)) + +cop.plot.bar(ax=ax, legend=False) + +ax.set_axisbelow(True) +ax.yaxis.grid(linestyle="dashed") +ax.set_xlabel("Name of working fluid") +ax.set_ylabel("Coefficicent of performance") +ax.set_title("Coefficicent of performance for different working fluids") +plt.tight_layout() + +fig.savefig("COP_by_wf.svg") +# %%[sec_8] From 02db4f1a8a9473d680890ed78dcd8f19348523cb Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 3 Sep 2022 14:08:33 +0200 Subject: [PATCH 076/120] Remove card idea for API docs --- docs/api.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 67abc834b..6a2d34f7f 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -12,8 +12,5 @@ sources are cited individually. .. toctree:: :maxdepth: 1 :glob: - :hidden: api/* - -TODO: NICE CARDS HERE AS WELL From 377878246f3b6353dafa623c9d3d1277cf93619e Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 3 Sep 2022 14:26:52 +0200 Subject: [PATCH 077/120] Some more fine tuning --- .../heat_pump_starting_values/COP_by_wf.svg | 210 +++++------------- tutorial/advanced/starting_values.py | 4 +- 2 files changed, 60 insertions(+), 154 deletions(-) diff --git a/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg b/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg index bf9935c84..a254ae375 100644 --- a/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg +++ b/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg @@ -6,7 +6,7 @@ - 2022-09-03T14:01:02.045537 + 2022-09-03T14:25:58.157590 image/svg+xml @@ -32,8 +32,8 @@ z @@ -43,10 +43,10 @@ z +" id="m266a38ce72" style="stroke:#000000;stroke-width:0.8;"/> - + @@ -123,7 +123,7 @@ z - + @@ -192,7 +192,7 @@ z - + @@ -277,7 +277,7 @@ z - + @@ -321,7 +321,7 @@ z - + @@ -390,7 +390,7 @@ z - + @@ -752,7 +752,7 @@ z - @@ -760,10 +760,10 @@ L 1132.56 470.41 +" id="md4480219d4" style="stroke:#000000;stroke-width:0.8;"/> - + @@ -786,18 +786,18 @@ z - - + - + @@ -806,18 +806,18 @@ L 1132.56 393.313536 - - + - + @@ -826,18 +826,18 @@ L 1132.56 316.217072 - - + - + @@ -846,18 +846,18 @@ L 1132.56 239.120608 - - + - + @@ -866,18 +866,18 @@ L 1132.56 162.024144 - - + - + @@ -886,7 +886,7 @@ L 1132.56 84.92768 - + - - - - - - @@ -1072,109 +1072,15 @@ L 1132.56 470.41 " style="fill:none;stroke:#000000;stroke-linecap:square;stroke-linejoin:miter;stroke-width:0.8;"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/tutorial/advanced/starting_values.py b/tutorial/advanced/starting_values.py index 00f5036a7..da8c53de9 100644 --- a/tutorial/advanced/starting_values.py +++ b/tutorial/advanced/starting_values.py @@ -6,7 +6,7 @@ HeatExchangerSimple, Pump, Sink, Source, Valve ) -from tespy.connections import Connection, Ref, Bus +from tespy.connections import Connection, Bus # %%[sec_2] wf = "NH3" @@ -152,6 +152,7 @@ cons_heatsink.Q.val / (cons_pump.P.val + heatsource_pump.P.val + compressor.P.val) ) +print(cop) # %%[sec_6] def generate_network_with_starting_values(wf): # network @@ -312,7 +313,6 @@ def generate_network_with_starting_values(wf): ax.yaxis.grid(linestyle="dashed") ax.set_xlabel("Name of working fluid") ax.set_ylabel("Coefficicent of performance") -ax.set_title("Coefficicent of performance for different working fluids") plt.tight_layout() fig.savefig("COP_by_wf.svg") From 4912d521fb4a43a9dec1397cfd307e8ea07e8143 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 3 Sep 2022 14:28:57 +0200 Subject: [PATCH 078/120] Add download link for code example --- docs/tutorials/starting_values.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/tutorials/starting_values.rst b/docs/tutorials/starting_values.rst index 8cd8c3eaa..d61d23dc7 100644 --- a/docs/tutorials/starting_values.rst +++ b/docs/tutorials/starting_values.rst @@ -27,6 +27,9 @@ different working fluids. modifications have to be made on this setup. We plan to include respective examples here in the future. +You can download the full code of this example here: +:download:`starting_values.py ` + Topology of the heat pump ^^^^^^^^^^^^^^^^^^^^^^^^^ Following the first tutorial a slightly different topology for a heat pump @@ -68,7 +71,7 @@ working fluid will be set with the variable `wf`, `"NH3"` is used in the first setup. This way, we will be able to change the working fluid in a flexible way. -.. dropdown:: Display source code of the full code +.. dropdown:: Click to expand to code section .. literalinclude:: /../tutorial/advanced/starting_values.py :language: python @@ -91,7 +94,7 @@ following way: - Pressure losses in all heat exchangers (`pr1`, `pr2`, `pr`) - Consumer heat demand (`Q`) -.. dropdown:: Display source code of the full code +.. dropdown:: Click to expand to code section .. literalinclude:: /../tutorial/advanced/starting_values.py :language: python @@ -178,7 +181,7 @@ Expand fix to any working fluids Finally, using this strategy, it is possible to build a generic function, building a network, that works with a variety of working fluids. -.. dropdown:: Display source code of the full code +.. dropdown:: Click to expand to code section .. literalinclude:: /../tutorial/advanced/starting_values.py :language: python From 670888f8f035cf904c1aa0d5189c9b60165d0c69 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 3 Sep 2022 14:32:14 +0200 Subject: [PATCH 079/120] Harmonize folder structure --- docs/tutorials/heat_pump_exergy.rst | 15 ++++++++++----- tutorial/{ => heat_pump_exergy}/NH3.py | 0 .../{ => heat_pump_exergy}/NH3_calculations.py | 0 tutorial/{ => heat_pump_exergy}/R410A.py | 0 .../{ => heat_pump_exergy}/R410A_calculations.py | 0 tutorial/{ => heat_pump_exergy}/plots.py | 0 6 files changed, 10 insertions(+), 5 deletions(-) rename tutorial/{ => heat_pump_exergy}/NH3.py (100%) rename tutorial/{ => heat_pump_exergy}/NH3_calculations.py (100%) rename tutorial/{ => heat_pump_exergy}/R410A.py (100%) rename tutorial/{ => heat_pump_exergy}/R410A_calculations.py (100%) rename tutorial/{ => heat_pump_exergy}/plots.py (100%) diff --git a/docs/tutorials/heat_pump_exergy.rst b/docs/tutorials/heat_pump_exergy.rst index 204d99e8a..6bf01e3f0 100644 --- a/docs/tutorials/heat_pump_exergy.rst +++ b/docs/tutorials/heat_pump_exergy.rst @@ -31,11 +31,16 @@ the heat pump model differs slightly in structure from the model in the previous tutorial. All related Python scripts of the fully working GCHP-model are listed in the following: -- GCHP with NH3 (the model only): :download:`NH3 ` -- GCHP with R410A (the model only): :download:`R410A ` -- GCHP with NH3 (model and post-processing): :download:`NH3_calculations ` -- GCHP with R410A (model and post-processing): :download:`R410A_calculations ` -- Plots of the results of the parameter variations: :download:`plots ` +- GCHP with NH3 (the model only): + :download:`NH3.py ` +- GCHP with R410A (the model only): + :download:`R410A.py ` +- GCHP with NH3 (model and post-processing): + :download:`NH3_calculations.py ` +- GCHP with R410A (model and post-processing): + :download:`R410A_calculations.py ` +- Plots of the results of the parameter variations: + :download:`plots.py ` The figure below shows the topology of the GCHP. In this model, a ground-coupled heat pump is modeled, which is for instance connected to a diff --git a/tutorial/NH3.py b/tutorial/heat_pump_exergy/NH3.py similarity index 100% rename from tutorial/NH3.py rename to tutorial/heat_pump_exergy/NH3.py diff --git a/tutorial/NH3_calculations.py b/tutorial/heat_pump_exergy/NH3_calculations.py similarity index 100% rename from tutorial/NH3_calculations.py rename to tutorial/heat_pump_exergy/NH3_calculations.py diff --git a/tutorial/R410A.py b/tutorial/heat_pump_exergy/R410A.py similarity index 100% rename from tutorial/R410A.py rename to tutorial/heat_pump_exergy/R410A.py diff --git a/tutorial/R410A_calculations.py b/tutorial/heat_pump_exergy/R410A_calculations.py similarity index 100% rename from tutorial/R410A_calculations.py rename to tutorial/heat_pump_exergy/R410A_calculations.py diff --git a/tutorial/plots.py b/tutorial/heat_pump_exergy/plots.py similarity index 100% rename from tutorial/plots.py rename to tutorial/heat_pump_exergy/plots.py From 2aa74af1840bc2da691b584dc0c9d74854e0b627 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 3 Sep 2022 15:27:45 +0200 Subject: [PATCH 080/120] Tidy up and move some images --- .../{ => modules}/Ts_diagram_states.svg | 0 .../{ => modules}/logph_diagram_states.svg | 0 docs/basics.rst | 2 + docs/examples.rst | 69 ++++++++++++++++++- docs/introduction.rst | 10 ++- docs/modules/networks.rst | 21 ++---- docs/tutorials/heat_pump_exergy.rst | 36 +++++----- docs/whats_new/v0-1-1.rst | 2 - docs/whats_new/v0-1-2.rst | 2 - docs/whats_new/v0-2-0.rst | 5 -- docs/whats_new/v0-3-4.rst | 2 +- docs/whats_new/v0-4-0.rst | 4 +- docs/whats_new/v0-4-1.rst | 2 +- 13 files changed, 103 insertions(+), 52 deletions(-) rename docs/_static/images/{ => modules}/Ts_diagram_states.svg (100%) rename docs/_static/images/{ => modules}/logph_diagram_states.svg (100%) diff --git a/docs/_static/images/Ts_diagram_states.svg b/docs/_static/images/modules/Ts_diagram_states.svg similarity index 100% rename from docs/_static/images/Ts_diagram_states.svg rename to docs/_static/images/modules/Ts_diagram_states.svg diff --git a/docs/_static/images/logph_diagram_states.svg b/docs/_static/images/modules/logph_diagram_states.svg similarity index 100% rename from docs/_static/images/logph_diagram_states.svg rename to docs/_static/images/modules/logph_diagram_states.svg diff --git a/docs/basics.rst b/docs/basics.rst index 8bd6e0a21..ccec3e310 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -1,3 +1,5 @@ +.. _tespy_basics_label: + Modeling Basic Systems ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/examples.rst b/docs/examples.rst index 04841fd82..153e82a13 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -4,7 +4,74 @@ Example Applications ~~~~~~~~~~~~~~~~~~~~ -.. card:: Exergy Analysis of a supercritical CO2 Powerplant +.. card:: Exergy Analysis of a Solarthermal Powerplant + :link: https://github.com/fwitte/SEGS_exergy + + Header + ^^^ + + .. grid:: 1 2 + :outline: + + .. grid-item:: + + Some description + + .. grid-item:: + + .. image:: /_static/images/tutorials/heat_pump_steps/flowsheet.svg + :align: center + :alt: BLABLA + + +++ + Footer + +.. card:: Parametric Optimization of a Geothermal Organic Rankine Cycle + :link: https://github.com/fwitte/ORCSimulator + + Header + ^^^ + + .. grid:: 1 2 + :outline: + + .. grid-item:: + + Some description + + .. grid-item:: + + .. image:: /_static/images/tutorials/heat_pump_steps/flowsheet.svg + :align: center + :alt: BLABLA + + +++ + Footer + +.. card:: District Heating Supply using an Organic Rankine Cycle + :link: https://github.com/fwitte/chp_orc + + Header + ^^^ + + .. grid:: 1 2 + :outline: + + .. grid-item:: + + Some description + + .. grid-item:: + + .. image:: /_static/images/tutorials/heat_pump_steps/flowsheet.svg + :align: center + :alt: BLABLA + + +++ + Footer + + +.. card:: District Heating Supply using an Organic Rankine Cycle :link: https://github.com/fwitte/sCO2_exergy Header diff --git a/docs/introduction.rst b/docs/introduction.rst index 0d7cdb1e8..dbe0d6379 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -63,12 +63,10 @@ Getting into TESPy ================== For a good start on how TESPy works and how you can use it, we provide some -examples at the :ref:`examples section `. On top of that, -there is a step-by-step :ref:`tutorial ` on how to -model a heat pump in TESPy. - -The :ref:`TESPy modules section ` provides you -with all important information on the different modules of TESPy. +:ref:`basic ` and :ref:`advanced ` +tutorials in the User Guide section. The +:ref:`modules ` section provides you with in depth +information on the different modules of TESPy. Citation ======== diff --git a/docs/modules/networks.rst b/docs/modules/networks.rst index dea1d535c..fd282fa72 100644 --- a/docs/modules/networks.rst +++ b/docs/modules/networks.rst @@ -438,17 +438,6 @@ check is skipped. In a lot of different tests the algorithm has found a near enough solution after the third iteration, further checks are usually not required. -.. note:: - - It is possible to improve the convergence stability manually when using - pure fluids. If you know the fluid's state is liquid or gaseous prior to - the calculation, you may provide the according value for the keyword e.g. - :code:`myconn.set_attr(state='l')`. The convergence check manipulates the - enthalpy values so that the fluid is always in the desired state at that - point. For an example see the release information of - :ref:`version 0.1.1 `. **Please note, that** - **you need to adjust the other parts of the script to the latest API.** - Calculation speed improvement +++++++++++++++++++++++++++++ For improvement of calculation speed, the calculation of specific derivatives @@ -744,15 +733,17 @@ respective API documentation. Creating fluid property diagrams ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. figure:: /api/_images/logph_diagram_states.svg +.. figure:: /_static/images/modules/logph_diagram_states.svg :align: center + :alt: logph diagram of NH3 with a simple heat pump cycle - Figure: logph diagram of NH3 with a simple heat pump cycle. + Figure: logph diagram of NH3 with a simple heat pump cycle -.. figure:: /api/_images/Ts_diagram_states.svg +.. figure:: /_static/images/modules/Ts_diagram_states.svg :align: center + :alt: Ts diagram of NH3 with a simple heat pump cycle - Figure: Ts diagram of NH3 with a simple heat pump cycle. + Figure: Ts diagram of NH3 with a simple heat pump cycle CoolProp has an inbuilt feature for creating fluid property diagrams. Unfortunately, the handling is not very easy at the moment. We recommend using diff --git a/docs/tutorials/heat_pump_exergy.rst b/docs/tutorials/heat_pump_exergy.rst index 6bf01e3f0..e7731356f 100644 --- a/docs/tutorials/heat_pump_exergy.rst +++ b/docs/tutorials/heat_pump_exergy.rst @@ -34,7 +34,7 @@ are listed in the following: - GCHP with NH3 (the model only): :download:`NH3.py ` - GCHP with R410A (the model only): - :download:`R410A.py ` + :download:`R410A.py ` - GCHP with NH3 (model and post-processing): :download:`NH3_calculations.py ` - GCHP with R410A (model and post-processing): @@ -144,14 +144,14 @@ flow temperature in the design calculation is set to :code:`Tgeo + 1.5°C` and the return flow temperature is set to :code:`Tgeo - 1.5°C`. The complete Python code of the TESPy models is available in the scripts -:download:`NH3.py ` with NH3 as refrigerant and -:download:`R410A.py ` with R410A as refrigerant. All -other specified values of the component and connection parameters can be found -in these Python scripts. +:download:`NH3.py ` with NH3 as +refrigerant and :download:`R410A.py ` +with R410A as refrigerant. All other specified values of the component and +connection parameters can be found in these Python scripts. In the scripts -:download:`NH3_calculations.py ` and -:download:`R410A_calculations.py `, +:download:`NH3_calculations.py ` and +:download:`R410A_calculations.py `, the Python code of the TESPy models of the GCHP is extended to handle the different tasks mentioned in the introduction. In these two scripts you can find the corresponding Python code for all calculations that will be presented @@ -380,7 +380,7 @@ considered: In order to be able to compare the results of the two refrigerants NH3 and R410A, plots of the results of the mentioned issues are created in a separate -plot script :download:`plots.py `. The plots in this +plot script :download:`plots.py `. The plots in this tutorial are created with `Matplotlib `_. For installation instructions or further documentation please see the Matplotlib documentation. @@ -444,11 +444,12 @@ different refrigerants NH3 and R410A in a separate script. script for plot creation, all data frames must be saved as a file with their own individual name. -In the separate plot script (:download:`plots.py `) the :code:`.csv` files can -now be re-imported to create plots with Matplotlib. The Python code for -creating the bar chart is included in the previously referenced plot script -and can be found there. For more information on creating plots with -Matplotlib, please check the +In the separate plot script +(:download:`plots.py `) the +:code:`.csv` files can now be re-imported to create plots with Matplotlib. The +Python code for creating the bar chart is included in the previously +referenced plot script and can be found there. For more information on +creating plots with Matplotlib, please check the `Matplotlib documentation `_. The resulting bar chart is shown below. @@ -544,8 +545,9 @@ temperatures is carried out as an offdesign calculation. Again, no new The results of the calculation can be plotted as shown in the following figure. The related Python code to create this plot can be found in the plot -script (:download:`plots.py `). For further documentation -please see the `Matplotlib documentation `_. +script (:download:`plots.py `). For +further documentation please see the `Matplotlib `__ +documentation. .. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo.svg :align: center @@ -623,7 +625,7 @@ of :code:`Ths` as columns. The results of this calculation are shown in the following figure. The corresponding Python code can likewise be found in the plot script -(:download:`plots.py `). +(:download:`plots.py `). .. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths.svg :align: center @@ -663,7 +665,7 @@ instead. The results are shown in the figure above. As before, the Python code for creating the plot can be found in the plot script -(:download:`plots.py `). +(:download:`plots.py `). The partial load behavior of the GCHP, which results from the characteristic lines of the efficiencies of the individual components, can be recognized in the curves shown. diff --git a/docs/whats_new/v0-1-1.rst b/docs/whats_new/v0-1-1.rst index cd8ee80bf..7658e884e 100644 --- a/docs/whats_new/v0-1-1.rst +++ b/docs/whats_new/v0-1-1.rst @@ -29,8 +29,6 @@ Other changes - Changed access to imported network's connections (:code:`mynetwork.imp_conns['{source}:{source id}_{target}:{target id}']`, replace :code:`{...}` by the respectve component or id). (`a5a867 `_). - Improved convergence stability for temperatures specified near to the two phase area using the keyowrd :code:`state='l'` (for liquid) or :code:`state='g'` (for gaseous). The convergence check manipulates the enthalpy values at this connection in order to meet the phase specification (`PR #64 `_). - -.. _whats_new_011_example_label: Example ####### diff --git a/docs/whats_new/v0-1-2.rst b/docs/whats_new/v0-1-2.rst index d0902af3f..efa0a2501 100644 --- a/docs/whats_new/v0-1-2.rst +++ b/docs/whats_new/v0-1-2.rst @@ -33,8 +33,6 @@ Other changes - Add method to calculate and export vapour mass fraction values of pure fluids in the post processing (`PR #74 `_). - Only allow label and P as parameters for busses to avoid misleading parameter specification (`PR #78 `_). -.. _whats_new_012_example_label: - Water Electrolyzer Example ########################## diff --git a/docs/whats_new/v0-2-0.rst b/docs/whats_new/v0-2-0.rst index f42cb9d46..09da95e25 100644 --- a/docs/whats_new/v0-2-0.rst +++ b/docs/whats_new/v0-2-0.rst @@ -6,9 +6,6 @@ new features have been implemented improving the usage of the software. Due to changes in the API, **version 0.2.0 will not be compatible with older** **versions of TESPy!** -The :ref:`example section below ` quickly shows, -how to modify your scripts in order to work with the new version. - New Features ############ - Implemented a new component "cycle_closer". This component may serve as substitute for a @@ -86,8 +83,6 @@ Contributors - @stianchris - @FranziPl -.. _tespy_v020_examples_label: - Examples ######## diff --git a/docs/whats_new/v0-3-4.rst b/docs/whats_new/v0-3-4.rst index 07f70687a..f15597fd9 100644 --- a/docs/whats_new/v0-3-4.rst +++ b/docs/whats_new/v0-3-4.rst @@ -4,7 +4,7 @@ v0.3.4 - Darwin's Delight (October, 13, 2020) Documentation ############# - Replace enthalpy starting value with :code:`state` keyword in the - :ref:`heat pump tutorial` and the examples from the + :ref:`heat pump tutorial ` and the examples from the oemof_examples repository (`PR #214 `_, `743bfeb `_). diff --git a/docs/whats_new/v0-4-0.rst b/docs/whats_new/v0-4-0.rst index cdec58a5c..d470650b4 100644 --- a/docs/whats_new/v0-4-0.rst +++ b/docs/whats_new/v0-4-0.rst @@ -140,12 +140,12 @@ New Features The diagrams could look like this: - .. figure:: /api/_images/logph_diagram_states.svg + .. figure:: /_static/images/modules/logph_diagram_states.svg :align: center Figure: logph diagram of NH3 with a simple heat pump cycle. - .. figure:: /api/_images/Ts_diagram_states.svg + .. figure:: /_static/images/modules/Ts_diagram_states.svg :align: center Figure: Ts diagram of NH3 with a simple heat pump cycle. diff --git a/docs/whats_new/v0-4-1.rst b/docs/whats_new/v0-4-1.rst index df2bdfccf..5517c19ba 100644 --- a/docs/whats_new/v0-4-1.rst +++ b/docs/whats_new/v0-4-1.rst @@ -10,7 +10,7 @@ New Features restrictions as long as the partial derivatives are provided correctly. For extensive examples have a look at the API documentation of class :py:class:`tespy.tools.helpers.UserDefinedEquation` or in the respective - section in the online :ref:`documentation ` + section in the online :ref:`documentation ` (`PR #245 `_). Documentation From 192c5ecb0cf56a8aeadacbe2f16e60206e9a7acc Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 3 Sep 2022 18:34:51 +0200 Subject: [PATCH 081/120] Remove residuals --- tutorial/step_2.py | 142 ------------------------------------ tutorial/step_3.py | 174 --------------------------------------------- 2 files changed, 316 deletions(-) delete mode 100644 tutorial/step_2.py delete mode 100644 tutorial/step_3.py diff --git a/tutorial/step_2.py b/tutorial/step_2.py deleted file mode 100644 index c23a166a1..000000000 --- a/tutorial/step_2.py +++ /dev/null @@ -1,142 +0,0 @@ -# -*- coding: utf-8 -*- - -from tespy.components import Condenser -from tespy.components import CycleCloser -from tespy.components import Drum -from tespy.components import HeatExchanger -from tespy.components import HeatExchangerSimple -from tespy.components import Pump -from tespy.components import Sink -from tespy.components import Source -from tespy.components import Valve -from tespy.connections import Connection -from tespy.connections import Ref -from tespy.networks import Network -from tespy.tools.characteristics import CharLine -from tespy.tools.characteristics import load_default_char as ldc - -# %% network - -nw = Network(fluids=['water', 'NH3'], T_unit='C', p_unit='bar', - h_unit='kJ / kg', m_unit='kg / s') - -# %% components - -# sources & sinks - -c_in = Source('coolant in') -cons_closer = CycleCloser('consumer cycle closer') - -amb_in = Source('source ambient') -amb_out = Sink('sink ambient') - -# consumer system - -cd = Condenser('condenser') -rp = Pump('recirculation pump') -cons = HeatExchangerSimple('consumer') - -# evaporator system - -va = Valve('valve') -dr = Drum('drum') -ev = HeatExchanger('evaporator') -su = HeatExchanger('superheater') -pu = Pump('pump evaporator') - -cp1 = Sink('compressor 1') - -# %% connections - -# consumer system - -c_in_cd = Connection(c_in, 'out1', cd, 'in1') - -close_rp = Connection(cons_closer, 'out1', rp, 'in1') -rp_cd = Connection(rp, 'out1', cd, 'in2') -cd_cons = Connection(cd, 'out2', cons, 'in1') -cons_close = Connection(cons, 'out1', cons_closer, 'in1') - -nw.add_conns(c_in_cd, close_rp, rp_cd, cd_cons, cons_close) - -# connection condenser - evaporator system - -cd_va = Connection(cd, 'out1', va, 'in1') - -nw.add_conns(cd_va) - -# evaporator system - -va_dr = Connection(va, 'out1', dr, 'in1') -dr_pu = Connection(dr, 'out1', pu, 'in1') -pu_ev = Connection(pu, 'out1', ev, 'in2') -ev_dr = Connection(ev, 'out2', dr, 'in2') -dr_su = Connection(dr, 'out2', su, 'in2') - -nw.add_conns(va_dr, dr_pu, pu_ev, ev_dr, dr_su) - -amb_in_su = Connection(amb_in, 'out1', su, 'in1') -su_ev = Connection(su, 'out1', ev, 'in1') -ev_amb_out = Connection(ev, 'out1', amb_out, 'in1') - -nw.add_conns(amb_in_su, su_ev, ev_amb_out) - -# connection evaporator system - compressor system - -su_cp1 = Connection(su, 'out2', cp1, 'in1') - -nw.add_conns(su_cp1) - -# %% component parametrization - -# condenser system - -cd.set_attr(pr1=0.99, pr2=0.99, ttd_u=5, design=['pr2', 'ttd_u'], - offdesign=['zeta2', 'kA_char']) -rp.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) -cons.set_attr(pr=0.99, design=['pr'], offdesign=['zeta']) - -# evaporator system - -kA_char1 = ldc('heat exchanger', 'kA_char1', 'DEFAULT', CharLine) -kA_char2 = ldc('heat exchanger', 'kA_char2', 'EVAPORATING FLUID', CharLine) - -ev.set_attr(pr1=0.99, pr2=0.99, ttd_l=5, - kA_char1=kA_char1, kA_char2=kA_char2, - design=['pr1', 'ttd_l'], offdesign=['zeta1', 'kA_char']) -su.set_attr(pr1=0.99, pr2=0.99, ttd_u=2, design=['pr1', 'pr2', 'ttd_u'], - offdesign=['zeta1', 'zeta2', 'kA_char']) -pu.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) - -# %% connection parametrization - -# condenser system - -c_in_cd.set_attr(T=170, fluid={'water': 0, 'NH3': 1}) -close_rp.set_attr(T=60, p=10, fluid={'water': 1, 'NH3': 0}) -cd_cons.set_attr(T=90) - -# evaporator system cold side - -pu_ev.set_attr(m=Ref(va_dr, 0.75, 0)) -su_cp1.set_attr(state='g') - -# evaporator system hot side - -amb_in_su.set_attr(T=12, p=1, fluid={'water': 1, 'NH3': 0}) -ev_amb_out.set_attr(T=9) - -# %% key paramter - -cons.set_attr(Q=-230e3) - -# %% Calculation - -nw.solve('design') -nw.print_results() -nw.save('condenser_eva') - -cons.set_attr(Q=-200e3) - -nw.solve('offdesign', design_path='condenser_eva') -nw.print_results() diff --git a/tutorial/step_3.py b/tutorial/step_3.py deleted file mode 100644 index 6aba803b4..000000000 --- a/tutorial/step_3.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- coding: utf-8 -*- - -from tespy.components import Compressor -from tespy.components import Condenser -from tespy.components import CycleCloser -from tespy.components import Drum -from tespy.components import HeatExchanger -from tespy.components import HeatExchangerSimple -from tespy.components import Pump -from tespy.components import Sink -from tespy.components import Source -from tespy.components import Valve -from tespy.connections import Connection -from tespy.connections import Ref -from tespy.networks import Network -from tespy.tools.characteristics import CharLine -from tespy.tools.characteristics import load_default_char as ldc - -# %% network - -nw = Network(fluids=['water', 'NH3'], T_unit='C', p_unit='bar', - h_unit='kJ / kg', m_unit='kg / s') - -# %% components - -# sources & sinks - -cool_closer = CycleCloser('coolant cycle closer') -cons_closer = CycleCloser('consumer cycle closer') - -amb_in = Source('source ambient') -amb_out = Sink('sink ambient') - -ic_in = Source('source intercool') -ic_out = Sink('sink intercool') - -# consumer system - -cd = Condenser('condenser') -rp = Pump('recirculation pump') -cons = HeatExchangerSimple('consumer') - -# evaporator system - -va = Valve('valve') -dr = Drum('drum') -ev = HeatExchanger('evaporator') -su = HeatExchanger('superheater') -pu = Pump('pump evaporator') - -# compressor-system - -cp1 = Compressor('compressor 1') -cp2 = Compressor('compressor 2') -he = HeatExchanger('intercooler') - -# %% connections - -# consumer system - -c_in_cd = Connection(cool_closer, 'out1', cd, 'in1') -close_rp = Connection(cons_closer, 'out1', rp, 'in1') -rp_cd = Connection(rp, 'out1', cd, 'in2') -cd_cons = Connection(cd, 'out2', cons, 'in1') -cons_close = Connection(cons, 'out1', cons_closer, 'in1') - -nw.add_conns(c_in_cd, close_rp, rp_cd, cd_cons, cons_close) - -# connection condenser - evaporator system - -cd_va = Connection(cd, 'out1', va, 'in1') - -nw.add_conns(cd_va) - -# evaporator system - -va_dr = Connection(va, 'out1', dr, 'in1') -dr_pu = Connection(dr, 'out1', pu, 'in1') -pu_ev = Connection(pu, 'out1', ev, 'in2') -ev_dr = Connection(ev, 'out2', dr, 'in2') -dr_su = Connection(dr, 'out2', su, 'in2') - -nw.add_conns(va_dr, dr_pu, pu_ev, ev_dr, dr_su) - -amb_in_su = Connection(amb_in, 'out1', su, 'in1') -su_ev = Connection(su, 'out1', ev, 'in1') -ev_amb_out = Connection(ev, 'out1', amb_out, 'in1') - -nw.add_conns(amb_in_su, su_ev, ev_amb_out) - -# connection evaporator system - compressor system - -su_cp1 = Connection(su, 'out2', cp1, 'in1') - -nw.add_conns(su_cp1) - -# compressor-system - -cp1_he = Connection(cp1, 'out1', he, 'in1') -he_cp2 = Connection(he, 'out1', cp2, 'in1') -cp2_close = Connection(cp2, 'out1', cool_closer, 'in1') - -ic_in_he = Connection(ic_in, 'out1', he, 'in2') -he_ic_out = Connection(he, 'out2', ic_out, 'in1') - -nw.add_conns(cp1_he, he_cp2, ic_in_he, he_ic_out, cp2_close) - -# %% component parametrization - -# condenser system - -cd.set_attr(pr1=0.99, pr2=0.99, ttd_u=5, design=['pr2', 'ttd_u'], - offdesign=['zeta2', 'kA_char']) -rp.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) -cons.set_attr(pr=0.99, design=['pr'], offdesign=['zeta']) - -# evaporator system - -kA_char1 = ldc('heat exchanger', 'kA_char1', 'DEFAULT', CharLine) -kA_char2 = ldc('heat exchanger', 'kA_char2', 'EVAPORATING FLUID', CharLine) - -ev.set_attr(pr1=0.99, pr2=0.99, ttd_l=5, - kA_char1=kA_char1, kA_char2=kA_char2, - design=['pr1', 'ttd_l'], offdesign=['zeta1', 'kA_char']) -su.set_attr(pr1=0.99, pr2=0.99, ttd_u=2, design=['pr1', 'pr2', 'ttd_u'], - offdesign=['zeta1', 'zeta2', 'kA_char']) -pu.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) - -# compressor system - -cp1.set_attr(eta_s=0.8, design=['eta_s'], offdesign=['eta_s_char']) -cp2.set_attr(eta_s=0.8, pr=5, design=['eta_s'], offdesign=['eta_s_char']) - -he.set_attr(pr1=0.98, pr2=0.98, design=['pr1', 'pr2'], - offdesign=['zeta1', 'zeta2', 'kA_char']) - -# %% connection parametrization - -# condenser system - -c_in_cd.set_attr(fluid={'water': 0, 'NH3': 1}) -close_rp.set_attr(T=60, p=10, fluid={'water': 1, 'NH3': 0}) -cd_cons.set_attr(T=90) - -# evaporator system cold side - -pu_ev.set_attr(m=Ref(va_dr, 0.75, 0)) -su_cp1.set_attr(state='g') - -# evaporator system hot side - -amb_in_su.set_attr(T=12, p=1, fluid={'water': 1, 'NH3': 0}) -ev_amb_out.set_attr(T=9) - -he_cp2.set_attr(T=40, p0=10) -ic_in_he.set_attr(p=5, T=20, fluid={'water': 1, 'NH3': 0}) -he_ic_out.set_attr(T=30, design=['T']) - -# %% key paramter - -cons.set_attr(Q=-230e3) - -# %% Calculation - -nw.solve('design') -# alternatively use: -nw.solve('design', init_path='condenser_eva') -nw.print_results() -nw.save('heat_pump') - -cons.set_attr(Q=-200e3) - -nw.solve('offdesign', design_path='heat_pump') -nw.print_results() From 545d759161af92d5c571d0d33a570a7f59177f25 Mon Sep 17 00:00:00 2001 From: matbock Date: Mon, 5 Sep 2022 10:15:06 +0200 Subject: [PATCH 082/120] typos in example fixed --- src/tespy/components/reactors/fuel_cell.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/tespy/components/reactors/fuel_cell.py b/src/tespy/components/reactors/fuel_cell.py index 3bc26099c..8c13a9989 100644 --- a/src/tespy/components/reactors/fuel_cell.py +++ b/src/tespy/components/reactors/fuel_cell.py @@ -38,8 +38,6 @@ class FuelCell(Component): - in1 (cooling inlet), in2 (oxygen inlet), in3 (hydrogen inlet) - out1 (cooling outlet), out2 (water outlet) - //TODO: add image - Image .. image:: _images/FuelCell.svg @@ -99,8 +97,6 @@ class FuelCell(Component): as the water outlet. Thus, the user must not specify the fluid composition at these connections! - \\TODO: complete example - Example ------- The example shows a simple adaptation of the fuel cell. It works with water as cooling fluid. @@ -121,11 +117,11 @@ class FuelCell(Component): >>> cw_source = Source('cw_source') >>> cw_sink = Sink('cw_sink') >>> water_sink = Sink('water_sink') - >>> cw_in = Connection(cw_source, 'out1', FC, 'in1') - >>> cw_out = Connection(FC, 'out1', cw_sink, 'in1') - >>> oxygen_in = Connection(oxygen_source, 'out1', FC, 'in2') - >>> hydrogen_in = Connection(hydrogen_source, 'out1', FC, 'in3') - >>> water_out = Connection(FC, 'out2', water_sink, 'in1') + >>> cw_in = Connection(cw_source, 'out1', fc, 'in1') + >>> cw_out = Connection(fc, 'out1', cw_sink, 'in1') + >>> oxygen_in = Connection(oxygen_source, 'out1', fc, 'in2') + >>> hydrogen_in = Connection(hydrogen_source, 'out1', fc, 'in3') + >>> water_out = Connection(fc, 'out2', water_sink, 'in1') >>> nw.add_conns(cw_in, cw_out, oxygen_in, hydrogen_in, water_out) The fuel cell shall produce 200kW of electrical power and 200kW of heat with an efficiency of 0.45. The From 95d29429ee7a8c218297589bf5f20f81ecbff601 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 5 Sep 2022 21:09:46 +0200 Subject: [PATCH 083/120] Restructure pygmo example --- docs/tutorials/pygmo_optimization.rst | 105 +++++++++++++++++--------- src/tespy/tools/optimization.py | 55 +------------- 2 files changed, 73 insertions(+), 87 deletions(-) diff --git a/docs/tutorials/pygmo_optimization.rst b/docs/tutorials/pygmo_optimization.rst index cc0e3ad1d..620bb14a8 100644 --- a/docs/tutorials/pygmo_optimization.rst +++ b/docs/tutorials/pygmo_optimization.rst @@ -5,27 +5,35 @@ Thermal Power Plant Efficiency Optimization Task ^^^^ - Designing a power plant meets multiple different tasks, such as finding the optimal fresh steam temperature and pressure to reduce exhaust steam water content, or the optimization of extraction pressures to maximize cycle efficiency and many more. -In case of a rather simple power plant topologies the task of finding optimized -values for e.g. extraction pressures is still manageable without any +In case of a rather simple power plant topologies the task of finding +optimized values for e.g. extraction pressures is still manageable without any optimization tool. As the topology becomes more complex and boundary conditions come into play the usage of additional tools is recommended. The following tutorial is intended to show the usage of PyGMO in combination with TESPy to **maximize the cycle efficiency of a power plant with two** **extractions.** -The source code can be found at the TESPy -`examples repository `__. +You can download the code here: +:download:`pygmo_optimization.py ` + +.. figure:: /_static/images/tutorials/pygmo_optimization/flowsheet.svg + :align: center + :alt: Topology of the power plant + :figclass: only-light + + Figure: Topology of the power plant -.. figure:: /api/_images/power_plant_two_extractions.svg +.. figure:: /_static/images/tutorials/pygmo_optimization/flowsheet_darkmode.svg :align: center + :alt: Topology of the power plant + :figclass: only-dark - Figure: Topology of the power plant. + Figure: Topology of the power plant What is PyGMO? ^^^^^^^^^^^^^^ @@ -51,37 +59,46 @@ approximation for the real optimum. Install PyGMO +++++++++++++ -conda -##### +.. tab-set:: + + .. tab-item:: conda + + With the conda package manager PyGMO is available for Linux, OSX and + Windows thanks to the infrastructure of + `conda-forge `_: -With the conda package manager PyGMO is available for Linux, OSX and Windows -thanks to the infrastructure of `conda-forge `_: + .. code-block:: bash -.. code-block:: bash + conda install -c conda-forge pygmo - conda install -c conda-forge pygmo -pip -### + Windows user can perform an installation from source as an alternative + to conda. For further information on this process we recommend the + `PyGMO installation `__ + accordingly. -On Linux you also have the option to use the -`pip `_ package installer: -.. code-block:: bash + .. tab-item:: pip (Linux only!) - pip install pygmo + On Linux you also have the option to use the + `pip `_ package installer: -Windows user can perform an installation from source as an alternative to conda. -For further information on this process we recommend the `PyGMO installation -`__ -accordingly. + .. code-block:: bash + + pip install pygmo Creating your TESPy-Model ^^^^^^^^^^^^^^^^^^^^^^^^^ +To use the API, you need to define a class holding a TESPy network. The +initialization of the class should build the network and run an initial +simulation. Furthermore, you have to define methods + +- to get component or connection parameters of the plant :code:`get_param`, +- to run a new simulation for every new input from PyGMO :code:`solve_model` + and +- to return the objective value :code:`get_objective`. -It is necessary to use object oriented programming in PyGMO. Therefore we create -a class :code:`PowerPlant` which contains our TESPy-Model and a function to -return the cycle efficiency. +First, we set up the class with the TESPy network. .. dropdown:: Display source code for the PowerPlant class @@ -247,12 +264,13 @@ return the cycle efficiency. else: return self.nw.busses['power'].P.val / self.nw.busses['heat'].P.val -Note, that you have to label all busses and connections you want to access -later on with PyGMO. In :code:`calculate_efficiency(self, x)` the variable -:code:`x` is a list containing your decision variables. This function returns -the cycle efficiency for a specific set of decision variables. The efficiency -is defined by the ratio of total power transferred (including turbines and -pumps) to steam generator heat input. +Next, we add the methods :code:`get_param`, :code:`solve_model` and +:code:`get_objective`. + +.. note:: + + The sense of optimization is always minimization, therefore you need to + define your objective functions in the appropriate way. Additionally, we have to make sure, only the result of physically feasible solutions is returned. In case we have infeasible solutions, we can simply @@ -261,6 +279,25 @@ of a turbine is positive, the power of a pump is negative or the heat exchanged in any of the preheaters is positive. We also check, if the calculation does converge. +After this, we import the :py:class:`tespy.tools.optimize.OptimizationProblem` +class and create an instance of our self defined class, which we pass to an +instance of the OptimizationProblem class. We also have to pass + +- the variables to optimize, +- the constraints to consider and +- the objective function name (you can define multiple). + +Before we can run the optimization, we only need to select an appropriate +algorithm. After that we can start the optimization run. For more information +on algorithms available in the PyGMO framework and their individual +specifications please refer to the respective section in their online +documentation: +`list of algorithms `__. +Specify the number of individuals, the number of generations and call the +:py:meth:`tespy.tools.optimization.OptimizationProblem.run` method of your +:code:`OptimizationProblem` instance passing the algorithm and the number +of individuals and generations. + .. math:: \eta_\mathrm{th}=\frac{|\sum P|}{\dot{Q}_{sg}} @@ -356,8 +393,8 @@ With :code:`pop` we define the size of each population for the optimization, algorithms can be found in `List of algorithms `_. The choice of your algorithm depends on the type of problem. Have you set -equality or inequality constraints? Do you perform a single- or multi-objective -optimization? +equality or inequality constraints? Do you perform a single- or +multi-objective optimization? We choose a population size of 10 individuals and want to carry out 15 generations. We can evolve the population generation by generation, e.g. using diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index d78a789db..c89b7121e 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -50,59 +50,8 @@ class OptimizationProblem: Example ------- - This example shows the optimization of the thermal efficiency of the - `SamplePlant` with respect to the pressure value at the intermediate - extration of the turbine. You can find the example code on the GitHub page - of TESPy: - :download:`example implementation `. - - To use the API, you need to define a class holding a TESPy network. You - create an instance of your plant class, i.e. :code:`plant = SamplePlant()`. - Then create an instance of the class - :py:class:`tespy.tools.optimization.OptimizationProblem` and pass - - - the plant instance, - - the variables, - - the constraints and - - the objective function name. - - For the optimization problem in this example, it can be formulated as - unconstrained problem by defining the lower and the upper limits for the - variable values, the constraints parameter can be left out. The objective - function of your plant (:code:`get_objective`), should return the - evaluation of the objective function. You can define multiple objective - functions, which can be accessed by the name of the objective. In the - example code only the thermal efficiency is defined, therefore the - :code:`objective` keyword does not need to be defined. The keywod is mainly - of use, if you want to quickly change the evaluation. - - The only variable in this example is the extraction pressure at the - turbine. The upper limit is 50 bar and the lower limit 0.4 bar. Of course, - it is possible to use multiple variables and component parameters as - variables as well. Just provide them in the same structure as in this - example. - - .. note:: - - Please note, that the sense of optimization is always minimization, - therefore you need to define your objective functions in the - appropriate way. - - After selection of an appropriate algorithm (differential evolution is a - good fit for this application) we can start the optimization run. For more - information on algorithms available in the PyGMO framework and their - individual specifications please refer to the respective section in their - online documentation: - `list of algorithms `__. - Specify the number of individuals, the number of generations and call the - :py:meth:`tespy.tools.optimization.OptimizationProblem.run` method of your - :code:`OptimizationProblem` instance passing the algorithm and the number - of individials and generations. - - In our sample run, we found an optimal value for the extraction pressure of - about 4.45 bar for a thermal efficiency of 38.7 %. The results for every - individual in each generation are stored in the :code:`individuals` - attribute of the :code:`OptimizationProblem`. + For an example please go to the tutorials section of TESPy's online + documentation. """ def __init__(self, model, variables={}, constraints={}, objective="objective"): From 960f71690c17811a0db559c28b6cbf8e6dc30064 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 5 Sep 2022 21:10:16 +0200 Subject: [PATCH 084/120] Update What's New --- docs/tutorials.rst | 4 ++-- docs/whats_new/v0-6-1.rst | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 750d1e080..215d502aa 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -11,13 +11,13 @@ At the example of different heat pump topologies, you will learn to - create a more complex model *step by step* and get the idea of designing a plant and calculating the offdesign behavior. - set up a code structure, which allows you to generate stable starting values - flexibly, helping you to make faster analyses. + flexibly, helping you to build reliable setups faster. - use the inbuilt exergy analysis method in a simple geothermal heat pump setting. Furthermore, we introduce the coupling of TESPy with pygmo in order to create an optimization problem, which optimizes thermal efficiency of a clausius -rankine power plant. +rankine power plant. The - CGAM! - Larger dh system diff --git a/docs/whats_new/v0-6-1.rst b/docs/whats_new/v0-6-1.rst index d4602506c..b0466fac1 100644 --- a/docs/whats_new/v0-6-1.rst +++ b/docs/whats_new/v0-6-1.rst @@ -1,5 +1,9 @@ v0.6.1 - Upcoming features ++++++++++++++++++++++++++ +We have completely revised the documentation improving the overall structure +and introducing a modern look +(`PR #355 `_). Have fun exploring the +website! New Features ############ From 0d30f5b3b0828df59a2d735a820422500bdabdd1 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 5 Sep 2022 21:14:05 +0200 Subject: [PATCH 085/120] Modify Problemclass to accept referenced constraints --- src/tespy/tools/optimization.py | 94 ++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 31 deletions(-) diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index c89b7121e..88dbefd16 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -105,23 +105,65 @@ def __init__(self, model, variables={}, constraints={}, objective="objective"): self.input_dict = self.variables.copy() self.nic = 0 - for obj, data in self.constraints['upper limits'].items(): - for label, constraints in data.items(): - for param, constraint in constraints.items(): - self.nic += 1 - self.constraint_list += [ - obj + '-' + label + '-' + param + ' <= ' + - str(constraint) - ] + self.collect_constraints("upper", build=True) + self.collect_constraints("lower", build=True) + + def collect_constraints(self, border, build=False): + """Collect the constraints + + Parameters + ---------- + border : str + "upper" or "lower", determine which constraints to collect. + build : bool, optional + If True, the constraints are evaluated and returned, by default + False - for obj, data in self.constraints['lower limits'].items(): + Returns + ------- + tuple + Return the upper and lower constraints evaluation lists. + """ + evaluation = [] + for obj, data in self.constraints[f'{border} limits'].items(): for label, constraints in data.items(): for param, constraint in constraints.items(): - self.nic += 1 - self.constraint_list += [ - obj + '-' + label + '-' + param + ' >= ' + - str(constraint) - ] + # to build the equations + if build: + self.nic += 1 + if isinstance(constraint, str): + right_side = '-'.join(self.constraints[constraint]) + else: + right_side = str(constraint) + + direction = '>=' if border == 'lower' else '<=' + self.constraint_list += [ + obj + '-' + label + '-' + param + direction + + right_side + ] + # to get the constraints evaluation + else: + if isinstance(constraint, str): + c = ( + self.model.get_param( + *self.constraints[constraint] + ) - self.model.get_param(obj, label, param) + ) + else: + c = ( + constraint - + self.model.get_param(obj, label, param) + ) + if border == 'lower': + evaluation += [c] + else: + evaluation += [-c] + + if build: + return None + else: + return evaluation + def fitness(self, x): """Evaluate the fitness function of an individual. @@ -151,18 +193,8 @@ def fitness(self, x): self.model.solve_model(**self.input_dict) f1 = [self.model.get_objective(self.objective)] - cu = [ - self.model.get_param(obj, label, parameter) - constraint - for obj, data in self.constraints['upper limits'].items() - for label, constraints in data.items() - for parameter, constraint in constraints.items() - ] - cl = [ - constraint - self.model.get_param(obj, label, parameter) - for obj, data in self.constraints['lower limits'].items() - for label, constraints in data.items() - for parameter, constraint in constraints.items() - ] + cu = self.collect_constraints("upper") + cl = self.collect_constraints("lower") return f1 + cu + cl @@ -207,14 +239,17 @@ def _process_generation_data(self, gen, pop): self.individuals[self.constraint_list] < 0 ).all(axis='columns') - def run(self, algo, num_ind, num_gen): + def run(self, algo, pop, num_ind, num_gen): """Run the optimization algorithm. Parameters ---------- - algo : pygmo.core + algo : pygmo.core.algorithm PyGMO optimization algorithm. + pop : pygmo.core.population + PyGMO population. + num_ind : int Number of individuals. @@ -235,9 +270,6 @@ def run(self, algo, num_ind, num_gen): self.individuals.set_index(["gen", "ind"], inplace=True) - algo = pg.algorithm(algo) - pop = pg.population(pg.problem(self), size=num_ind) - # replace prints with logging gen = 0 for gen in range(num_gen - 1): From 9e57de5f9bea303fade987c5b4c397a8f52b0ae1 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 5 Sep 2022 21:14:32 +0200 Subject: [PATCH 086/120] Adjust optimization example to more complex version --- tutorial/optimization_example.py | 247 ++++++++++++++++++++----------- 1 file changed, 161 insertions(+), 86 deletions(-) diff --git a/tutorial/optimization_example.py b/tutorial/optimization_example.py index 292a62aba..9a90a8b73 100644 --- a/tutorial/optimization_example.py +++ b/tutorial/optimization_example.py @@ -1,17 +1,21 @@ import numpy as np import pygmo as pg -from tespy.components.basics.cycle_closer import CycleCloser -from tespy.components.heat_exchangers.condenser import Condenser -from tespy.components.heat_exchangers.simple import HeatExchangerSimple -from tespy.components.nodes.merge import Merge -from tespy.components.nodes.splitter import Splitter -from tespy.components.piping.valve import Valve -from tespy.components.turbomachinery.pump import Pump -from tespy.components.turbomachinery.turbine import Turbine -from tespy.connections.bus import Bus -from tespy.connections.connection import Connection -from tespy.networks.network import Network +from tespy.components import CycleCloser +from tespy.components import Sink +from tespy.components import Source +from tespy.components import Condenser +from tespy.components import Desuperheater +from tespy.components import HeatExchangerSimple +from tespy.components import Merge +from tespy.components import Splitter +from tespy.components import Valve +from tespy.components import Pump +from tespy.components import Turbine +from tespy.connections import Bus +from tespy.connections import Connection +from tespy.networks import Network + from tespy.tools.optimization import OptimizationProblem @@ -19,75 +23,121 @@ class SamplePlant: """Class template for TESPy model usage in optimization module.""" def __init__(self): - self.nw = Network(fluids=['water']) - self.nw.set_attr(p_unit="bar", T_unit="C", h_unit="kJ / kg", iterinfo=False) + self.nw = Network(fluids=["water"]) + self.nw.set_attr( + p_unit="bar", T_unit="C", h_unit="kJ / kg", iterinfo=False + ) + # components + # main cycle + sg = HeatExchangerSimple("steam generator") + cc = CycleCloser("cycle closer") + hpt = Turbine("high pressure turbine") + sp1 = Splitter("splitter 1", num_out=2) + mpt = Turbine("mid pressure turbine") + sp2 = Splitter("splitter 2", num_out=2) + lpt = Turbine("low pressure turbine") + con = Condenser("condenser") + pu1 = Pump("feed water pump") + fwh1 = Condenser("feed water preheater 1") + fwh2 = Condenser("feed water preheater 2") + dsh = Desuperheater("desuperheater") + me2 = Merge("merge2", num_in=2) + pu2 = Pump("feed water pump 2") + pu3 = Pump("feed water pump 3") + me = Merge("merge", num_in=2) + + # cooling water + cwi = Source("cooling water source") + cwo = Sink("cooling water sink") + + # connections + # main cycle + c0 = Connection(sg, "out1", cc, "in1", label="0") + c1 = Connection(cc, "out1", hpt, "in1", label="1") + c2 = Connection(hpt, "out1", sp1, "in1", label="2") + c3 = Connection(sp1, "out1", mpt, "in1", label="3", state="g") + c4 = Connection(mpt, "out1", sp2, "in1", label="4") + c5 = Connection(sp2, "out1", lpt, "in1", label="5") + c6 = Connection(lpt, "out1", con, "in1", label="6") + c7 = Connection(con, "out1", pu1, "in1", label="7", state="l") + c8 = Connection(pu1, "out1", fwh1, "in2", label="8", state="l") + c9 = Connection(fwh1, "out2", me, "in1", label="9", state="l") + c10 = Connection(me, "out1", fwh2, "in2", label="10", state="l") + c11 = Connection(fwh2, "out2", dsh, "in2", label="11", state="l") + c12 = Connection(dsh, "out2", me2, "in1", label="12", state="l") + c13 = Connection(me2, "out1", sg, "in1", label="13", state="l") + + self.nw.add_conns( + c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13 + ) + + # preheating + c21 = Connection(sp1, "out2", dsh, "in1", label="21") + c22 = Connection(dsh, "out1", fwh2, "in1", label="22") + c23 = Connection(fwh2, "out1", pu2, "in1", label="23") + c24 = Connection(pu2, "out1", me2, "in2", label="24") - # main cycle components cycle closer - steam_generator = HeatExchangerSimple("steam generator") - close_cycle = CycleCloser("cycle closer") + c31 = Connection(sp2, "out2", fwh1, "in1", label="31") + c32 = Connection(fwh1, "out1", pu3, "in1", label="32") + c33 = Connection(pu3, "out1", me, "in2", label="33") - turbine_hp = Turbine("turbine high pressure") - turbine_lp = Turbine("turbine low pressure") - extraction = Splitter("steam extraction splitter", num_out=2) - preheater = Condenser("feed water preheater") - valve = Valve("preheater condensate valve") - waste_steam_merge = Merge("waste steam merge") + self.nw.add_conns( + c21, c22, c23, c24, + c31, c32, c33 + ) - condenser = HeatExchangerSimple("main condenser") - feed_pump = Pump("feed water pump") + # cooling water + c41 = Connection(cwi, "out1", con, "in2", label="41") + c42 = Connection(con, "out2", cwo, "in1", label="42") - # Connections + self.nw.add_conns(c41, c42) - # main cycle - c0 = Connection(steam_generator, "out1", close_cycle, "in1", label="0") - c1 = Connection(close_cycle, "out1", turbine_hp, "in1", label="1") - c2 = Connection(turbine_hp, "out1", extraction, "in1", label="2") - c3 = Connection(extraction, "out1", turbine_lp, "in1", label="3") - c4 = Connection(turbine_lp, "out1", waste_steam_merge, "in1", label="4") - c5 = Connection(waste_steam_merge, "out1", condenser, "in1", label="5") - c6 = Connection(condenser, "out1", feed_pump, "in1", label="6") - c7 = Connection(feed_pump, "out1", preheater, "in2", label="7") - c8 = Connection(preheater, "out2", steam_generator, "in1", label="8") - - # steam extraction - c11 = Connection(extraction, "out2", preheater, "in1", label="11") - c12 = Connection(preheater, "out1", valve, "in1", label="12") - c13 = Connection(valve, "out1", waste_steam_merge, "in2", label="13") - - self.nw.add_conns(c0, c1, c2, c3, c4, c5, c6, c7, c8, c11, c12, c13) - - # component specifications - steam_generator.set_attr(pr=0.92) - turbine_hp.set_attr(eta_s=0.9) - turbine_lp.set_attr(eta_s=0.9) - condenser.set_attr(pr=1) - feed_pump.set_attr(eta_s=0.75) - preheater.set_attr(ttd_u=5, pr1=1, pr2=0.98) - - # connection specifications - c1.set_attr(fluid={'water': 1}, p=100, T=600, m=10) - # pressure at connection 2 will be the parameter to optimize - c2.set_attr(p=10) - c6.set_attr(x=0, p=0.1) - # set liquid state to provide good starting values - c8.set_attr(state='l') - - power_bus = Bus('power output') - power_bus.add_comps( - {'comp': turbine_hp, 'char': 0.97}, - {'comp': turbine_lp, 'char': 0.97}, - {'comp': feed_pump, 'char': 0.97, 'base': 'bus'} + # busses + # power bus + self.power = Bus("power") + self.power.add_comps( + {"comp": hpt, "char": -1}, {"comp": mpt, "char": -1}, + {"comp": lpt, "char": -1}, {"comp": pu1, "char": -1}, + {"comp": pu2, "char": -1}, {"comp": pu3, "char": -1} ) - heat_bus = Bus('heat input') - heat_bus.add_comps({'comp': steam_generator}) - self.nw.add_busses(power_bus, heat_bus) + + # heating bus + self.heat = Bus("heat") + self.heat.add_comps({"comp": sg, "char": 1}) + + self.nw.add_busses(self.power, self.heat) + + # parametrization + # components + hpt.set_attr(eta_s=0.9) + mpt.set_attr(eta_s=0.9) + lpt.set_attr(eta_s=0.9) + + pu1.set_attr(eta_s=0.8) + pu2.set_attr(eta_s=0.8) + pu3.set_attr(eta_s=0.8) + + sg.set_attr(pr=0.92) + + con.set_attr(pr1=1, pr2=0.99, ttd_u=5) + fwh1.set_attr(pr1=1, pr2=0.99, ttd_u=5) + fwh2.set_attr(pr1=1, pr2=0.99, ttd_u=5) + dsh.set_attr(pr1=0.99, pr2=0.99) + + c1.set_attr(m=200, T=650, p=100, fluid={"water": 1}) + c2.set_attr(p=20) + c4.set_attr(p=3) + + c41.set_attr(T=20, p=3, fluid={"water": 1}) + c42.set_attr(T=28) self.nw.solve("design") self.stable = "_stable" self.nw.save(self.stable) + self.solved = True def get_param(self, obj, label, parameter): - """Get the value of a parameter in the network's unit system. + """Get the value of a parameter in the network"s unit system. Parameters ---------- @@ -105,9 +155,9 @@ def get_param(self, obj, label, parameter): value : float Value of the parameter. """ - if obj == 'Components': + if obj == "Components": return self.nw.get_comp(label).get_attr(parameter).val - elif obj == 'Connections': + elif obj == "Connections": return self.nw.get_conn(label).get_attr(parameter).val def set_params(self, **kwargs): @@ -122,9 +172,8 @@ def set_params(self, **kwargs): def solve_model(self, **kwargs): """ - Solve the TESPy model given the + Solve the TESPy model given the the input parameters """ - self.set_params(**kwargs) self.solved = False @@ -134,7 +183,7 @@ def solve_model(self, **kwargs): self.nw.solve("design", init_only=True, init_path=self.stable) else: # might need more checks here! - if any(self.nw.results['Condenser']['Q'] > 0): + if any(self.nw.results["Condenser"]["Q"] > 0): self.solved = False else: self.solved = True @@ -142,7 +191,7 @@ def solve_model(self, **kwargs): self.nw.lin_dep = True self.nw.solve("design", init_only=True, init_path=self.stable) - def get_objective(self, objective): + def get_objective(self, objective=None): """ Get the current objective function evaluation. @@ -157,20 +206,46 @@ def get_objective(self, objective): Evaluation of the objective function. """ if self.solved: - return -1 / ( - self.nw.busses['power output'].P.val / - self.nw.busses['heat input'].P.val - ) + if objective == "efficiency": + return 1 / ( + self.nw.busses["power"].P.val / + self.nw.busses["heat"].P.val + ) + else: + msg = f"Objective {objective} not implemented." + raise NotImplementedError(msg) else: return np.nan plant = SamplePlant() -variables = {"Connections": {"2": {"p": {"min": 0.4, "max": 50}}}} -optimize = OptimizationProblem(plant, variables) - -num_ind = 10 -num_gen = 15 - -algo = pg.de() -optimize.run(algo, num_ind, num_gen) +plant.get_objective("efficiency") +variables = { + "Connections": { + "2": {"p": {"min": 1, "max": 40}}, + "4": {"p": {"min": 1, "max": 40}} + } +} +constraints = { + "lower limits": { + "Connections": { + "2": {"p": "ref1"} + }, + }, + "ref1": ["Connections", "4", "p"] +} + +optimize = OptimizationProblem( + plant, variables, constraints, objective="efficiency" +) + +num_ind = 5 +num_gen = 3 + +# careful here, some algorithms do need the number of generations passed, +# some not! +algo = pg.algorithm(pg.ihs(gen=num_gen)) +# create starting population +pop = pg.population(pg.problem(optimize), size=num_ind) + +optimize.run(algo, pop, num_ind, num_gen) From bb49648a1523794ca151db15714b736f34e86369 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 5 Sep 2022 21:18:42 +0200 Subject: [PATCH 087/120] Update What's New --- docs/whats_new/v0-6-1.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/whats_new/v0-6-1.rst b/docs/whats_new/v0-6-1.rst index b0466fac1..7f8f89df1 100644 --- a/docs/whats_new/v0-6-1.rst +++ b/docs/whats_new/v0-6-1.rst @@ -16,7 +16,8 @@ New Features (`PR #329 `_). - Integration of an optimization suite using pygmo :cite:`Biscani2020` to apply a variety of state of the art optimization algorithms to your TESPy model - (`PR #296 `_). + (`PR #296 `_). It has been further + improved in `PR #357 `_. Documentation ############# From 5cdd1988ef1588426a954cc924ea9907776e314c Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 5 Sep 2022 21:19:55 +0200 Subject: [PATCH 088/120] Move to final location --- tutorial/{ => advanced}/optimization_example.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tutorial/{ => advanced}/optimization_example.py (100%) diff --git a/tutorial/optimization_example.py b/tutorial/advanced/optimization_example.py similarity index 100% rename from tutorial/optimization_example.py rename to tutorial/advanced/optimization_example.py From 0ee40df1c3f97e9705f582c23ae3a78baf5b49d9 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 6 Sep 2022 16:50:02 +0200 Subject: [PATCH 089/120] Fill in some text in benchmarks section --- docs/benchmarks.rst | 51 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/docs/benchmarks.rst b/docs/benchmarks.rst index e69a48c48..228cabb1e 100644 --- a/docs/benchmarks.rst +++ b/docs/benchmarks.rst @@ -1,8 +1,49 @@ Benchmarks ========== +To ensure credibility as well as reproducibility for the software, several +measures are taken. The most important information is listed below: -- SEGS :cite:`Witte2022` -- sCO2 :cite:`Witte2022` -- air refrigeration :cite:`Witte2022` -- CGAM :cite:`Hofmann2022`, :cite:`Valero1994`, :cite:`Bejan1996` -- UNIT TESTING STUFF +Model Validation +---------------- +TESPy has been used to model several different research and engineering +applications. In the paper on integration of generic exergy analysis in TESPy +:cite:`Witte2022` three models have been built from literature sources: A +solar thermal power plant, a supercritical CO2 brayton cycle as well as a +refrigeration machine using air as working fluid. + +For the solar thermal power plant we have created a full model of the plant +using a standard industry software in parallel. **The comparison showed** +**identical results**. For the other two applications we have compared the +results of the TESPy model with the data published in the respective research +paper and found very well matching results. Differences can be explained by +different implementations of the fluid property back-end. + +Finally, in the extension of the exergy analysis to chemical exergy +:cite:`Hofmann2022` we have also compared results of the CGAM process +:cite:`Valero1994` modeled in TESPy with a full model using industry software +and with the data provided from literature as well :cite:`Bejan1996`. + +Unit testing +------------ +Appart from the full model validation, the software includes full unit testing. +Here, single features of the software are tested by comparing the result the +software provides with the result we would expect when manually modeling that +feature. For example, we set up a turbine and check, whether the isentropic +efficiency specification in the TESPy component matches the results that is +expected doing the same process manually. This is done for all modules of the +software. + +Furthermore, the full models denoted in the model validation are included in +the testing pipeline as well. + +Continuous Integration +---------------------- +TESPy has a +`Continuous Integration `__ +pipeline. The unit tests and the full model tests are automatically run +whenever changes to the source code of the software are made. By this we can +ensure, that changes in the code do not break with existing features or +invalidate results of the existing models. + +For more information on how to run the tests please see the +:ref:`how to develop ` section. From 3dc7dd7f8293021d378c4383e25302f6efa3ba9c Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 6 Sep 2022 16:52:49 +0200 Subject: [PATCH 090/120] Update images --- .../subsystem_waste_heat_generator.svg | 357 +++++++++++++++++ ...ubsystem_waste_heat_generator_darkmode.svg | 358 ++++++++++++++++++ docs/modules/subsystems.rst | 13 +- 3 files changed, 726 insertions(+), 2 deletions(-) create mode 100644 docs/_static/images/modules/subsystem_waste_heat_generator.svg create mode 100644 docs/_static/images/modules/subsystem_waste_heat_generator_darkmode.svg diff --git a/docs/_static/images/modules/subsystem_waste_heat_generator.svg b/docs/_static/images/modules/subsystem_waste_heat_generator.svg new file mode 100644 index 000000000..5c06d0533 --- /dev/null +++ b/docs/_static/images/modules/subsystem_waste_heat_generator.svg @@ -0,0 +1,357 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + evaporator + drum + + + + + + + + + + + + + + + + + + + + + + + + superheater + economizer + + diff --git a/docs/_static/images/modules/subsystem_waste_heat_generator_darkmode.svg b/docs/_static/images/modules/subsystem_waste_heat_generator_darkmode.svg new file mode 100644 index 000000000..294f07948 --- /dev/null +++ b/docs/_static/images/modules/subsystem_waste_heat_generator_darkmode.svg @@ -0,0 +1,358 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + evaporator + drum + + + + + + + + + + + + + + + + + + + + + + + + superheater + economizer + + diff --git a/docs/modules/subsystems.rst b/docs/modules/subsystems.rst index 8ba660416..336625ec1 100644 --- a/docs/modules/subsystems.rst +++ b/docs/modules/subsystems.rst @@ -34,10 +34,19 @@ We create a subsystem for the usage of a waste heat steam generator. The subsystem is built up of a superheater, an evaporator, a drum and an economizer as seen in the figure below. -.. figure:: /api/_images/subsystem_waste_heat_generator.svg +.. figure:: /_static/images/modules/subsystem_waste_heat_generator.svg :align: center + :alt: Topology of the waste heat steam generator + :figclass: only-light - Figure: Topology of the waste heat steam generator. + Figure: Topology of the waste heat steam generator + +.. figure:: /_static/images/modules/subsystem_waste_heat_generator_darkmode.svg + :align: center + :alt: Topology of the waste heat steam generator + :figclass: only-dark + + Figure: Topology of the waste heat steam generator Create a file, e.g. :code:`mysubsystems.py` and add the following lines: From a95c38e375e92d77ab52daae81a7761d708f0212 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 6 Sep 2022 17:47:32 +0200 Subject: [PATCH 091/120] Restructure a lot of code --- docs/tutorials/pygmo_optimization.rst | 344 ++++------------------ tutorial/advanced/optimization_example.py | 53 +++- 2 files changed, 109 insertions(+), 288 deletions(-) diff --git a/docs/tutorials/pygmo_optimization.rst b/docs/tutorials/pygmo_optimization.rst index 620bb14a8..f34beb326 100644 --- a/docs/tutorials/pygmo_optimization.rst +++ b/docs/tutorials/pygmo_optimization.rst @@ -102,315 +102,85 @@ First, we set up the class with the TESPy network. .. dropdown:: Display source code for the PowerPlant class - .. code-block:: python - - from tespy.networks import Network - from tespy.components import ( - Turbine, Splitter, Merge, Condenser, Pump, Sink, Source, - HeatExchangerSimple, Desuperheater, CycleCloser - ) - from tespy.connections import Connection, Bus - from tespy.tools import logger - import logging - - import numpy as np - - - logger.define_logging(screen_level=logging.ERROR) - - - class PowerPlant(): - - def __init__(self): - self.nw = Network( - fluids=['BICUBIC::water'], - p_unit='bar', T_unit='C', h_unit='kJ / kg', - iterinfo=False) - # components - # main cycle - eco = HeatExchangerSimple('economizer') - eva = HeatExchangerSimple('evaporator') - sup = HeatExchangerSimple('superheater') - cc = CycleCloser('cycle closer') - hpt = Turbine('high pressure turbine') - sp1 = Splitter('splitter 1', num_out=2) - mpt = Turbine('mid pressure turbine') - sp2 = Splitter('splitter 2', num_out=2) - lpt = Turbine('low pressure turbine') - con = Condenser('condenser') - pu1 = Pump('feed water pump') - fwh1 = Condenser('feed water preheater 1') - fwh2 = Condenser('feed water preheater 2') - dsh = Desuperheater('desuperheater') - me2 = Merge('merge2', num_in=2) - pu2 = Pump('feed water pump 2') - pu3 = Pump('feed water pump 3') - me = Merge('merge', num_in=2) - - # cooling water - cwi = Source('cooling water source') - cwo = Sink('cooling water sink') - - # connections - # main cycle - cc_hpt = Connection(cc, 'out1', hpt, 'in1', label='feed steam') - hpt_sp1 = Connection(hpt, 'out1', sp1, 'in1', label='extraction1') - sp1_mpt = Connection(sp1, 'out1', mpt, 'in1', state='g') - mpt_sp2 = Connection(mpt, 'out1', sp2, 'in1', label='extraction2') - sp2_lpt = Connection(sp2, 'out1', lpt, 'in1') - lpt_con = Connection(lpt, 'out1', con, 'in1') - con_pu1 = Connection(con, 'out1', pu1, 'in1') - pu1_fwh1 = Connection(pu1, 'out1', fwh1, 'in2') - fwh1_me = Connection(fwh1, 'out2', me, 'in1', state='l') - me_fwh2 = Connection(me, 'out1', fwh2, 'in2', state='l') - fwh2_dsh = Connection(fwh2, 'out2', dsh, 'in2', state='l') - dsh_me2 = Connection(dsh, 'out2', me2, 'in1') - me2_eco = Connection(me2, 'out1', eco, 'in1', state='l') - eco_eva = Connection(eco, 'out1', eva, 'in1') - eva_sup = Connection(eva, 'out1', sup, 'in1') - sup_cc = Connection(sup, 'out1', cc, 'in1') - - self.nw.add_conns(cc_hpt, hpt_sp1, sp1_mpt, mpt_sp2, sp2_lpt, - lpt_con, con_pu1, pu1_fwh1, fwh1_me, me_fwh2, - fwh2_dsh, dsh_me2, me2_eco, eco_eva, eva_sup, sup_cc) - - # cooling water - cwi_con = Connection(cwi, 'out1', con, 'in2') - con_cwo = Connection(con, 'out2', cwo, 'in1') - - self.nw.add_conns(cwi_con, con_cwo) - - # preheating - sp1_dsh = Connection(sp1, 'out2', dsh, 'in1') - dsh_fwh2 = Connection(dsh, 'out1', fwh2, 'in1') - fwh2_pu2 = Connection(fwh2, 'out1', pu2, 'in1') - pu2_me2 = Connection(pu2, 'out1', me2, 'in2') - - sp2_fwh1 = Connection(sp2, 'out2', fwh1, 'in1') - fwh1_pu3 = Connection(fwh1, 'out1', pu3, 'in1') - pu3_me = Connection(pu3, 'out1', me, 'in2') - - self.nw.add_conns(sp1_dsh, dsh_fwh2, fwh2_pu2, pu2_me2, - sp2_fwh1, fwh1_pu3, pu3_me) - - # busses - # power bus - self.power = Bus('power') - self.power.add_comps( - {'comp': hpt, 'char': -1}, {'comp': mpt, 'char': -1}, - {'comp': lpt, 'char': -1}, {'comp': pu1, 'char': -1}, - {'comp': pu2, 'char': -1}, {'comp': pu3, 'char': -1}) - - # heating bus - self.heat = Bus('heat') - self.heat.add_comps( - {'comp': eco, 'char': 1}, {'comp': eva, 'char': 1}, - {'comp': sup, 'char': 1}) - - self.nw.add_busses(self.power, self.heat) - - # parametrization - # components - hpt.set_attr(eta_s=0.9) - mpt.set_attr(eta_s=0.9) - lpt.set_attr(eta_s=0.9) - - pu1.set_attr(eta_s=0.8) - pu2.set_attr(eta_s=0.8) - pu3.set_attr(eta_s=0.8) - - eco.set_attr(pr=0.99) - eva.set_attr(pr=0.99) - sup.set_attr(pr=0.99) - - con.set_attr(pr1=1, pr2=0.99, ttd_u=5) - fwh1.set_attr(pr1=1, pr2=0.99, ttd_u=5) - fwh2.set_attr(pr1=1, pr2=0.99, ttd_u=5) - dsh.set_attr(pr1=0.99, pr2=0.99) - - # connections - eco_eva.set_attr(x=0) - eva_sup.set_attr(x=1) - - cc_hpt.set_attr(m=200, T=650, p=100, fluid={'water': 1}) - hpt_sp1.set_attr(p=20) - mpt_sp2.set_attr(p=3) - lpt_con.set_attr(p=0.05) - - cwi_con.set_attr(T=20, p=10, fluid={'water': 1}) - - def calculate_efficiency(self, x): - # set extraction pressure - self.nw.get_conn('extraction1').set_attr(p=x[0]) - self.nw.get_conn('extraction2').set_attr(p=x[1]) - - self.nw.solve('design') - - # components are saved in a DataFrame, column 'object' holds the - # component instances - for cp in self.nw.comps['object']: - if isinstance(cp, Condenser) or isinstance(cp, Desuperheater): - if cp.Q.val > 0: - return np.nan - elif isinstance(cp, Pump): - if cp.P.val < 0: - return np.nan - elif isinstance(cp, Turbine): - if cp.P.val > 0: - return np.nan - - if self.nw.res[-1] > 1e-3 or self.nw.lin_dep: - return np.nan - else: - return self.nw.busses['power'].P.val / self.nw.busses['heat'].P.val + .. literalinclude:: /../tutorial/advanced/optimization_example.py + :language: python + :start-after: [sec_1] + :end-before: [sec_2] + Next, we add the methods :code:`get_param`, :code:`solve_model` and -:code:`get_objective`. +:code:`get_objective`. On top of that, we add a setter working in a similar +way as the getter. The objective is to maximize thermal efficiency as defined +in the equation below. + +.. math:: + + \eta_\mathrm{th}=\frac{|\sum P|}{\dot{Q}_{sg}} -.. note:: +.. attention:: The sense of optimization is always minimization, therefore you need to - define your objective functions in the appropriate way. + define your objective functions in the appropriate way: We return the + reciprocal value of the efficiency for this reason. -Additionally, we have to make sure, only the result of physically feasible -solutions is returned. In case we have infeasible solutions, we can simply -return :code:`np.nan`. An infeasible solution is obtained in case the power -of a turbine is positive, the power of a pump is negative or the heat exchanged +We also have to make sure, only the results of physically feasible solutions +are returned. In case we have infeasible solutions, we can simply return +:code:`np.nan`. An infeasible solution is obtained in case the power of a +turbine is positive, the power of a pump is negative or the heat exchanged in any of the preheaters is positive. We also check, if the calculation does converge. +.. dropdown:: Display source code for the class methods + + .. literalinclude:: /../tutorial/advanced/optimization_example.py + :language: python + :start-after: [sec_2] + :end-before: [sec_3] + After this, we import the :py:class:`tespy.tools.optimize.OptimizationProblem` class and create an instance of our self defined class, which we pass to an instance of the OptimizationProblem class. We also have to pass - the variables to optimize, - the constraints to consider and -- the objective function name (you can define multiple). +- the objective function name (you could define multiple in the + :code:`get_objective` method if you wanted). -Before we can run the optimization, we only need to select an appropriate -algorithm. After that we can start the optimization run. For more information -on algorithms available in the PyGMO framework and their individual -specifications please refer to the respective section in their online -documentation: -`list of algorithms `__. -Specify the number of individuals, the number of generations and call the -:py:meth:`tespy.tools.optimization.OptimizationProblem.run` method of your -:code:`OptimizationProblem` instance passing the algorithm and the number -of individuals and generations. - -.. math:: - - \eta_\mathrm{th}=\frac{|\sum P|}{\dot{Q}_{sg}} - -Creating your PyGMO-Model -^^^^^^^^^^^^^^^^^^^^^^^^^ - -The optimization in PyGMO starts by defining the problem. You can set the -number of objectives your problem has in :code:`get_nobj()`. The number of -constraints is set in :code:`get_nec()` (equality constraints) and -:code:`get_nic()` (inequality constraints). In :code:`get_bounds()` you set the -bounds of your decision variables. Finally, you define your fitness function -and constraints in :code:`fitness(self, x)`: - -.. code-block:: python - - import pygmo as pg - - - class optimization_problem(): - - def fitness(self, x): - f1 = 1 / self.model.calculate_efficiency(x) - ci1 = -x[0] + x[1] - print(x) - return [f1, ci1] - - def get_nobj(self): - """Return number of objectives.""" - return 1 - - # equality constraints - def get_nec(self): - return 0 - - # inequality constraints - def get_nic(self): - return 1 - - def get_bounds(self): - """Return bounds of decision variables.""" - return ([1, 1], [40, 40]) - -By default PyGMO minimizes the fitness function. Therefore we set the fitness -function f1 to the reciprocal of the cycle efficiency. We set one inequality -constraint so that the pressure of the first extraction has to be bigger than -the second one: +We set one inequality constraint, namely that the pressure of the first +extraction has to be higher than the pressure at the second one: .. math:: p_{e,1} > p_{e,2} -In PyGMO your inequality constraint has to be in form of <0: - -.. math:: - - - p_{e,1} + p_{e,2} < 0 - -We expect that the extraction pressure won't be more than 40 bar and not less -1 bar. Therefore we set the bounds of our decision variables: - -.. math:: +To do this, we can set a lower limit for the pressure at connection 2 and +reference the pressure at connection 4 as seen in the code: - 1 bar < p_{e,1} < 40 bar\\ - 1 bar < p_{e,2} < 40 bar +.. literalinclude:: /../tutorial/advanced/optimization_example.py + :language: python + :start-after: [sec_3] + :end-before: [sec_4] +Before we can run the optimization, we only need to select an appropriate +algorithm. After that we can start the optimization run. For more information +on algorithms available in the PyGMO framework and their individual +specifications please refer to the respective section in their online +documentation: +`list of algorithms `__. +Create an initial population and then specify the number of individuals, the +number of generations and call the +:py:meth:`tespy.tools.optimization.OptimizationProblem.run` method of your +:code:`OptimizationProblem` instance passing the algorithm, the population and +the number of individuals and generations. Run PyGMO-Optimization ^^^^^^^^^^^^^^^^^^^^^^ +The following code then simply runs the PyGMO optimization. -The following code shows how to run the PyGMO optimization. - -.. code-block:: python - - optimize = optimization_problem() - optimize.model = PowerPlant() - prob = pg.problem(optimize) - num_gen = 15 - - pop = pg.population(prob, size=10) - algo = pg.algorithm(pg.ihs(gen=num_gen)) - - -With optimize you tell PyGMO which problem you want to optimize. In the class -:code:`optimization_problem()` we defined our problem be setting fitness -function and inequality constraint. With :code:`optimize.model` we set the -model we want to optimize. In our case we want to optimize the extraction -pressures in our instance of class :code:`PowerPlant`. Finally, our problem is -set in :code:`prob = pg.problem(optimize)`. - -With :code:`pop` we define the size of each population for the optimization, -:code:`algo` is used to set the algorithm you want to use. A list of available -algorithms can be found in -`List of algorithms `_. -The choice of your algorithm depends on the type of problem. Have you set -equality or inequality constraints? Do you perform a single- or -multi-objective optimization? - -We choose a population size of 10 individuals and want to carry out 15 -generations. We can evolve the population generation by generation, e.g. using -a for loop. At the end, we print out the information of the best individual. - -.. code-block:: python - - for gen in range(num_gen): - print('Evolution: {}'.format(gen)) - print('Efficiency: {} %'.format(round(100 / pop.champion_f[0], 4))) - pop = algo.evolve(pop) - - print() - print('Efficiency: {} %'.format(round(100 / pop.champion_f[0], 4))) - print('Extraction 1: {} bar'.format(round(pop.champion_x[0], 4))) - print('Extraction 2: {} bar'.format(round(pop.champion_x[1], 4))) +.. literalinclude:: /../tutorial/advanced/optimization_example.py + :language: python + :start-after: [sec_4] + :end-before: [sec_5] In our run, we got: @@ -420,8 +190,16 @@ In our run, we got: Extraction 1: 25.8585 bar Extraction 2: 2.6903 bar - .. figure:: /api/_images/scatterplot_efficiency_optimization.svg :align: center Figure: Scatter plot for all individuals during the optimization. + +Finally, you can access the individuals in each of the generations and you +can have a look at you population. For more info on the population API please +visit the pygmo documentation. + +.. literalinclude:: /../tutorial/advanced/optimization_example.py + :language: python + :start-after: [sec_5] + :end-before: [sec_6] diff --git a/tutorial/advanced/optimization_example.py b/tutorial/advanced/optimization_example.py index 9a90a8b73..c7619aed3 100644 --- a/tutorial/advanced/optimization_example.py +++ b/tutorial/advanced/optimization_example.py @@ -1,3 +1,4 @@ +# %%[sec_1] import numpy as np import pygmo as pg @@ -136,6 +137,8 @@ def __init__(self): self.nw.save(self.stable) self.solved = True + # %%[sec_2] + def get_param(self, obj, label, parameter): """Get the value of a parameter in the network"s unit system. @@ -183,7 +186,12 @@ def solve_model(self, **kwargs): self.nw.solve("design", init_only=True, init_path=self.stable) else: # might need more checks here! - if any(self.nw.results["Condenser"]["Q"] > 0): + if ( + any(self.nw.results["Condenser"]["Q"] > 0) + or any(self.nw.results["Desuperheater"]["Q"] > 0) + or any(self.nw.results["Turbine"]["P"] > 0) + or any(self.nw.results["Pump"]["P"] < 0) + ): self.solved = False else: self.solved = True @@ -217,6 +225,7 @@ def get_objective(self, objective=None): else: return np.nan + # %%[sec_3] plant = SamplePlant() plant.get_objective("efficiency") @@ -238,14 +247,48 @@ def get_objective(self, objective=None): optimize = OptimizationProblem( plant, variables, constraints, objective="efficiency" ) - -num_ind = 5 -num_gen = 3 +# %%[sec_4] +num_ind = 10 +num_gen = 25 # careful here, some algorithms do need the number of generations passed, # some not! algo = pg.algorithm(pg.ihs(gen=num_gen)) # create starting population -pop = pg.population(pg.problem(optimize), size=num_ind) +pop = pg.population(pg.problem(optimize), size=num_ind, seed=42) optimize.run(algo, pop, num_ind, num_gen) +# %%[sec_5] +# To access the results +print(optimize.individuals) +# check pygmo documentation to see, what you can get from the population +print(pop) +# plot the results +import matplotlib.pyplot as plt + + +# make text reasonably sized +plt.rc("font", **{"size": 18}) + +fig, ax = plt.subplots(1, figsize=(16, 8)) + +filter_valid_constraint = optimize.individuals["valid"].values +filter_valid_result = ~np.isnan(optimize.individuals["efficiency"].values) +data = optimize.individuals.loc[filter_valid_constraint & filter_valid_result] + +sc = ax.scatter( + data["Connections-2-p"], + data["Connections-4-p"], + c=1 / data["efficiency"] * 100, + s=100 +) +cbar = plt.colorbar(sc) +cbar.set_label("Thermal efficiency in %") + +ax.set_axisbelow(True) +ax.set_xlabel("Pressure at connection 2 in bar") +ax.set_ylabel("Pressure at connection 4 in bar") +plt.tight_layout() + +fig.savefig("pygmo_optimization.svg") +# %%[sec_6] From c4d2bec7351c9c56dafd0fa8ac8ea6a1abeb018a Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 6 Sep 2022 17:55:30 +0200 Subject: [PATCH 092/120] Finalize tutorial --- .../pygmo_optimization/pygmo_optimization.svg | 4114 +++++++++++++++++ docs/tutorials/pygmo_optimization.rst | 28 +- tutorial/advanced/optimization_example.py | 10 +- 3 files changed, 4135 insertions(+), 17 deletions(-) create mode 100644 docs/_static/images/tutorials/pygmo_optimization/pygmo_optimization.svg diff --git a/docs/_static/images/tutorials/pygmo_optimization/pygmo_optimization.svg b/docs/_static/images/tutorials/pygmo_optimization/pygmo_optimization.svg new file mode 100644 index 000000000..7e4f02431 --- /dev/null +++ b/docs/_static/images/tutorials/pygmo_optimization/pygmo_optimization.svg @@ -0,0 +1,4114 @@ + + + + + + + + 2022-09-06T17:50:12.894236 + image/svg+xml + + + Matplotlib v3.4.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/tutorials/pygmo_optimization.rst b/docs/tutorials/pygmo_optimization.rst index f34beb326..0f2d45b2a 100644 --- a/docs/tutorials/pygmo_optimization.rst +++ b/docs/tutorials/pygmo_optimization.rst @@ -19,7 +19,7 @@ TESPy to **maximize the cycle efficiency of a power plant with two** **extractions.** You can download the code here: -:download:`pygmo_optimization.py ` +:download:`optimization_example.py ` .. figure:: /_static/images/tutorials/pygmo_optimization/flowsheet.svg :align: center @@ -38,10 +38,10 @@ You can download the code here: What is PyGMO? ^^^^^^^^^^^^^^ -PyGMO (Python Parallel Global Multiobjective Optimizer, :cite:`Biscani2020`) is -a library that provides a large number of evolutionary optimization algorithms. -PyGMO can be used to solve constrained, unconstrained, single objective and -multi objective problems. +PyGMO (Python Parallel Global Multiobjective Optimizer, :cite:`Biscani2020`) +is a library that provides a large number of evolutionary optimization +algorithms. PyGMO can be used to solve constrained, unconstrained, single +objective and multi objective problems. Evolutionary Algorithms +++++++++++++++++++++++ @@ -137,9 +137,10 @@ converge. :start-after: [sec_2] :end-before: [sec_3] -After this, we import the :py:class:`tespy.tools.optimize.OptimizationProblem` -class and create an instance of our self defined class, which we pass to an -instance of the OptimizationProblem class. We also have to pass +After this, we import the +:py:class:`tespy.tools.optimization.OptimizationProblem` class and create an +instance of our self defined class, which we pass to an instance of the +OptimizationProblem class. We also have to pass - the variables to optimize, - the constraints to consider and @@ -186,14 +187,15 @@ In our run, we got: .. code:: bash - Efficiency: 44.8596 % - Extraction 1: 25.8585 bar - Extraction 2: 2.6903 bar + Efficiency: 44.82 % + Extraction 1: 25.4756 bar + Extraction 2: 2.5428 bar -.. figure:: /api/_images/scatterplot_efficiency_optimization.svg +.. figure:: /_static/images/tutorials/pygmo_optimization/pygmo_optimization.svg :align: center + :alt: Scatter plot for all individuals during the optimization - Figure: Scatter plot for all individuals during the optimization. + Figure: Scatter plot for all individuals during the optimization Finally, you can access the individuals in each of the generations and you can have a look at you population. For more info on the population API please diff --git a/tutorial/advanced/optimization_example.py b/tutorial/advanced/optimization_example.py index c7619aed3..213fcb869 100644 --- a/tutorial/advanced/optimization_example.py +++ b/tutorial/advanced/optimization_example.py @@ -249,11 +249,13 @@ def get_objective(self, objective=None): ) # %%[sec_4] num_ind = 10 -num_gen = 25 +num_gen = 100 -# careful here, some algorithms do need the number of generations passed, -# some not! -algo = pg.algorithm(pg.ihs(gen=num_gen)) +# for algorithm selection and parametrization please consider the pygmo +# documentation! The number of generations indicated in the algorithm is +# the number of evolutions we undertake within each generation defined in +# num_gen +algo = pg.algorithm(pg.ihs(gen=3, seed=42)) # create starting population pop = pg.population(pg.problem(optimize), size=num_ind, seed=42) From cd68be13cc77ed3bbb2f96fea4820124b95e0445 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 6 Sep 2022 18:00:40 +0200 Subject: [PATCH 093/120] Add flowsheets --- .../pygmo_optimization/flowsheet.svg | 693 ++++++++++++++++++ .../pygmo_optimization/flowsheet_darkmode.svg | 675 +++++++++++++++++ 2 files changed, 1368 insertions(+) create mode 100644 docs/_static/images/tutorials/pygmo_optimization/flowsheet.svg create mode 100644 docs/_static/images/tutorials/pygmo_optimization/flowsheet_darkmode.svg diff --git a/docs/_static/images/tutorials/pygmo_optimization/flowsheet.svg b/docs/_static/images/tutorials/pygmo_optimization/flowsheet.svg new file mode 100644 index 000000000..97b4ad2a1 --- /dev/null +++ b/docs/_static/images/tutorials/pygmo_optimization/flowsheet.svg @@ -0,0 +1,693 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + G + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + + + 41 + 42 + 12 + 13 + 21 + 23 + 24 + 33 + 32 + 31 + + + + + + diff --git a/docs/_static/images/tutorials/pygmo_optimization/flowsheet_darkmode.svg b/docs/_static/images/tutorials/pygmo_optimization/flowsheet_darkmode.svg new file mode 100644 index 000000000..ac0259092 --- /dev/null +++ b/docs/_static/images/tutorials/pygmo_optimization/flowsheet_darkmode.svg @@ -0,0 +1,675 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + G + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + + + 41 + 42 + 12 + 13 + 21 + 23 + 24 + 33 + 32 + 31 + + + + From f0ee3b6bb054470fc67f8b81fb2c581413945bc0 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 6 Sep 2022 20:28:46 +0200 Subject: [PATCH 094/120] Fix grid layout for advanced tutorials --- docs/basics.rst | 6 +++-- docs/tutorials.rst | 58 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/docs/basics.rst b/docs/basics.rst index ccec3e310..ccc9354d2 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -26,11 +26,13 @@ meetings as well as a discussion forum on GitHub. basics/district_heating.rst -.. card:: Introduction +.. card:: Introduction: Learn the basic modeling concept of TESPy :link: tespy_basics_intro_label :link-type: ref - Learn the basic modeling concept of TESPy + .. figure:: /_static/images/basics/modeling_concept.svg + :align: center + :alt: TESPy's modeling concept .. grid:: 2 :gutter: 1 diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 215d502aa..4244a35e5 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -17,10 +17,62 @@ At the example of different heat pump topologies, you will learn to Furthermore, we introduce the coupling of TESPy with pygmo in order to create an optimization problem, which optimizes thermal efficiency of a clausius -rankine power plant. The +rankine power plant. Another typical setup are heat recovery steam generators +using exhaust gases from an open cycle gas turbine. + +Finally, we provide an approach on how to model complex district heating +systems. If you have any questions, ideas for other tutorials or feedback, +please reach out to us. We are looking forward to hearing from you! + +.. grid:: 2 + :gutter: 1 + + .. grid-item-card:: Build complex systems step by step + :link: tespy_tutorial_heat_pump_label + :link-type: ref + + .. image:: /_static/images/tutorials/heat_pump_stepwise/flowsheet.svg + :class: only-light + + .. image:: /_static/images/tutorials/heat_pump_stepwise/flowsheet_darkmode.svg + :class: only-dark + + .. grid-item-card:: Generate stable starting values + :link: tespy_tutorial_starting_values_label + :link-type: ref + + .. image:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg + +.. grid:: 2 + :gutter: 1 + + .. grid-item-card:: Exergy analysis of a heat pump + :link: tespy_tutorial_heat_pump_exergy_label + :link-type: ref + + .. image:: /_static/images/tutorials/heat_pump_exergy/diagram_E_D.svg + + .. grid-item-card:: Building Complex District Heating Systems + :link: TODO + :link-type: ref + + Coming soon! + +.. grid:: 2 + :gutter: 1 + + .. grid-item-card:: Optimization of a thermal power plant + :link: tespy_tutorial_pygmo_optimization_label + :link-type: ref + + .. image:: /_static/images/tutorials/pygmo_optimization/pygmo_optimization.svg + + .. grid-item-card:: Gas Turbine with Heat Recovery Steam Generator + :link: TODO + :link-type: ref + + Coming soon! -- CGAM! -- Larger dh system .. toctree:: :maxdepth: 1 From 0afd6200bab3b0eabab281fc1884208105f4886e Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 7 Sep 2022 09:14:01 +0200 Subject: [PATCH 095/120] Add darkmode figures --- .../heat_pump_exergy/diagram_E_D.svg | 2852 +++++++-------- .../heat_pump_exergy/diagram_E_D_darkmode.svg | 2195 +++++++++++ .../diagram_cop_eps_Tgeo_Q.svg | 2902 ++++++++------- .../diagram_cop_eps_Tgeo_Q_darkmode.svg | 1926 ++++++++++ .../diagram_cop_eps_Tgeo_Ths.svg | 3224 +++++++++-------- .../diagram_cop_eps_Tgeo_Ths_darkmode.svg | 2151 +++++++++++ .../diagram_eps_Tamb_Tgeo.svg | 2909 +++++++-------- .../diagram_eps_Tamb_Tgeo_darkmode.svg | 1851 ++++++++++ docs/tutorials/heat_pump_exergy.rst | 33 + 9 files changed, 14281 insertions(+), 5762 deletions(-) create mode 100644 docs/_static/images/tutorials/heat_pump_exergy/diagram_E_D_darkmode.svg create mode 100644 docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q_darkmode.svg create mode 100644 docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths_darkmode.svg create mode 100644 docs/_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo_darkmode.svg diff --git a/docs/_static/images/tutorials/heat_pump_exergy/diagram_E_D.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_E_D.svg index 377ff6679..b3963ca96 100644 --- a/docs/_static/images/tutorials/heat_pump_exergy/diagram_E_D.svg +++ b/docs/_static/images/tutorials/heat_pump_exergy/diagram_E_D.svg @@ -1,569 +1,580 @@ - - + - + - 2021-08-23T12:31:42.026353 + 2022-09-07T09:09:50.566835 image/svg+xml - Matplotlib v3.3.4, https://matplotlib.org/ + Matplotlib v3.5.3, https://matplotlib.org/ - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #3a9dce"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #f08e2b"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #f08e2b"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #f08e2b"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #f08e2b"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #db5252"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #6ed880"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #6ed880"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #6ed880"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #6ed880"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #6ed880"/> - +" clip-path="url(#p9aec09bc3e)" style="fill: #6ed880"/> - +" style="stroke: #000000; stroke-width: 0.8"/> - + - + - + - + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - - + + + + - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + @@ -571,690 +582,700 @@ z - +" style="stroke: #000000; stroke-width: 0.8"/> - + - + - - + + - - - + + + - + - + - - - - + + + + - - - - - - - - - + + + + + + + + + - + - + - - - + + + - - - - - + + + + + - + - + - - + + - - - - - - - - - - + + + + + + + + + + - + - + - + - - - - - - - - - - + + + + + + + + + + - + - + - + - - - + + + - + - + - + - + - + - - - + + + - - - + + + - +" style="fill: #ffffff"/> - +" clip-path="url(#p39d1779824)" style="fill: #3a9dce"/> - +" clip-path="url(#p39d1779824)" style="fill: #f08e2b"/> - +" clip-path="url(#p39d1779824)" style="fill: #f08e2b"/> - +" clip-path="url(#p39d1779824)" style="fill: #f08e2b"/> - +" clip-path="url(#p39d1779824)" style="fill: #f08e2b"/> - +" clip-path="url(#p39d1779824)" style="fill: #db5252"/> - +" clip-path="url(#p39d1779824)" style="fill: #6ed880"/> - +" clip-path="url(#p39d1779824)" style="fill: #6ed880"/> - +" clip-path="url(#p39d1779824)" style="fill: #6ed880"/> - +" clip-path="url(#p39d1779824)" style="fill: #6ed880"/> - +" clip-path="url(#p39d1779824)" style="fill: #6ed880"/> - +" clip-path="url(#p39d1779824)" style="fill: #6ed880"/> - + - - + + - + - - - - + + + + - + - - - - + + + + - + - - - - + + + + - + - - - - + + + + - + - - - - - + + + + + - - - - - - - - - - - - + + + + + + + + + + + + @@ -1262,362 +1283,366 @@ z - + - + - + - + - + - + - + - + - + - + - + - - + + - - - - - + + + + + - +" style="fill: #ffffff"/> - +" clip-path="url(#pf4004c995f)" style="fill: #3a9dce"/> - +" clip-path="url(#pf4004c995f)" style="fill: #f08e2b"/> - +" clip-path="url(#pf4004c995f)" style="fill: #f08e2b"/> - +" clip-path="url(#pf4004c995f)" style="fill: #f08e2b"/> - +" clip-path="url(#pf4004c995f)" style="fill: #f08e2b"/> - +" clip-path="url(#pf4004c995f)" style="fill: #db5252"/> - +" clip-path="url(#pf4004c995f)" style="fill: #6ed880"/> - +" clip-path="url(#pf4004c995f)" style="fill: #6ed880"/> - +" clip-path="url(#pf4004c995f)" style="fill: #6ed880"/> - +" clip-path="url(#pf4004c995f)" style="fill: #6ed880"/> - +" clip-path="url(#pf4004c995f)" style="fill: #6ed880"/> - +" clip-path="url(#pf4004c995f)" style="fill: #6ed880"/> - + - + - +" transform="scale(0.015625)"/> - - - + + + - + - - - - + + + + - + - - - - + + + + - + - - - - + + + + - + - - - - + + + + - + - - - - + + + + - + - + - + @@ -1625,337 +1650,337 @@ z - + - - - - + + + + - + - - - - - - - - - - + + + + + + + + + + - + - - - - - - + + + + + + - + - - - - - - - - - - - + + + + + + + + + + + - + - - - - - - - - - - - + + + + + + + + + + + - + - - - - + + + + - + - + - + - + - +" style="fill: #ffffff"/> - +" clip-path="url(#p909af01851)" style="fill: #3a9dce"/> - +" clip-path="url(#p909af01851)" style="fill: #f08e2b"/> - +" clip-path="url(#p909af01851)" style="fill: #f08e2b"/> - +" clip-path="url(#p909af01851)" style="fill: #f08e2b"/> - +" clip-path="url(#p909af01851)" style="fill: #f08e2b"/> - +" clip-path="url(#p909af01851)" style="fill: #db5252"/> - +" clip-path="url(#p909af01851)" style="fill: #6ed880"/> - +" clip-path="url(#p909af01851)" style="fill: #6ed880"/> - +" clip-path="url(#p909af01851)" style="fill: #6ed880"/> - +" clip-path="url(#p909af01851)" style="fill: #6ed880"/> - +" clip-path="url(#p909af01851)" style="fill: #6ed880"/> - +" clip-path="url(#p909af01851)" style="fill: #6ed880"/> - + - - - - + + + + - + - - - - + + + + - + - - - - + + + + - + - - - - + + + + - + - - - - + + + + - + - - - - + + + + - - + + @@ -1963,205 +1988,208 @@ z - + - + - + - + - + - + - + - + - + - + - + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - +" style="fill: #6ed880"/> - - - - + + + + - - + + - - + + - - + + - - + + diff --git a/docs/_static/images/tutorials/heat_pump_exergy/diagram_E_D_darkmode.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_E_D_darkmode.svg new file mode 100644 index 000000000..60de02a98 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_exergy/diagram_E_D_darkmode.svg @@ -0,0 +1,2195 @@ + + + + + + + + 2022-09-07T09:08:19.587231 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q.svg index 77e0a00e6..aef774b73 100644 --- a/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q.svg +++ b/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q.svg @@ -1,67 +1,66 @@ - - + - + - 2021-08-09T11:06:48.809804 + 2022-09-07T09:09:52.284731 image/svg+xml - Matplotlib v3.3.4, https://matplotlib.org/ + Matplotlib v3.5.3, https://matplotlib.org/ - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - +" style="stroke: #000000; stroke-width: 0.8"/> - + - + - + @@ -70,353 +69,359 @@ L 0 3.5 - +" style="stroke: #000000; stroke-width: 0.8"/> - + - + - - - + + + - - - - + + + + - + - + - + - - - - + + + + - + - - - - - + + + + + - + - - - - - + + + + + - + - + - + - +" style="stroke: #00395b"/> - - - - - - - + + + + + + + - +" style="stroke: #74adc1"/> - - - - - - - + + + + + + + - +" style="stroke: #b54036"/> - - - - - - - + + + + + + + - + - + - + - + - + - - - + + + - - - + + + - +" style="fill: #ffffff"/> - + - + - + @@ -425,442 +430,452 @@ z - + - + - + - + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - + - + - + - + - + - - - + + + - - - - - + + + + + - +" style="fill: #ffffff"/> - + - + - + - - - + + + - + - - - - + + + + - + - - - - + + + + - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + @@ -868,959 +883,1044 @@ z - + - - - + + + + + - + - - - + + + + + - + - - - + + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + - + - + - - - + + + - - - + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - + - + - + - + - +" style="fill: #ffffff"/> - + - + - + - - - - + + + + - + - + - + - - - - + + + + - + - + - + - - - - + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - - + + - + - - + + - + - - + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - + - + - + - + - + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + - + - + - + - - - - - + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + - + - + - + - + - - - - - - - - - - - - - + + + + + + + + + + + + + - - + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + diff --git a/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q_darkmode.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q_darkmode.svg new file mode 100644 index 000000000..3319876b3 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q_darkmode.svg @@ -0,0 +1,1926 @@ + + + + + + + + 2022-09-07T09:08:21.461847 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths.svg index 891e51078..465ff7e19 100644 --- a/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths.svg +++ b/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths.svg @@ -1,88 +1,87 @@ - - + - + - 2021-08-09T11:06:47.618579 + 2022-09-07T09:09:51.669444 image/svg+xml - Matplotlib v3.3.4, https://matplotlib.org/ + Matplotlib v3.5.3, https://matplotlib.org/ - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - +" style="stroke: #000000; stroke-width: 0.8"/> - + - + - + - + - + - + @@ -91,1855 +90,2062 @@ L 0 3.5 - +" style="stroke: #000000; stroke-width: 0.8"/> - + - - + + - - - - + + + + + - - - - + + + + + - + - - - - - - + + + + + + + - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + - + - + - + - + - +" style="stroke: #00395b"/> - - - - + + + + - + - +" style="stroke: #74adc1"/> - - - - + + + + - + - +" style="stroke: #b54036"/> - - - - + + + + - + - + - + - + - + - + - - - + + + - - - + + + - +" style="fill: #ffffff"/> - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - - + + - + - - + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - + - + - + - + - + - + - - - + + + - - - - - + + + + + - +" style="fill: #ffffff"/> - + - + - + - - - - - - + + + - + - + - + - - - + + + - + - + - + - + - + - - + + - + - + - + - + - + - - + + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - + + - + - - - - + + + + + + - - + + - + - - - - + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - + + + + + + - + - + - - + + - - - + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - + - + - + - + - +" style="fill: #ffffff"/> - + - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + + - + - - + + - + - - + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - + - + - + - + - + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + - + - + - + - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + diff --git a/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths_darkmode.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths_darkmode.svg new file mode 100644 index 000000000..92949bff8 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths_darkmode.svg @@ -0,0 +1,2151 @@ + + + + + + + + 2022-09-07T09:08:20.624387 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo.svg index dd4bd1594..f7026a097 100644 --- a/docs/_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo.svg +++ b/docs/_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo.svg @@ -1,577 +1,589 @@ - - + - + - 2021-08-09T11:06:46.095693 + 2022-09-07T09:09:51.038006 image/svg+xml - Matplotlib v3.3.4, https://matplotlib.org/ + Matplotlib v3.5.3, https://matplotlib.org/ - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - +" style="stroke: #000000; stroke-width: 0.8"/> - + - + - + - + - + - + - - + + - - + + - + - - - + + + - + - + - + - - + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -579,1244 +591,1261 @@ z - +" style="stroke: #000000; stroke-width: 0.8"/> - + - - - - - + + + + + - + - + - + - - - - + + + + - + - - - - - + + + + + - + - + - + - - - - + + + + - + - - - - - + + + + + - + - - - - - + + + + + - + - - - - - + + + + + - + - + - + - - - - + + + + - + - + - + - +" style="stroke: #00395b"/> - - - - - - - + + + + + + + - +" style="stroke: #ec6707"/> - - - - - - - + + + + + + + - + - + - + - + - + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + - - + - + - + - - + + - - - + + + - - + - + - + - - + + - - - - - + + + + + - +" style="fill: #ffffff"/> - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - - - + + + - + - + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - + - + - + - + - + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - + - + - - - - + + + + - - + - + - - - - - - + + + + + + - + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + diff --git a/docs/_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo_darkmode.svg b/docs/_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo_darkmode.svg new file mode 100644 index 000000000..247ff154e --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo_darkmode.svg @@ -0,0 +1,1851 @@ + + + + + + + + 2022-09-07T09:08:20.041805 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/tutorials/heat_pump_exergy.rst b/docs/tutorials/heat_pump_exergy.rst index e7731356f..81de492d8 100644 --- a/docs/tutorials/heat_pump_exergy.rst +++ b/docs/tutorials/heat_pump_exergy.rst @@ -456,6 +456,15 @@ is shown below. .. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_E_D.svg :align: center :alt: Comparison of exergy destruction and exergy efficiency + :figclass: only-light + + Figure: Comparison of exergy destruction and exergy efficiency of both + working fluids in design case. + +.. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_E_D_darkmode.svg + :align: center + :alt: Comparison of exergy destruction and exergy efficiency + :figclass: only-dark Figure: Comparison of exergy destruction and exergy efficiency of both working fluids in design case. @@ -552,6 +561,14 @@ documentation. .. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo.svg :align: center :alt: Varying Tamb and Tgeo of the GCHP + :figclass: only-light + + Figure: Varying ambient and geothermal temperature. + +.. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_eps_Tamb_Tgeo_darkmode.svg + :align: center + :alt: Varying Tamb and Tgeo of the GCHP + :figclass: only-dark Figure: Varying ambient and geothermal temperature. @@ -630,6 +647,14 @@ corresponding Python code can likewise be found in the plot script .. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths.svg :align: center :alt: Varying Tgeo and Ths of the GCHP + :figclass: only-light + + Figure: Varying geothermal and heating system temperature. + +.. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Ths_darkmode.svg + :align: center + :alt: Varying Tgeo and Ths of the GCHP + :figclass: only-dark Figure: Varying geothermal and heating system temperature. @@ -660,6 +685,14 @@ instead. .. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q.svg :align: center :alt: Varying Tgeo and Q of the GCHP + :figclass: only-light + + Figure: Varying geothermal temperature and heat load. + +.. figure:: /_static/images/tutorials/heat_pump_exergy/diagram_cop_eps_Tgeo_Q_darkmode.svg + :align: center + :alt: Varying Tgeo and Q of the GCHP + :figclass: only-dark Figure: Varying geothermal temperature and heat load. From 0fcc486943afdc61d448a4256b8877eafed11ecf Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 7 Sep 2022 09:15:12 +0200 Subject: [PATCH 096/120] Add more darkmode --- .../COP_by_wf_darkmode.svg | 1086 +++++ .../pygmo_optimization_darkmode.svg | 4102 +++++++++++++++++ docs/tutorials.rst | 13 +- docs/tutorials/pygmo_optimization.rst | 8 + docs/tutorials/starting_values.rst | 8 + tutorial/advanced/optimization_example.py | 2 +- tutorial/heat_pump_exergy/plots.py | 5 +- 7 files changed, 5221 insertions(+), 3 deletions(-) create mode 100644 docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf_darkmode.svg create mode 100644 docs/_static/images/tutorials/pygmo_optimization/pygmo_optimization_darkmode.svg diff --git a/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf_darkmode.svg b/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf_darkmode.svg new file mode 100644 index 000000000..ab52d3504 --- /dev/null +++ b/docs/_static/images/tutorials/heat_pump_starting_values/COP_by_wf_darkmode.svg @@ -0,0 +1,1086 @@ + + + + + + + + 2022-09-07T08:42:29.766262 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/tutorials/pygmo_optimization/pygmo_optimization_darkmode.svg b/docs/_static/images/tutorials/pygmo_optimization/pygmo_optimization_darkmode.svg new file mode 100644 index 000000000..024a65beb --- /dev/null +++ b/docs/_static/images/tutorials/pygmo_optimization/pygmo_optimization_darkmode.svg @@ -0,0 +1,4102 @@ + + + + + + + + 2022-09-07T08:57:41.884127 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 4244a35e5..93ced9b31 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -42,6 +42,10 @@ please reach out to us. We are looking forward to hearing from you! :link-type: ref .. image:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg + :class: only-light + + .. image:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf_darkmode.svg + :class: only-dark .. grid:: 2 :gutter: 1 @@ -51,6 +55,10 @@ please reach out to us. We are looking forward to hearing from you! :link-type: ref .. image:: /_static/images/tutorials/heat_pump_exergy/diagram_E_D.svg + :class: only-light + + .. image:: /_static/images/tutorials/heat_pump_exergy/diagram_E_D_darkmode.svg + :class: only-dark .. grid-item-card:: Building Complex District Heating Systems :link: TODO @@ -66,6 +74,10 @@ please reach out to us. We are looking forward to hearing from you! :link-type: ref .. image:: /_static/images/tutorials/pygmo_optimization/pygmo_optimization.svg + :class: only-light + + .. image:: /_static/images/tutorials/pygmo_optimization/pygmo_optimization_darkmode.svg + :class: only-dark .. grid-item-card:: Gas Turbine with Heat Recovery Steam Generator :link: TODO @@ -83,4 +95,3 @@ please reach out to us. We are looking forward to hearing from you! tutorials/starting_values.rst tutorials/heat_pump_exergy.rst tutorials/pygmo_optimization.rst - tutorials/combustion_chamber.rst diff --git a/docs/tutorials/pygmo_optimization.rst b/docs/tutorials/pygmo_optimization.rst index 0f2d45b2a..2a4bf3fc1 100644 --- a/docs/tutorials/pygmo_optimization.rst +++ b/docs/tutorials/pygmo_optimization.rst @@ -194,6 +194,14 @@ In our run, we got: .. figure:: /_static/images/tutorials/pygmo_optimization/pygmo_optimization.svg :align: center :alt: Scatter plot for all individuals during the optimization + :figclass: only-light + + Figure: Scatter plot for all individuals during the optimization + +.. figure:: /_static/images/tutorials/pygmo_optimization/pygmo_optimization_darkmode.svg + :align: center + :alt: Scatter plot for all individuals during the optimization + :figclass: only-dark Figure: Scatter plot for all individuals during the optimization diff --git a/docs/tutorials/starting_values.rst b/docs/tutorials/starting_values.rst index d61d23dc7..b3d8c22dd 100644 --- a/docs/tutorials/starting_values.rst +++ b/docs/tutorials/starting_values.rst @@ -198,5 +198,13 @@ We can run that function for different working fluids and plot the results: .. figure:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf.svg :align: center :alt: Analysis of the COP using different working fluids + :figclass: only-light + + Figure: Analysis of the COP using different working fluids + +.. figure:: /_static/images/tutorials/heat_pump_starting_values/COP_by_wf_darkmode.svg + :align: center + :alt: Analysis of the COP using different working fluids + :figclass: only-dark Figure: Analysis of the COP using different working fluids diff --git a/tutorial/advanced/optimization_example.py b/tutorial/advanced/optimization_example.py index 213fcb869..8b95b0adf 100644 --- a/tutorial/advanced/optimization_example.py +++ b/tutorial/advanced/optimization_example.py @@ -264,7 +264,7 @@ def get_objective(self, objective=None): # To access the results print(optimize.individuals) # check pygmo documentation to see, what you can get from the population -print(pop) +pop # plot the results import matplotlib.pyplot as plt diff --git a/tutorial/heat_pump_exergy/plots.py b/tutorial/heat_pump_exergy/plots.py index e2ac8d9d6..b380d0287 100644 --- a/tutorial/heat_pump_exergy/plots.py +++ b/tutorial/heat_pump_exergy/plots.py @@ -75,8 +75,8 @@ fig.suptitle('Component Exergy Destruction', fontsize=14) fig.legend(bbox_to_anchor=(0.08, 0, 0.9, .0), loc='center', ncol=3, borderaxespad=0.) -plt.show() fig.savefig('diagram_E_D.svg', bbox_inches='tight') +plt.close() # %% figure 2: epsilon depending on ambient Temperature Tamb @@ -118,6 +118,7 @@ fig.suptitle('Exergetic Efficency depending on Temperature', fontsize=14) fig.savefig('diagram_eps_Tamb_Tgeo.svg', bbox_inches='tight') +plt.close() # %% figure 3: epsilon and COP depending on mean geothermal temperature Tgeo @@ -166,6 +167,7 @@ 'COP and $\epsilon$ depending heating and geothermal mean temperature', fontsize=12) fig.savefig('diagram_cop_eps_Tgeo_Ths.svg', bbox_inches='tight') +plt.close() # %% figure 4: epsilon and COP depending on mean geothermal temperature Tgeo @@ -217,3 +219,4 @@ 'COP and $\epsilon$ depending on load and geothermal mean temperature', fontsize=12) fig.savefig('diagram_cop_eps_Tgeo_Q.svg', bbox_inches='tight') +plt.close() From d6f2864ea72157043a0792df5ffedb6083ab2e83 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 7 Sep 2022 09:15:39 +0200 Subject: [PATCH 097/120] Print some results --- tutorial/advanced/optimization_example.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tutorial/advanced/optimization_example.py b/tutorial/advanced/optimization_example.py index 8b95b0adf..9c5b12689 100644 --- a/tutorial/advanced/optimization_example.py +++ b/tutorial/advanced/optimization_example.py @@ -293,4 +293,5 @@ def get_objective(self, objective=None): plt.tight_layout() fig.savefig("pygmo_optimization.svg") +print(data.loc[data["efficiency"].values == data["efficiency"].min()]) # %%[sec_6] From 2dae95f60ed67b71621db8eed01b1c50d90d97ec Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 7 Sep 2022 09:24:31 +0200 Subject: [PATCH 098/120] Clean up a lot of residuals --- docs/tutorials/clausius_rankine.rst | 30 --- docs/tutorials/clausius_rankine_chp.rst | 29 --- docs/tutorials/combined_cycle_chp.rst | 16 -- docs/tutorials/combustion_chamber.rst | 254 ------------------------ docs/tutorials/combustion_engine.rst | 47 ----- docs/tutorials/district_heating.rst | 10 +- docs/tutorials/heat_pump.rst | 43 ---- docs/tutorials/solar_collector.rst | 44 ---- docs/whats_new/v0-2-0.rst | 2 +- docs/whats_new/v0-3-0.rst | 6 - 10 files changed, 7 insertions(+), 474 deletions(-) delete mode 100644 docs/tutorials/clausius_rankine.rst delete mode 100644 docs/tutorials/clausius_rankine_chp.rst delete mode 100644 docs/tutorials/combined_cycle_chp.rst delete mode 100644 docs/tutorials/combustion_chamber.rst delete mode 100644 docs/tutorials/combustion_engine.rst delete mode 100644 docs/tutorials/heat_pump.rst delete mode 100644 docs/tutorials/solar_collector.rst diff --git a/docs/tutorials/clausius_rankine.rst b/docs/tutorials/clausius_rankine.rst deleted file mode 100644 index 19ff81b9c..000000000 --- a/docs/tutorials/clausius_rankine.rst +++ /dev/null @@ -1,30 +0,0 @@ -Clausius rankine cycle ----------------------- - -This example provides a model for a basic clausius rankine cycle. -The process flow diagram is shown in the image below, the source code can be -found at the TESPy `examples repository -`__. - -.. figure:: /api/_images/basic.svg - :align: center - - Figure: Topology of the basic clausius rankine cycle. - -The basic clausius rankine cycle is built up of a steam turbine, a condenser, -the feed water pump and the steam generator. The ideal process' isentropic -efficiencies of the steam turbine and the pump are at a value of 100 %, and -pressure losses in the condenser and the steam generator are non-existent, -which would result in the thermal efficiency being equal to the Carnot -efficiency. For this example realistic figures have been chosen. -After the plant design an offdesign calculation with 90 % rated power is -performed. The inline-comments give you hints which and why offdesign -parameters have been chosen. - -For a good start you can try to modify or exchange parameters. E.g. adjust the -value of the upper terminal temperature difference at the condenser, or replace -this parameter with a pressure at the turbine's outlet. In order to get more -familiar with how TESPy works you could try to insert more components, maybe -add an extraction of the steam turbine for preheating the feed water. It is -strongly recommended to add new components bit per bit, troubleshooting is much -easier this way. diff --git a/docs/tutorials/clausius_rankine_chp.rst b/docs/tutorials/clausius_rankine_chp.rst deleted file mode 100644 index e7d54a842..000000000 --- a/docs/tutorials/clausius_rankine_chp.rst +++ /dev/null @@ -1,29 +0,0 @@ -CHP with backpressure turbine ------------------------------ - -We have set up a simple combined heat and power unit for this example. A -backpressure steam turbine is operated with steam extraction for preheating -purposes. -You will find the source code `here -`__. - -.. figure:: /api/_images/chp.svg - :align: center - - Figure: Topology of the chp unit. - -At first, a plant design is chosen: The unit provides a total power of 5 MW and -heating at a temperature of 110 °C for the feed flow. -After that, the temperature at feed flow and live steam mass flow are altered -(70 °C to 120 °C and 60 % to 105 % in respect to design mass flow) to cover the -unit's range of operation. Thus, the calculation mode is switched to offdesign -and the temperature and mass flow are altered in two embedded loops. -The latest calculated case of the same mass flow is selected for initialisation -in order to achieve better and faster convergence. -The results are saved to .csv-files and the following plot of backpressure -lines will be created. - -.. figure:: /api/_images/chp_PQ.svg - :align: center - - Figure: Backpressure lines of a CHP unit. diff --git a/docs/tutorials/combined_cycle_chp.rst b/docs/tutorials/combined_cycle_chp.rst deleted file mode 100644 index ca6c80a33..000000000 --- a/docs/tutorials/combined_cycle_chp.rst +++ /dev/null @@ -1,16 +0,0 @@ -Combined cycle with backpressure turbine ----------------------------------------- - -Another example for chp units, this one is a combined cycle power plant using a -backpressure steam turbine. Additionally to the heat extraction at the steam -turbine condenser, the district heating water extracts energy from the waste -heat of the waste heat steam generator. You will find the source code -`here `__. - -.. figure:: /api/_images/cc_bp.svg - :align: center - - Figure: Topology of the chp unit. - -The example file handles the plant's design as well as the offdesign -performance. diff --git a/docs/tutorials/combustion_chamber.rst b/docs/tutorials/combustion_chamber.rst deleted file mode 100644 index 4ae02f717..000000000 --- a/docs/tutorials/combustion_chamber.rst +++ /dev/null @@ -1,254 +0,0 @@ -.. _tespy_tutorial_waste_heat_steam_recovery_label: - -Combustion Chamber Tutorial ---------------------------- - -There are two different types of combustion chambers available: - -- :py:class:`tespy.components.combustion.base.CombustionChamber` and -- :py:class:`tespy.components.combustion.diabatic.DiabaticCombustionChamber`. - -Both can handle varying fluid compositions for the air and the fuel and -calculates the fluid composition of the flue gas. Thus, it is possible to e.g. -specify the oxygen mass fraction in the flue gas in a calculation. The -difference between the components lies in the fact, that the -:code:`CombustionChamber` does **not consider heat or pressure losses**, while -:code:`DiabaticCombustionChamber` does so. We provide a tutorial for both -components, where you learn how they work, and what the differences are. - -CombustionChamber -^^^^^^^^^^^^^^^^^ - -The combustion chamber is an important component within thermal power plants, -but unfortunately is the reason for many issues, as the solving algorithm is -very sensitive to small changes e.g. the fluid composition. We will -demonstrate how to handle the combustion chamber in a very small, simple -example. You can download the full code from the TESPy -`examples repository `__. - -First of all you need to define the network containing all fluid components -used for the combustion chamber. **These are at least the fuel, oxygen, -carbon-dioxide and water**. For this example we added Argon, and of course - as -we are using Air for the combustion - Nitrogen. - -.. code-block:: python - - from tespy.networks import Network - - # define full fluid list for the network's variable space - fluid_list = ['Ar', 'N2', 'O2', 'CO2', 'CH4', 'H2O'] - - # define unit systems - nw = Network(fluids=fluid_list, p_unit='bar', T_unit='C') - -As components there are two sources required, one for the fresh air, one for -the fuel, a sink for the flue gas and the combustion chamber. Connect the -components and add the connections to your network afterwards. - -.. code-block:: python - - from tespy.components import Sink, Source, CombustionChamber - - # sinks & sources - amb = Source('ambient') - sf = Source('fuel') - fg = Sink('flue gas outlet') - - # combustion chamber - comb = CombustionChamber(label='combustion chamber') - -.. code-block:: python - - from tespy.connections import Connection - - amb_comb = Connection(amb, 'out1', comb, 'in1') - sf_comb = Connection(sf, 'out1', comb, 'in2') - comb_fg = Connection(comb, 'out1', fg, 'in1') - - nw.add_conns(sf_comb, amb_comb, comb_fg) - -For the parametrisation we specify the combustion chamber's air to -stoichiometric air ratio lamb and the thermal input -(:math:`LHV \cdot \dot{m}_{f}`). - -.. code-block:: python - - # set combustion chamber air to stoichiometric air ratio and thermal input - comb.set_attr(lamb=3, ti=2e6) - -The ambient conditions as well as the fuel gas inlet temperature are defined in -the next step. The air and the fuel gas composition must fully be stated, the -component combustion chamber can not handle "Air" as input fluid! - -.. code-block:: python - - # air from ambient (ambient pressure and temperature), air composition must - # be stated component wise. - amb_comb.set_attr(p=1, T=20, fluid={'Ar': 0.0129, 'N2': 0.7553, 'H2O': 0, - 'CH4': 0, 'CO2': 0.0004, 'O2': 0.2314}) - - # fuel, pressure must not be stated, as pressure is the same at all inlets - # and outlets of the combustion chamber - sf_comb.set_attr(T=25, fluid={'CO2': 0.04, 'Ar': 0, 'N2': 0, 'O2': 0, - 'H2O': 0, 'CH4': 0.96}) - -Finally run the code: - -.. code-block:: python - - nw.solve('design') - nw.print_results() - -Of course, you can change the parametrisation in any desired way. For example -instead of stating the thermal input, you could choose any of the mass flows, -or instead of the air to stoichiometric air ratio you could specify the flue -gas temperature. It is also possible to make modifications on the fluid -composition, for example stating the oxygen content in the flue gas or to -change the fuel composition. Make sure, all desired fuels of your fuel mixture -are also within the fluid_list of the network. For the example below we added -hydrogen to the fuel mixture. - -.. code-block:: python - - from tespy.networks import Network - from tespy.components import Sink, Source, CombustionChamber - from tespy.connections import Connection - - # %% network - - fluid_list = ['Ar', 'N2', 'O2', 'CO2', 'CH4', 'H2O', 'H2'] - nw = Network(fluids=fluid_list, p_unit='bar', T_unit='C') - - # %% components - - # sinks & sources - amb = Source('ambient') - sf = Source('fuel') - fg = Sink('flue gas outlet') - - # combustion chamber - comb = CombustionChamber(label='combustion chamber') - - # %% connections - - amb_comb = Connection(amb, 'out1', comb, 'in1') - sf_comb = Connection(sf, 'out1', comb, 'in2') - comb_fg = Connection(comb, 'out1', fg, 'in1') - - nw.add_conns(sf_comb, amb_comb, comb_fg) - - # %% component parameters - - # set combustion chamber air to stoichometric air ratio and thermal input - comb.set_attr(lamb=3, ti=2e6) - - # %% connection parameters - - amb_comb.set_attr(p=1, T=20, fluid={'Ar': 0.0129, 'N2': 0.7553, 'H2O': 0, - 'CH4': 0, 'CO2': 0.0004, 'O2': 0.2314, - 'H2': 0}) - - sf_comb.set_attr(T=25, fluid={'CO2': 0, 'Ar': 0, 'N2': 0,'O2': 0, 'H2O': 0, - 'CH4': 0.95, 'H2': 0.05}) - - # %% solving - - nw.solve('design') - nw.print_results() - -DiabaticCombustionChamber -^^^^^^^^^^^^^^^^^^^^^^^^^ - -The example for the diabatic combustion chamber can as well be taken from the -TESPy -`examples repository `__. - -The setup of the network, connections and components is identical to the -first setup, therefore we skip over that part in this section. Note, that -instead of :code:`CombustionChamber` we are importing the component -:code:`DiabaticCombustionChamber`. Since heat losses and pressure losses are -considered in this component, we have to make additional assumptions to -simulate it. First, we will make run the simulation with inputs in a way, that -the outcome is identical to the behavior of the adiabatic version without -pressure losses as described above. - -As in the example above, we also specify thermal input and lambda, as well as -identical parameters for the connections. Furthermore, we specify the efficiency -:code:`eta` of the component, which determines the heat loss as ratio of the -thermal input. :code:`eta=1` means, no heat losses, thus adiabatic behavior. -On top of that, we set the pressure ratio :code:`pr`, which describes the -ratio of the pressure at the outlet to the pressure at **the inlet 1**. The -pressure value at the inlet 2 is detached from the other pressure values, it -must be a result of a different parameter specification. In this example, we -set it directly. To match the inputs of the first tutorial, we set -:code:`pr=1` and :code:`p=1` for connection :code:`sf_comb`. - -.. note:: - - A warning message is promted at the end of the simulation, if the pressure - of the inlet 2 is lower or equal to the pressure of inlet 1. - -.. code-block:: python - - from tespy.networks import Network - from tespy.components import Sink, Source, DiabaticCombustionChamber - from tespy.connections import Connection - - # %% network - - fluid_list = ['Ar', 'N2', 'O2', 'CO2', 'CH4', 'H2O', 'H2'] - nw = Network(fluids=fluid_list, p_unit='bar', T_unit='C') - - # %% components - - # sinks & sources - amb = Source('ambient') - sf = Source('fuel') - fg = Sink('flue gas outlet') - - # combustion chamber - comb = DiabaticCombustionChamber(label='combustion chamber') - - # %% connections - - amb_comb = Connection(amb, 'out1', comb, 'in1') - sf_comb = Connection(sf, 'out1', comb, 'in2') - comb_fg = Connection(comb, 'out1', fg, 'in1') - - nw.add_conns(sf_comb, amb_comb, comb_fg) - - # set combustion chamber air to stoichometric air ratio, thermal input - # and efficiency - comb.set_attr(lamb=3, ti=2e6, eta=1, pr=1) - - # %% connection parameters - - amb_comb.set_attr(p=1, T=20, fluid={'Ar': 0.0129, 'N2': 0.7553, 'H2O': 0, - 'CH4': 0, 'CO2': 0.0004, 'O2': 0.2314, - 'H2': 0}) - - sf_comb.set_attr(p=1, T=25, fluid={'CO2': 0, 'Ar': 0, 'N2': 0,'O2': 0, - 'H2O': 0, 'CH4': 0.95, 'H2': 0.05}) - - # %% solving - - nw.solve('design') - nw.print_results() - -Now, consider heat loss of the surface of the component. This is simply done by -specifying the value for :code:`eta`. We assume 4 % of thermal input as heat -loss and set that value accordingly. Furthermore, the pressure of the fuel is -set to 1.5 bar. The air inlet pressure will be the result of the specified -pressure ratio and the outlet pressure assuming 2 % pressure losses. All -other parameters stay untouched. - -.. code-block:: python - - comb.set_attr(eta=0.96, pr=0.98) - - amb_comb.set_attr(p=None) - sf_comb.set_attr(p=1.5) - comb_fg.set_attr(p=1.0) - - nw.solve('design') - nw.print_results() diff --git a/docs/tutorials/combustion_engine.rst b/docs/tutorials/combustion_engine.rst deleted file mode 100644 index 975ec94ad..000000000 --- a/docs/tutorials/combustion_engine.rst +++ /dev/null @@ -1,47 +0,0 @@ -Combustion engine ------------------ - -We have added a combustion engine in version 0.0.5 of TESPy. The combustion -engine is based on the combustion chamber, and additionally provides a power -as well as two heating outlets and heat losses can be taken into account, too. -Power output, heat production and heat losses are all linked to the thermal -input of the combustion engine by characteristic lines, which usually are -provided by the manufacturer. TESPy provides a set of predefined -characteristics (documented in the :ref:`tespy_data_label`). - -.. figure:: /api/_images/CombustionEngine.svg - :align: center - - Figure: Topology of the combustion engine. - -The characteristics take the power ratio (:math:`\frac{P}{P_{ref}}`) as -argument. For a design case simulation the power ratio is always assumed to be -equal to 1. For offdesign calculation TESPy will automatically take the rated -power from the design case and use it to determine the power ratio. Still it is -possible to specify the rated power manually, if you like. - -In contrast to other components, the combustion engine has several busses, -which are accessible by specifying the corresponding bus parameter: - -- TI (thermal input), -- Q (total heat output), -- Q1 and Q2 (heat output 1 and 2), -- QLOSS (heat losses) and -- P (power output). - -If you want to add a bus to the example from the TESPy examples repository, -your code could look like this: - -.. code-block:: python - - chp = CombustionEngine('chp') - - b = Bus('some label') - # for thermal input - b.add_comps({'comp': chp, 'param': 'TI'}) - # for power output - b.add_comps({'comp': chp, 'param': 'P'}) - -Enjoy fiddling around with the source code of the -`combustion engine `_ -in the examples repository! diff --git a/docs/tutorials/district_heating.rst b/docs/tutorials/district_heating.rst index 11ce3d54f..f241f4b24 100644 --- a/docs/tutorials/district_heating.rst +++ b/docs/tutorials/district_heating.rst @@ -1,3 +1,5 @@ +.. _tespy_tutorial_district_heating_label: + Distric heating system ---------------------- @@ -10,7 +12,7 @@ Although the structure of the system (see the Figure below) does not seem very complex, it has more than 120 components. But we can easily determine repeating structures for the consumers and this is, where the subsystems come in place. -.. figure:: /api/_images/dhs.svg +.. figure:: /_static/images/tutorials/district_heating_system/dhs.svg :align: center Figure: Topology of the heating system. @@ -22,17 +24,17 @@ closed) or is open to connect to another part of the grid (industrial area, see subsystem open). Additionally, each branch of the main grid is connected to the upstream part with the fork subsystem (Ki, see subsystem fork). -.. figure:: /api/_images/dhs_closed.svg +.. figure:: /_static/images/tutorials/district_heating_system/dhs_closed.svg :align: center Figure: Generic topology of the dead end subsystem. -.. figure:: /api/_images/dhs_open.svg +.. figure:: /_static/images/tutorials/district_heating_system/dhs_open.svg :align: center Figure: Generic topology of the open subsystem. -.. figure:: /api/_images/dhs_forks.svg +.. figure:: /_static/images/tutorials/district_heating_system/dhs_forks.svg :align: center Figure: Generic topology of the forks (variable number of branches). diff --git a/docs/tutorials/heat_pump.rst b/docs/tutorials/heat_pump.rst deleted file mode 100644 index bafe2f462..000000000 --- a/docs/tutorials/heat_pump.rst +++ /dev/null @@ -1,43 +0,0 @@ -COP of a heat pump ------------------- - -This example is based on the :ref:`heat pump tutorial -` and shows how to calculate the COP of a heat pump -at different ambient temperatures and different loads of the plant. -The idea is very similar to the :ref:`CHP example `, thus -you should have a look at the tutorial and the CHP example first. -Be aware, that there are slight changes regarding the topology of the system -from the tutorial to this example. -You will find the source code `in this repository -`_. - -.. figure:: /api/_images/heat_pump_example.svg - :align: center - - Figure: Topology of the heat pump unit. - -After the plant has been designed, the consumer's heat demand and the ambient -temperature are modified within defined ranges. -Generally, if you are performing offdesign calculation, keep in mind, that a -good initial guess/solution is the key to good convergence progress. This is -why, we initialise the calculation at a higher ambient temperature with the -results from the calculation of the same load and the nearest ambient -temperature possible (in this case always the calculation one step before). -This helps the algorithm to stabilize and find a solution. -If you skip out on a large range of temperature or power, you might run into -convergence issues. The figures below show the COP of the heat pump for two -different heat sources at different temperature levels and at different loads: -In the first figure water is used as heat source, in the second one air. -Obviously, the heat pump using air performs much worse. This is mainly to the -high power consumption of the fan, as for the same amount of heat to be -transferred, a much higher volume has to be moved. - -.. figure:: /api/_images/heat_pump_COP_water.svg - :align: center - - Figure: COP of the heat pump using water as heat source. - -.. figure:: /api/_images/heat_pump_COP_air.svg - :align: center - - Figure: COP of the heat pump using air as heat source. diff --git a/docs/tutorials/solar_collector.rst b/docs/tutorials/solar_collector.rst deleted file mode 100644 index dd9b873e5..000000000 --- a/docs/tutorials/solar_collector.rst +++ /dev/null @@ -1,44 +0,0 @@ -Solar collector ---------------- - -This example shows how you can use a solarthermal collector in TESPy. -The process flow diagram is shown in the image below, the source code can be -found at the TESPy `examples repository -`__. - -.. figure:: /api/_images/SolarCollector.svg - :align: center - - Figure: Topology of the solar collector. - -The solarthermal collector is used to transfer heat from the solar radiation to -the collector fluid. The TESPy component -:py:class:`tespy.components.heat_exchangers.solar_collector.SolarCollector` -inherits from the -:py:class:`tespy.components.heat_exchangers.simple.HeatExchangerSimple` -component. An energy balance is applied according to the -:py:meth:`tespy.components.heat_exchangers.solar_collector.SolarCollector.energy_group_func` -method, which takes the collector's - -- surface area :code:`A`, -- loss key figures :code:`lkf_lin` (linear) and :code:`lkf_quad` (quadratic), -- ambient temperature :code:`Tamb`, -- optical efficiency :code:`eta_opt` as well as -- incoming radiation :code:`E` (W/m^2) - -into account. - -In the script different ways of parametrisation are shown. In the last part a -collector is designed and the offdesign performance at different rates of -absorption and ambient temperatures is calculated subsequently. Assuming a -constant mass flow through the collector, the outlet temperature and the -pressure losses of the collector are calculated. - -For example, if you want to calculate the performance of the collector within -a specific period of time, you could have the absorbed energy and the ambient -temperature as input time series and iterate over said series. As the absorbed -energy of the collector is a function of the global radiation on the inclined -surface, datetime and location only (optical losses are not temperature -dependent), you could calculate the absorption in a preprocessing script. If -you are to create such a script, we would appreciate you sharing and adding it -to TESPy! diff --git a/docs/whats_new/v0-2-0.rst b/docs/whats_new/v0-2-0.rst index 09da95e25..ecc6bc7e4 100644 --- a/docs/whats_new/v0-2-0.rst +++ b/docs/whats_new/v0-2-0.rst @@ -68,7 +68,7 @@ Other changes - Implement pep8speaks (PEP8 checker) in GitHub repository (`PR #131 `_). - The subsystem architecture has been simplified. Your connections and components are saved to dictionaries to make accessing the individual properties much easier (`PR #126 `_). For a use - case of subsystems, have a look at the :ref:`district heating example `. + case of subsystems, have a look at the :ref:`district heating example `. - Change the specification of set value for :py:class:`dc_simple ` class from :code:`val_set` to :code:`is_set` (`PR #138 `_). - Move the default characteristic function plots to the :ref:`tespy_data_label` documentation diff --git a/docs/whats_new/v0-3-0.rst b/docs/whats_new/v0-3-0.rst index c727e76aa..2884c620e 100644 --- a/docs/whats_new/v0-3-0.rst +++ b/docs/whats_new/v0-3-0.rst @@ -211,12 +211,6 @@ which has been used until version 0.2.x in TESPy. "h_range": [150, 3000] } -Due to the addition of the CoolProp back end selection the -:py:class:`tespy.components.combustion.stoichiometric` API changed -as well. Please refer to the -:ref:`combustion chamber tutorial` for the -new implementation. - If you are having trouble applying these changes, you are welcome to open an issue on our `github repository `_. From 194ad30381a68201b68e2a239e6bcbacb6c28393 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 7 Sep 2022 09:35:23 +0200 Subject: [PATCH 099/120] More cards fixing, move subsystems to components --- docs/modules.rst | 7 +- docs/modules/components.rst | 188 ++++++++++++++++++++++++++++++++++++ docs/modules/subsystems.rst | 187 ----------------------------------- 3 files changed, 190 insertions(+), 192 deletions(-) delete mode 100644 docs/modules/subsystems.rst diff --git a/docs/modules.rst b/docs/modules.rst index a5f6d2f1d..bc45c4466 100644 --- a/docs/modules.rst +++ b/docs/modules.rst @@ -35,10 +35,10 @@ as the underlying functionalities of the software. :link: tespy_modules_components_label :link-type: ref - .. image:: /_static/images/modules/components.svg + .. image:: /_static/images/modules/subsystem_waste_heat_generator.svg :class: only-light - .. image:: /_static/images/modules/components_darkmode.svg + .. image:: /_static/images/modules/subsystem_waste_heat_generator_darkmode.svg :class: only-dark .. grid:: 2 @@ -72,7 +72,4 @@ as the underlying functionalities of the software. .. math:: - \dot{m}_2 = f\left(\frac{X}{X_0}\right)\\ - \dot{m}_2 = f\left(\frac{X}{X_0}\right)\\ - \dot{m}_2 = f\left(\frac{X}{X_0}\right)\\ \dot{m}_2 = f\left(\frac{X}{X_0}\right) diff --git a/docs/modules/components.rst b/docs/modules/components.rst index 8eb0656aa..385eaa959 100644 --- a/docs/modules/components.rst +++ b/docs/modules/components.rst @@ -698,3 +698,191 @@ methods needs the label as parameter. Need assistance? ^^^^^^^^^^^^^^^^ You are very welcome to submit an issue on our GitHub! + +.. _tespy_subsystems_label: + +Component Groups: Subystems +=========================== + +Subsystems are an easy way to add frequently used component groups such as a +drum with evaporator or a preheater with desuperheater to your system. In this +section you will learn how to create a subsystem and implement it in your work. +The subsystems are highly customizable and thus a very powerful tool, if you +require to use specific component groups frequently. We provide an example, of +how to create a simple subsystem and use it in a simulation. + +Custom subsystems +----------------- + +Create a :code:`.py` file in your working-directory. This file contains the +class definition of your subsystem and at minimum two methods: + +- :code:`create_comps`: Method to create the components of your subsystem and + save them in the :code:`Subsystem.comps` attribute (dictionary). +- :code:`create_conns`: Method to create the connections of your subsystem and + save them in the :code:`Subsystem.conns` attribute (dictionary). + +All other functionalities are inherited by the parent class of the +:py:class:`subsystem ` object. + +Example +------- + +Create the subsystem +^^^^^^^^^^^^^^^^^^^^ + +We create a subsystem for the usage of a waste heat steam generator. The +subsystem is built up of a superheater, an evaporator, a drum and an economizer +as seen in the figure below. + +.. figure:: /_static/images/modules/subsystem_waste_heat_generator.svg + :align: center + :alt: Topology of the waste heat steam generator + :figclass: only-light + + Figure: Topology of the waste heat steam generator + +.. figure:: /_static/images/modules/subsystem_waste_heat_generator_darkmode.svg + :align: center + :alt: Topology of the waste heat steam generator + :figclass: only-dark + + Figure: Topology of the waste heat steam generator + +Create a file, e.g. :code:`mysubsystems.py` and add the following lines: + +- Imports of the necessary classes from tespy. +- Class definition of the subsystem (inheriting from subsystem class). +- Methods for component and connection creation. Both, components and + connections, are stored in a dictionary for easy access by their respective + label. + +.. code-block:: python + + from tespy.components import Subsystem, HeatExchanger, Drum + from tespy.connections import Connection + + + class WasteHeatSteamGenerator(Subsystem): + """Class documentation""" + + def create_comps(self): + """Create the subsystem's components.""" + self.comps['eco'] = HeatExchanger('economizer') + self.comps['eva'] = HeatExchanger('evaporator') + self.comps['sup'] = HeatExchanger('superheater') + self.comps['drum'] = Drum('drum') + + def create_conns(self): + """Define the subsystem's connections.""" + self.conns['eco_dr'] = Connection( + self.comps['eco'], 'out2', self.comps['drum'], 'in1') + self.conns['dr_eva'] = Connection( + self.comps['drum'], 'out1', self.comps['eva'], 'in2') + self.conns['eva_dr'] = Connection( + self.comps['eva'], 'out2', self.comps['drum'], 'in2') + self.conns['dr_sup'] = Connection( + self.comps['drum'], 'out2', self.comps['sup'], 'in2') + self.conns['sup_eva'] = Connection( + self.comps['sup'], 'out1', self.comps['eva'], 'in1') + self.conns['eva_eco'] = Connection( + self.comps['eva'], 'out1', self.comps['eco'], 'in1') + +Import your subsystem +^^^^^^^^^^^^^^^^^^^^^ + +In a different script, we create a network and import the subsystem we just +created along with the different tespy classes required. The location of the +:code:`mysubsystems.py` file must be known by your python installation or lie +within the same folder as your script. + +.. code-block:: python + + from tespy.networks import Network + from tespy.components import Source, Sink + from tespy.connections import Connection + import numpy as np + + from mysubsystems import WasteHeatSteamGenerator as WHSG + + # %% network definition + + fluid_list = ['air', 'water'] + nw = Network(fluid_list, p_unit='bar', T_unit='C') + + # %% component definition + + feed_water = Source('feed water inlet') + steam = Sink('live steam outlet') + + waste_heat = Source('waste heat inlet') + chimney = Sink('waste heat chimney') + + sg = WHSG('waste heat steam generator') + + # %% connection definition + + fw_sg = Connection(feed_water, 'out1', sg.comps['eco'], 'in2') + sg_ls = Connection(sg.comps['sup'], 'out2', steam, 'in1') + fg_sg = Connection(waste_heat, 'out1', sg.comps['sup'], 'in1') + sg_ch = Connection(sg.comps['eco'], 'out1', chimney, 'in1') + + nw.add_conns(fw_sg, sg_ls, fg_sg, sg_ch) + nw.add_subsys(sg) + + # %% connection parameters + + fw_sg.set_attr(fluid={'air': 0, 'water': 1}, T=25) + fg_sg.set_attr(fluid={'air': 1, 'water': 0}, T=650, m=100) + + sg_ls.set_attr(p=130) + sg_ch.set_attr(p=1) + + sg.conns['eva_dr'].set_attr(x=0.6) + + # %% component parameters + + sg.comps['eco'].set_attr(pr1=0.999, pr2=0.97, + design=['pr1', 'pr2', 'ttd_u'], + offdesign=['zeta1', 'zeta2', 'kA_char']) + + sg.comps['eva'].set_attr(pr1=0.999, ttd_l=20, design=['pr1', 'ttd_l'], + offdesign=['zeta1', 'kA_char']) + + sg.comps['sup'].set_attr(pr1=0.999, pr2=0.99, ttd_u=50, + design=['pr1', 'pr2', 'ttd_u'], + offdesign=['zeta1', 'zeta2', 'kA_char']) + + sg.conns['eco_dr'].set_attr(Td_bp=-5, design=['Td_bp']) + + # %% solve + + # solve design case + nw.solve('design') + nw.print_results() + nw.save('tmp') + + # offdesign test + nw.solve('offdesign', design_path='tmp') + + +Add more flexibility +-------------------- + +If you want to add even more flexibility, you might need to manipulate the +:code:`__init__` method of your custom subsystem class. Usually, you do not +need to override this method. However, if you need additional parameters, e.g. +in order to alter the subsystem's topology or specify additional information, +take a look at the :py:class:`tespy.components.subsystem.Subsystem` class and +add your code between the label declaration and the components and connection +creation in the :code:`__init__` method. + +For example, if you want a variable number of inlets and outlets because you +have a variable number of components groups within your subsystem, you may +introduce an attribute which is set on initialisation and lets you create and +parameterize components and connections generically. This might be very +interesting for district heating systems, turbines with several sections of +equal topology, etc.. For a good start, you can have a look at the +:code:`sub_consumer.py` of the district heating network in the +`oemof_examples `_ +repository. diff --git a/docs/modules/subsystems.rst b/docs/modules/subsystems.rst deleted file mode 100644 index 336625ec1..000000000 --- a/docs/modules/subsystems.rst +++ /dev/null @@ -1,187 +0,0 @@ -.. _tespy_subsystems_label: - -Subsystems and component groups -=============================== - -Subsystems are an easy way to add frequently used component groups such as a -drum with evaporator or a preheater with desuperheater to your system. In this -section you will learn how to create a subsystem and implement it in your work. -The subsystems are highly customizable and thus a very powerful tool, if you -require to use specific component groups frequently. We provide an example, of -how to create a simple subsystem and use it in a simulation. - -Custom subsystems ------------------ - -Create a :code:`.py` file in your working-directory. This file contains the -class definition of your subsystem and at minimum two methods: - -- :code:`create_comps`: Method to create the components of your subsystem and - save them in the :code:`Subsystem.comps` attribute (dictionary). -- :code:`create_conns`: Method to create the connections of your subsystem and - save them in the :code:`Subsystem.conns` attribute (dictionary). - -All other functionalities are inherited by the parent class of the -:py:class:`subsystem ` object. - -Example -------- - -Create the subsystem -^^^^^^^^^^^^^^^^^^^^ - -We create a subsystem for the usage of a waste heat steam generator. The -subsystem is built up of a superheater, an evaporator, a drum and an economizer -as seen in the figure below. - -.. figure:: /_static/images/modules/subsystem_waste_heat_generator.svg - :align: center - :alt: Topology of the waste heat steam generator - :figclass: only-light - - Figure: Topology of the waste heat steam generator - -.. figure:: /_static/images/modules/subsystem_waste_heat_generator_darkmode.svg - :align: center - :alt: Topology of the waste heat steam generator - :figclass: only-dark - - Figure: Topology of the waste heat steam generator - -Create a file, e.g. :code:`mysubsystems.py` and add the following lines: - -- Imports of the necessary classes from tespy. -- Class definition of the subsystem (inheriting from subsystem class). -- Methods for component and connection creation. Both, components and - connections, are stored in a dictionary for easy access by their respective - label. - -.. code-block:: python - - from tespy.components import Subsystem, HeatExchanger, Drum - from tespy.connections import Connection - - - class WasteHeatSteamGenerator(Subsystem): - """Class documentation""" - - def create_comps(self): - """Create the subsystem's components.""" - self.comps['eco'] = HeatExchanger('economizer') - self.comps['eva'] = HeatExchanger('evaporator') - self.comps['sup'] = HeatExchanger('superheater') - self.comps['drum'] = Drum('drum') - - def create_conns(self): - """Define the subsystem's connections.""" - self.conns['eco_dr'] = Connection( - self.comps['eco'], 'out2', self.comps['drum'], 'in1') - self.conns['dr_eva'] = Connection( - self.comps['drum'], 'out1', self.comps['eva'], 'in2') - self.conns['eva_dr'] = Connection( - self.comps['eva'], 'out2', self.comps['drum'], 'in2') - self.conns['dr_sup'] = Connection( - self.comps['drum'], 'out2', self.comps['sup'], 'in2') - self.conns['sup_eva'] = Connection( - self.comps['sup'], 'out1', self.comps['eva'], 'in1') - self.conns['eva_eco'] = Connection( - self.comps['eva'], 'out1', self.comps['eco'], 'in1') - -Import your subsystem -^^^^^^^^^^^^^^^^^^^^^ - -In a different script, we create a network and import the subsystem we just -created along with the different tespy classes required. The location of the -:code:`mysubsystems.py` file must be known by your python installation or lie -within the same folder as your script. - -.. code-block:: python - - from tespy.networks import Network - from tespy.components import Source, Sink - from tespy.connections import Connection - import numpy as np - - from mysubsystems import WasteHeatSteamGenerator as WHSG - - # %% network definition - - fluid_list = ['air', 'water'] - nw = Network(fluid_list, p_unit='bar', T_unit='C') - - # %% component definition - - feed_water = Source('feed water inlet') - steam = Sink('live steam outlet') - - waste_heat = Source('waste heat inlet') - chimney = Sink('waste heat chimney') - - sg = WHSG('waste heat steam generator') - - # %% connection definition - - fw_sg = Connection(feed_water, 'out1', sg.comps['eco'], 'in2') - sg_ls = Connection(sg.comps['sup'], 'out2', steam, 'in1') - fg_sg = Connection(waste_heat, 'out1', sg.comps['sup'], 'in1') - sg_ch = Connection(sg.comps['eco'], 'out1', chimney, 'in1') - - nw.add_conns(fw_sg, sg_ls, fg_sg, sg_ch) - nw.add_subsys(sg) - - # %% connection parameters - - fw_sg.set_attr(fluid={'air': 0, 'water': 1}, T=25) - fg_sg.set_attr(fluid={'air': 1, 'water': 0}, T=650, m=100) - - sg_ls.set_attr(p=130) - sg_ch.set_attr(p=1) - - sg.conns['eva_dr'].set_attr(x=0.6) - - # %% component parameters - - sg.comps['eco'].set_attr(pr1=0.999, pr2=0.97, - design=['pr1', 'pr2', 'ttd_u'], - offdesign=['zeta1', 'zeta2', 'kA_char']) - - sg.comps['eva'].set_attr(pr1=0.999, ttd_l=20, design=['pr1', 'ttd_l'], - offdesign=['zeta1', 'kA_char']) - - sg.comps['sup'].set_attr(pr1=0.999, pr2=0.99, ttd_u=50, - design=['pr1', 'pr2', 'ttd_u'], - offdesign=['zeta1', 'zeta2', 'kA_char']) - - sg.conns['eco_dr'].set_attr(Td_bp=-5, design=['Td_bp']) - - # %% solve - - # solve design case - nw.solve('design') - nw.print_results() - nw.save('tmp') - - # offdesign test - nw.solve('offdesign', design_path='tmp') - - -Add more flexibility --------------------- - -If you want to add even more flexibility, you might need to manipulate the -:code:`__init__` method of your custom subsystem class. Usually, you do not -need to override this method. However, if you need additional parameters, e.g. -in order to alter the subsystem's topology or specify additional information, -take a look at the :py:class:`tespy.components.subsystem.Subsystem` class and -add your code between the label declaration and the components and connection -creation in the :code:`__init__` method. - -For example, if you want a variable number of inlets and outlets because you -have a variable number of components groups within your subsystem, you may -introduce an attribute which is set on initialisation and lets you create and -parameterize components and connections generically. This might be very -interesting for district heating systems, turbines with several sections of -equal topology, etc.. For a good start, you can have a look at the -:code:`sub_consumer.py` of the district heating network in the -`oemof_examples `_ -repository. From d93790c050daecc5fabb1e3c359907ba400ea659 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Wed, 7 Sep 2022 09:38:33 +0200 Subject: [PATCH 100/120] Move fluid property diagram code --- docs/modules.rst | 1 - docs/modules/fluid_properties.rst | 95 ++++++++++++++++++++++++++++++ docs/modules/networks.rst | 96 ------------------------------- 3 files changed, 95 insertions(+), 97 deletions(-) diff --git a/docs/modules.rst b/docs/modules.rst index bc45c4466..73ad9d160 100644 --- a/docs/modules.rst +++ b/docs/modules.rst @@ -15,7 +15,6 @@ as the underlying functionalities of the software. modules/networks.rst modules/components.rst - modules/subsystems.rst modules/connections.rst modules/characteristics.rst modules/fluid_properties.rst diff --git a/docs/modules/fluid_properties.rst b/docs/modules/fluid_properties.rst index 038e12179..e0012e1c0 100644 --- a/docs/modules/fluid_properties.rst +++ b/docs/modules/fluid_properties.rst @@ -66,3 +66,98 @@ you try to use a mixture of two liquid or gaseous fluids and liquid fluids, e.g. water and methanol, the equations will still be applied, but obviously return wrong values. If you have ideas for the implementation of new kinds of mixtures we appreciate you contacting us. + +.. _FluProDia_label: + +Creating Fluid Property Diagrams +-------------------------------- + +.. figure:: /_static/images/modules/logph_diagram_states.svg + :align: center + :alt: logph diagram of NH3 with a simple heat pump cycle + + Figure: logph diagram of NH3 with a simple heat pump cycle + +.. figure:: /_static/images/modules/Ts_diagram_states.svg + :align: center + :alt: Ts diagram of NH3 with a simple heat pump cycle + + Figure: Ts diagram of NH3 with a simple heat pump cycle + +CoolProp has an inbuilt feature for creating fluid property diagrams. +Unfortunately, the handling is not very easy at the moment. We recommend using +fluprodia (Fluid Property Diagram) instead. You can create and customize +different types of diagrams for all pure and pseudo-pure fluids available in +CoolProp. In order to plot your process data into a diagram, you can use the +:code:`get_plotting_data` method of each component. The method returns a +dictionary, that can be passed as :code:`**kwargs` to the +:code:`calc_individual_isoline` method of a fluprodia +:code:`FluidPropertyDiagram` object. The fluprodia documentation provides +examples of how to plot a process into different diagrams, too. For more +information on fluprodia have a look at the +`online documentation `_. You can +install the package with pip. + +.. code-block:: bash + + pip install fluprodia + +.. note:: + + The plotting data a returned from the :code:`get_plotting_data` as a + nested dictionary. The first level key contains the connection id of the + state change (change state from incoming connection to outgoing + connection). The table below shows the state change and the respective id. + + .. list-table:: State change and respective ids of dictionary + :widths: 60 10 10 10 + :header-rows: 1 + + * - component + - state from + - state to + - id + * - components with one inlet and one outlet only + - :code:`in1` + - :code:`out1` + - :code:`1` + * - class HeatExchanger and subclasses + - :code:`in1` + - :code:`out1` + - :code:`1` + * - + - :code:`in2` + - :code:`out2` + - :code:`2` + * - class ORCEvaporator + - :code:`in1` + - :code:`out1` + - :code:`1` + * - + - :code:`in2` + - :code:`out2` + - :code:`2` + * - + - :code:`in3` + - :code:`out3` + - :code:`3` + * - class Merge + - :code:`in1` + - :code:`out1` + - :code:`1` + * - + - :code:`in2` + - :code:`out1` + - :code:`2` + * - + - ... + - ... + - ... + * - class Drum + - :code:`out1` + - :code:`out2` + - :code:`1` + + All other components do not return any information as either there is no + change in state or the state change is accompanied by a change in fluid + composition. diff --git a/docs/modules/networks.rst b/docs/modules/networks.rst index fd282fa72..e2e4f6edb 100644 --- a/docs/modules/networks.rst +++ b/docs/modules/networks.rst @@ -724,105 +724,9 @@ The index of the DataFrames is the connection's or component's label. results_for_specific_turbine = myplant.results['Turbine'].loc['turbine 1'] results_for_component_on_bus = myplant.results['power input'].loc['turbine 1'] - The full list of connection and component parameters can be obtained from the respective API documentation. -.. _FluProDia_label: - -Creating fluid property diagrams -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. figure:: /_static/images/modules/logph_diagram_states.svg - :align: center - :alt: logph diagram of NH3 with a simple heat pump cycle - - Figure: logph diagram of NH3 with a simple heat pump cycle - -.. figure:: /_static/images/modules/Ts_diagram_states.svg - :align: center - :alt: Ts diagram of NH3 with a simple heat pump cycle - - Figure: Ts diagram of NH3 with a simple heat pump cycle - -CoolProp has an inbuilt feature for creating fluid property diagrams. -Unfortunately, the handling is not very easy at the moment. We recommend using -fluprodia (Fluid Property Diagram) instead. You can create and customize -different types of diagrams for all pure and pseudo-pure fluids available in -CoolProp. In order to plot your process data into a diagram, you can use the -:code:`get_plotting_data` method of each component. The method returns a -dictionary, that can be passed as :code:`**kwargs` to the -:code:`calc_individual_isoline` method of a fluprodia -:code:`FluidPropertyDiagram` object. The fluprodia documentation provides -examples of how to plot a process into different diagrams, too. For more -information on fluprodia have a look at the -`online documentation `_. You can -install the package with pip. - -.. code-block:: bash - - pip install fluprodia - -.. note:: - - The plotting data a returned from the :code:`get_plotting_data` as a - nested dictionary. The first level key contains the connection id of the - state change (change state from incoming connection to outgoing - connection). The table below shows the state change and the respective id. - - .. list-table:: State change and respective ids of dictionary - :widths: 60 10 10 10 - :header-rows: 1 - - * - component - - state from - - state to - - id - * - components with one inlet and one outlet only - - :code:`in1` - - :code:`out1` - - :code:`1` - * - class HeatExchanger and subclasses - - :code:`in1` - - :code:`out1` - - :code:`1` - * - - - :code:`in2` - - :code:`out2` - - :code:`2` - * - class ORCEvaporator - - :code:`in1` - - :code:`out1` - - :code:`1` - * - - - :code:`in2` - - :code:`out2` - - :code:`2` - * - - - :code:`in3` - - :code:`out3` - - :code:`3` - * - class Merge - - :code:`in1` - - :code:`out1` - - :code:`1` - * - - - :code:`in2` - - :code:`out1` - - :code:`2` - * - - - ... - - ... - - ... - * - class Drum - - :code:`out1` - - :code:`out2` - - :code:`1` - - - All other components do not return any information as either there is no - change in state or the state change is accompanied by a change in fluid - composition. - Network reader ============== The network reader is a useful tool to import networks from a data structure From d9c8affd88e8c81c00bc28a1d9f31b4c2a1c43a7 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 23 Sep 2022 08:39:42 +0200 Subject: [PATCH 101/120] Add missing images for modules --- .../images/modules/characteristics.svg | 266 +++ .../modules/characteristics_darkmode.svg | 212 +++ docs/_static/images/modules/connections.svg | 258 +++ .../images/modules/connections_darkmode.svg | 258 +++ .../images/modules/fluid_properties.svg | 1229 +------------- .../modules/fluid_properties_darkmode.svg | 1044 ++++++++++++ docs/_static/images/modules/ude.svg | 1426 ++++++++++++++++ docs/_static/images/modules/ude_darkmode.svg | 1478 +++++++++++++++++ 8 files changed, 5011 insertions(+), 1160 deletions(-) create mode 100644 docs/_static/images/modules/characteristics.svg create mode 100644 docs/_static/images/modules/characteristics_darkmode.svg create mode 100644 docs/_static/images/modules/connections.svg create mode 100644 docs/_static/images/modules/connections_darkmode.svg create mode 100644 docs/_static/images/modules/fluid_properties_darkmode.svg create mode 100644 docs/_static/images/modules/ude.svg create mode 100644 docs/_static/images/modules/ude_darkmode.svg diff --git a/docs/_static/images/modules/characteristics.svg b/docs/_static/images/modules/characteristics.svg new file mode 100644 index 000000000..2d6c844f0 --- /dev/null +++ b/docs/_static/images/modules/characteristics.svg @@ -0,0 +1,266 @@ + + + + + + + + + + 2021-04-28T14:52:48.810737 + image/svg+xml + + + Matplotlib v3.3.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/modules/characteristics_darkmode.svg b/docs/_static/images/modules/characteristics_darkmode.svg new file mode 100644 index 000000000..ac35c4766 --- /dev/null +++ b/docs/_static/images/modules/characteristics_darkmode.svg @@ -0,0 +1,212 @@ + + + + + + + + + + 2021-04-28T14:52:48.810737 + image/svg+xml + + + Matplotlib v3.3.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/modules/connections.svg b/docs/_static/images/modules/connections.svg new file mode 100644 index 000000000..e3332db16 --- /dev/null +++ b/docs/_static/images/modules/connections.svg @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + 5.3 kg/s + 10.2 bar + 213.7 kJ/kg + + + 2.1 kg/s + 1.1 bar + 57.9 kJ/kg + + + diff --git a/docs/_static/images/modules/connections_darkmode.svg b/docs/_static/images/modules/connections_darkmode.svg new file mode 100644 index 000000000..eec924cd7 --- /dev/null +++ b/docs/_static/images/modules/connections_darkmode.svg @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + 5.3 kg/s + 10.2 bar + 213.7 kJ/kg + + + 2.1 kg/s + 1.1 bar + 57.9 kJ/kg + + + diff --git a/docs/_static/images/modules/fluid_properties.svg b/docs/_static/images/modules/fluid_properties.svg index a9a5d8f02..69541bda1 100644 --- a/docs/_static/images/modules/fluid_properties.svg +++ b/docs/_static/images/modules/fluid_properties.svg @@ -1,23 +1,23 @@ image/svg+xml0.002 -m -3 -kg -0.005 -m -3 -kg -0.01 -m -3 -kg -0.02 -m -3 -kg -0.05 -m -3 -kg -0.1 -m -3 -kg -0.2 -m -3 -kg -0.5 -m -3 -kg -1.0 -m -3 -kg - + + + + + + + + + + + + + +-25.0 °C + id="tspan1248">225.0 °C 0.0 °C + id="tspan1254">250.0 °C 25.0 °C + id="tspan1260">275.0 °C 50.0 °C -75.0 °C -100.0 °C -125.0 °C -150.0 °C -175.0 °C -200.0 °C -225.0 °C -250.0 °C -275.0 °C -325.0 °C -1000.0 -JkgK -1500.0 -JkgK -2000.0 -JkgK -2500.0 -JkgK -3000.0 -JkgK -3500.0 -JkgK -4000.0 -JkgK -4500.0 -JkgK -5000.0 -JkgK -5500.0 -JkgK -6000.0 -JkgK -6500.0 -JkgK -7000.0 -JkgK -7500.0 -JkgK -0.0 - -0.1 - -0.2 - -0.3 - -0.4 - -0.5 - -0.6 - -0.7 - -0.8 - -0.9 - -1.0 - + + + + + + + + + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 +2 +3 +4 +5 +6 + diff --git a/docs/_static/images/modules/ude.svg b/docs/_static/images/modules/ude.svg new file mode 100644 index 000000000..9b0fdf3fe --- /dev/null +++ b/docs/_static/images/modules/ude.svg @@ -0,0 +1,1426 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/modules/ude_darkmode.svg b/docs/_static/images/modules/ude_darkmode.svg new file mode 100644 index 000000000..d0aa67d39 --- /dev/null +++ b/docs/_static/images/modules/ude_darkmode.svg @@ -0,0 +1,1478 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b90442de36b1f150242de67b442a7ab342533b33 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 23 Sep 2022 08:40:05 +0200 Subject: [PATCH 102/120] Fix some typos and include new module imgaes --- docs/benchmarks.rst | 13 +++++++---- docs/modules.rst | 20 +++++++++++++--- docs/modules/connections.rst | 45 +++++++++++++++++++++--------------- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/docs/benchmarks.rst b/docs/benchmarks.rst index 228cabb1e..d73ec5a4a 100644 --- a/docs/benchmarks.rst +++ b/docs/benchmarks.rst @@ -23,9 +23,17 @@ Finally, in the extension of the exergy analysis to chemical exergy :cite:`Valero1994` modeled in TESPy with a full model using industry software and with the data provided from literature as well :cite:`Bejan1996`. +The code for the full models is accessible open source on GitHub: + +- `So called "Solar Energy Generating System" `__ +- `Supercritical CO2 power cycle `__ +- `Air refrigeration machine `__ +- `CGAM process `__ + + Unit testing ------------ -Appart from the full model validation, the software includes full unit testing. +On top of the full model validation, the software includes full unit testing. Here, single features of the software are tested by comparing the result the software provides with the result we would expect when manually modeling that feature. For example, we set up a turbine and check, whether the isentropic @@ -33,9 +41,6 @@ efficiency specification in the TESPy component matches the results that is expected doing the same process manually. This is done for all modules of the software. -Furthermore, the full models denoted in the model validation are included in -the testing pipeline as well. - Continuous Integration ---------------------- TESPy has a diff --git a/docs/modules.rst b/docs/modules.rst index 73ad9d160..bd96435e5 100644 --- a/docs/modules.rst +++ b/docs/modules.rst @@ -47,13 +47,21 @@ as the underlying functionalities of the software. :link: tespy_modules_connections_label :link-type: ref - TODO: IMAGE + .. image:: /_static/images/modules/connections.svg + :class: only-light + + .. image:: /_static/images/modules/connections_darkmode.svg + :class: only-dark .. grid-item-card:: Characteristics :link: tespy_modules_characteristics_label :link-type: ref .. image:: /_static/images/modules/characteristics.svg + :class: only-light + + .. image:: /_static/images/modules/characteristics_darkmode.svg + :class: only-dark .. grid:: 2 @@ -64,11 +72,17 @@ as the underlying functionalities of the software. :link-type: ref .. image:: /_static/images/modules/fluid_properties.svg + :class: only-light + + .. image:: /_static/images/modules/fluid_properties_darkmode.svg + :class: only-dark .. grid-item-card:: User Defined Equations :link: tespy_ude_label :link-type: ref - .. math:: + .. image:: /_static/images/modules/ude.svg + :class: only-light - \dot{m}_2 = f\left(\frac{X}{X_0}\right) + .. image:: /_static/images/modules/ude_darkmode.svg + :class: only-dark diff --git a/docs/modules/connections.rst b/docs/modules/connections.rst index da043de1d..ba619d716 100644 --- a/docs/modules/connections.rst +++ b/docs/modules/connections.rst @@ -12,14 +12,14 @@ Parametrisation As mentioned in the introduction, for each connection you can specify the following parameters: - * mass flow* (m), - * volumetric flow (v), - * pressure* (p), - * enthalpy* (h), - * temperature* (T), - * vapor mass fraction for pure fluids (x), - * a fluid vector (fluid) and - * a balance closer for the fluid vector (fluid_balance). +* mass flow* (m), +* volumetric flow (v), +* pressure* (p), +* enthalpy* (h), +* temperature* (T), +* vapor mass fraction for pure fluids (x), +* a fluid vector (fluid) and +* a balance closer for the fluid vector (fluid_balance). It is possible to specify values, starting values, references and data containers. The data containers for connections are dc_prop for fluid @@ -54,18 +54,24 @@ In order to create the connections we create the components to connect first. myconn.set_attr(m0=10, p0=15, h0=100) # do the same with a data container - myconn.set_attr(p=dc_prop(val=7, val_set=True), - x=dc_prop(val=0.5, val_set=True)) - myconn.set_attr(m=dc_prop(val0=10), p=dc_prop(val0=15), - h=dc_prop(val0=100)) + myconn.set_attr( + p=dc_prop(val=7, val_set=True), + x=dc_prop(val=0.5, val_set=True) + ) + myconn.set_attr( + m=dc_prop(val0=10), p=dc_prop(val0=15), h=dc_prop(val0=100) + ) # specify a referenced value: pressure of myconn is 1.2 times pressure at # myotherconn minus 5 (unit is the network's corresponding unit) myconn.set_attr(p=Ref(myotherconn, 1.2, -5)) # specify value and reference at the same time - myconn.set_attr(p=dc_prop(val=7, val_set=True, - ref=Ref(myotherconn, 1.2, -5), ref_set=True)) + myconn.set_attr( + p=dc_prop( + val=7, val_set=True, ref=Ref(myotherconn, 1.2, -5), ref_set=True + ) + ) # possibilities to unset values myconn.set_attr(p=np.nan) @@ -240,7 +246,7 @@ consumption. Create two turbines :code:`turbine1` and :code:`turbine2` which have the same power output. -.. code:: python +.. code-block:: python # the total power on this bus must be zero, too # we make sure the two turbines yield the same power output by adding the char @@ -253,7 +259,7 @@ Create a bus for post-processing purpose only. Include a characteristic line for a generator and add two turbines :code:`turbine_hp` and :code:`turbine_lp` to the bus. -.. code:: python +.. code-block:: python # bus for postprocessing, no power (or heat flow) specified but with variable # conversion efficiency @@ -264,14 +270,15 @@ to the bus. gen = CharLine(x=x, y=y) power.add_comps( {'comp': turbine_hp, 'char': gen1}, - {'comp': turbine_lp, 'char': gen2}) + {'comp': turbine_lp, 'char': gen2} + ) my_network.add_busses(power_bus) Create a bus for the electrical power output of a combustion engine :code:`comb_engine`. Use a generator for power conversion and specify the total power output. -.. code:: python +.. code-block:: python # bus for combustion engine power el_power_bus = Bus('combustion engine power', P=-10e6) @@ -282,7 +289,7 @@ Create a bus for the electrical power input of a pump :code:`pu` with the component power will be identical. Due to the different efficiency definitions the value of the bus power will differ in part load. -.. code:: python +.. code-block:: python import numpy as np from tespy.components import Pump, Sink, Source From 1adafc0a16db214616c70b237210445e3b8e505f Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 23 Sep 2022 14:32:03 +0200 Subject: [PATCH 103/120] Fixing some sphinx issues --- .../_static/images/advanced/exergy/sankey.png | Bin 69426 -> 0 bytes .../_static/images/advanced/exergy/sankey.svg | 949 ++++++++++++++++++ docs/advanced/exergy.rst | 2 +- docs/conf.py | 6 +- docs/modules/connections.rst | 3 +- docs/modules/networks.rst | 2 +- docs/regular_meeting.rst | 2 - docs/tutorials.rst | 4 - docs/tutorials/heat_pump_exergy.rst | 6 +- docs/whats_new/v0-4-3.rst | 2 +- 10 files changed, 959 insertions(+), 17 deletions(-) delete mode 100644 docs/_static/images/advanced/exergy/sankey.png create mode 100644 docs/_static/images/advanced/exergy/sankey.svg diff --git a/docs/_static/images/advanced/exergy/sankey.png b/docs/_static/images/advanced/exergy/sankey.png deleted file mode 100644 index 0b219dbd6c89a8eebca34ba8a834bf3e919e01ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69426 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

$cifUhPGg|?ho$4y5!I^=iomY%s_e-R5D|A-GY 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 z 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 diff --git a/docs/_static/images/advanced/exergy/sankey.svg b/docs/_static/images/advanced/exergy/sankey.svg new file mode 100644 index 000000000..c47a033b4 --- /dev/null +++ b/docs/_static/images/advanced/exergy/sankey.svg @@ -0,0 +1,949 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + E_F + + + + + + + SG + + + + + + + E_D + + + + + + + E_P + + + + + + + E_L + + + + + + + FWP + + + + + + + SF + + + + + + + HPT + + + + + + + RH + + + + + + + LPT + + + + + + + total output power + + + + + + + CW + + + + + + + LPP + + + + + + + HPP + + + + + diff --git a/docs/advanced/exergy.rst b/docs/advanced/exergy.rst index bdd5d53b3..4e0129f5d 100644 --- a/docs/advanced/exergy.rst +++ b/docs/advanced/exergy.rst @@ -395,7 +395,7 @@ diagram is then easily done: )) fig.show() -.. figure:: /_static/images/advanced/exergy/sankey.png +.. figure:: /_static/images/advanced/exergy/sankey.svg :align: center :alt: Sankey diagram of the Soler Energy Generating System (SEGS) diff --git a/docs/conf.py b/docs/conf.py index 8d62c12a4..555b8a741 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -99,9 +99,9 @@ html_css_files = [ 'css/custom.css', ] -html_additional_pages = { - "index": "index.html" -} +# html_additional_pages = { +# "index": "index.html" +# } html_sidebars = { '**': [ diff --git a/docs/modules/connections.rst b/docs/modules/connections.rst index ba619d716..ef9ceeb08 100644 --- a/docs/modules/connections.rst +++ b/docs/modules/connections.rst @@ -181,8 +181,7 @@ These data are also available in the network's results dictionary and contain - 'comp' for the component instance. - 'param' for the parameter (e.g. the combustion engine has various - parameters, have a look at the - :ref:`combustion engine example `) + parameters) - 'char' for the characteristic line - 'base' the base for efficiency definition - 'P_ref' for the reference value of the component diff --git a/docs/modules/networks.rst b/docs/modules/networks.rst index e2e4f6edb..0150c0c1c 100644 --- a/docs/modules/networks.rst +++ b/docs/modules/networks.rst @@ -505,7 +505,7 @@ the fluid_balance parameter adds only one equation to your system. If you are modeling a cycle, e.g. the clausius rankine cylce, you need to make a cut in the cycle using the cycle_closer or a sink and a source not to overdetermine the system. Have a look in the -:ref:`heat pump tutorial ` to understand why this is +:ref:`tutorial section ` to understand why this is important and how it can be implemented. If you have provided the correct number of parameters in your system and the diff --git a/docs/regular_meeting.rst b/docs/regular_meeting.rst index 084e5a035..e88785b81 100644 --- a/docs/regular_meeting.rst +++ b/docs/regular_meeting.rst @@ -26,5 +26,3 @@ In-person meetings ================== Currently, no in-person meetings are scheduled. We will update this section, as soon as a meeting is planned. - -TODO: INSERT SCREENSHOT OF MEETING HERE diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 93ced9b31..90d09667e 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -61,8 +61,6 @@ please reach out to us. We are looking forward to hearing from you! :class: only-dark .. grid-item-card:: Building Complex District Heating Systems - :link: TODO - :link-type: ref Coming soon! @@ -80,8 +78,6 @@ please reach out to us. We are looking forward to hearing from you! :class: only-dark .. grid-item-card:: Gas Turbine with Heat Recovery Steam Generator - :link: TODO - :link-type: ref Coming soon! diff --git a/docs/tutorials/heat_pump_exergy.rst b/docs/tutorials/heat_pump_exergy.rst index 81de492d8..c9038772b 100644 --- a/docs/tutorials/heat_pump_exergy.rst +++ b/docs/tutorials/heat_pump_exergy.rst @@ -25,9 +25,9 @@ plotted. GitHub. Since there is an existing tutorial for -:ref:`creating a heat pump `, this tutorial starts -with the explanations for setting up the exergy analysis. Note, however, that -the heat pump model differs slightly in structure from the model in the +:ref:`creating a heat pump `, this tutorial +starts with the explanations for setting up the exergy analysis. However note, +that the heat pump model differs slightly in structure from the model in the previous tutorial. All related Python scripts of the fully working GCHP-model are listed in the following: diff --git a/docs/whats_new/v0-4-3.rst b/docs/whats_new/v0-4-3.rst index bfb931088..84eda0a84 100644 --- a/docs/whats_new/v0-4-3.rst +++ b/docs/whats_new/v0-4-3.rst @@ -8,7 +8,7 @@ New Features exergy sankey diagrams. For example, the diagram of the solar thermal power plant presented in the thermodynamic analyses section - .. figure:: /api/_images/SEGS_sankey.png + .. figure:: /_static/images/advanced/exergy/sankey.svg :align: center :alt: Example of the sankey diagram From c19c501e2f60bffd5eca703b26048b431704569e Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 23 Sep 2022 14:35:27 +0200 Subject: [PATCH 104/120] Put custom landing page on hold --- docs/conf.py | 2 +- docs/{contents.rst => index.rst} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/{contents.rst => index.rst} (100%) diff --git a/docs/conf.py b/docs/conf.py index 555b8a741..b3643c520 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,7 +31,7 @@ ] # landing page -master_doc = 'contents' +# master_doc = 'contents' # names, years, etc project = 'TESPy' year = '2022' diff --git a/docs/contents.rst b/docs/index.rst similarity index 100% rename from docs/contents.rst rename to docs/index.rst From 903b3787ee5a4126bf17ae6a887e93e6963ef407 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 23 Sep 2022 14:47:16 +0200 Subject: [PATCH 105/120] Add missing darkmde figures --- docs/basics/district_heating.rst | 8 ++++++++ docs/basics/gas_turbine.rst | 27 +++++++++++++++++++++++++++ docs/basics/heat_pump.rst | 8 ++++++++ docs/basics/rankine_cycle.rst | 16 ++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/docs/basics/district_heating.rst b/docs/basics/district_heating.rst index 45152ca0a..7732f8f23 100644 --- a/docs/basics/district_heating.rst +++ b/docs/basics/district_heating.rst @@ -114,6 +114,14 @@ constant as well. .. figure:: /_static/images/basics/district_heating_partload.svg :align: center :alt: Performance of the district heating system at changing operating conditions + :figclass: only-light + + Figure: Performance of the district heating system at changing operating conditions. + +.. figure:: /_static/images/basics/district_heating_partload_darkmode.svg + :align: center + :alt: Performance of the district heating system at changing operating conditions + :figclass: only-dark Figure: Performance of the district heating system at changing operating conditions. diff --git a/docs/basics/gas_turbine.rst b/docs/basics/gas_turbine.rst index 77581f995..e271c6874 100644 --- a/docs/basics/gas_turbine.rst +++ b/docs/basics/gas_turbine.rst @@ -180,6 +180,15 @@ assume 2 % heat losses and 3 % pressure losses in the combustion chamber. .. figure:: /_static/images/basics/gas_turbine_parametric.svg :align: center :alt: Gas turbine performance at different compressor pressure ratios and turbine inlet temperatures + :figclass: only-light + + Figure: Gas turbine performance at different compressor pressure ratios + and turbine inlet temperatures + +.. figure:: /_static/images/basics/gas_turbine_parametric_darkmode.svg + :align: center + :alt: Gas turbine performance at different compressor pressure ratios and turbine inlet temperatures + :figclass: only-dark Figure: Gas turbine performance at different compressor pressure ratios and turbine inlet temperatures @@ -202,6 +211,15 @@ turbine inlet temperature correlates with the oxygen mass fraction. .. figure:: /_static/images/basics/gas_turbine_oxygen.svg :align: center :alt: Turbine inlet temperature at different levels of oxygen in the flue gas + :figclass: only-light + + Figure: Turbine inlet temperature at different levels of oxygen in the + flue gas + +.. figure:: /_static/images/basics/gas_turbine_oxygen_darkmode.svg + :align: center + :alt: Turbine inlet temperature at different levels of oxygen in the flue gas + :figclass: only-dark Figure: Turbine inlet temperature at different levels of oxygen in the flue gas @@ -233,6 +251,15 @@ hydrogen and methane. .. figure:: /_static/images/basics/gas_turbine_fuel_composition.svg :align: center :alt: Mass fractions of H2 and CH4 in fuel mixture at different thermal input + :figclass: only-light + + Figure: Mass fractions of H2 and CH4 in fuel mixture at varying thermal + input and constant fuel mass flow + +.. figure:: /_static/images/basics/gas_turbine_fuel_composition_darkmode.svg + :align: center + :alt: Mass fractions of H2 and CH4 in fuel mixture at different thermal input + :figclass: only-dark Figure: Mass fractions of H2 and CH4 in fuel mixture at varying thermal input and constant fuel mass flow diff --git a/docs/basics/heat_pump.rst b/docs/basics/heat_pump.rst index 794f12b7c..8be8a888a 100644 --- a/docs/basics/heat_pump.rst +++ b/docs/basics/heat_pump.rst @@ -155,6 +155,14 @@ plot using matplotlib. .. figure:: /_static/images/basics/heat_pump_parametric.svg :align: center :alt: Parametric analysis of the heat pump's COP + :figclass: only-light + + Figure: Parametric analysis of the heat pump's COP + +.. figure:: /_static/images/basics/heat_pump_parametric_darkmode.svg + :align: center + :alt: Parametric analysis of the heat pump's COP + :figclass: only-dark Figure: Parametric analysis of the heat pump's COP diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst index 6adbcdbb9..d412e6aa4 100644 --- a/docs/basics/rankine_cycle.rst +++ b/docs/basics/rankine_cycle.rst @@ -150,6 +150,14 @@ can disable the printout of the convergence history. .. figure:: /_static/images/basics/rankine_parametric.svg :align: center :alt: Parametric analysis of the efficiency and power output + :figclass: only-light + + Figure: Parametric analysis of the efficiency and power output + +.. figure:: /_static/images/basics/rankine_parametric_darkmode.svg + :align: center + :alt: Parametric analysis of the efficiency and power output + :figclass: only-dark Figure: Parametric analysis of the efficiency and power output @@ -232,5 +240,13 @@ Finally, we can alter the mass flow from its design value of 20 kg/s to only .. figure:: /_static/images/basics/rankine_partload.svg :align: center :alt: Partload electric efficiency of the rankine cycle + :figclass: only-light + + Figure: Partload electric efficiency of the rankine cycle + +.. figure:: /_static/images/basics/rankine_partload_darkmode.svg + :align: center + :alt: Partload electric efficiency of the rankine cycle + :figclass: only-dark Figure: Partload electric efficiency of the rankine cycle From 894691250af994b538a2c7282e04ac292f5d1ec9 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 23 Sep 2022 14:47:51 +0200 Subject: [PATCH 106/120] Add darkmode plots --- .../district_heating_partload_darkmode.svg | 2292 +++++++++++++++++ .../gas_turbine_fuel_composition_darkmode.svg | 1135 ++++++++ .../basics/gas_turbine_oxygen_darkmode.svg | 1100 ++++++++ .../gas_turbine_parametric_darkmode.svg | 1903 ++++++++++++++ .../basics/heat_pump_parametric_darkmode.svg | 1784 +++++++++++++ .../basics/rankine_parametric_darkmode.svg | 1997 ++++++++++++++ .../basics/rankine_partload_darkmode.svg | 1001 +++++++ 7 files changed, 11212 insertions(+) create mode 100644 docs/_static/images/basics/district_heating_partload_darkmode.svg create mode 100644 docs/_static/images/basics/gas_turbine_fuel_composition_darkmode.svg create mode 100644 docs/_static/images/basics/gas_turbine_oxygen_darkmode.svg create mode 100644 docs/_static/images/basics/gas_turbine_parametric_darkmode.svg create mode 100644 docs/_static/images/basics/heat_pump_parametric_darkmode.svg create mode 100644 docs/_static/images/basics/rankine_parametric_darkmode.svg create mode 100644 docs/_static/images/basics/rankine_partload_darkmode.svg diff --git a/docs/_static/images/basics/district_heating_partload_darkmode.svg b/docs/_static/images/basics/district_heating_partload_darkmode.svg new file mode 100644 index 000000000..41ed97c15 --- /dev/null +++ b/docs/_static/images/basics/district_heating_partload_darkmode.svg @@ -0,0 +1,2292 @@ + + + + + + + + 2022-09-23T14:39:34.855157 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/gas_turbine_fuel_composition_darkmode.svg b/docs/_static/images/basics/gas_turbine_fuel_composition_darkmode.svg new file mode 100644 index 000000000..3eed407fe --- /dev/null +++ b/docs/_static/images/basics/gas_turbine_fuel_composition_darkmode.svg @@ -0,0 +1,1135 @@ + + + + + + + + 2022-09-23T14:40:19.299228 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/gas_turbine_oxygen_darkmode.svg b/docs/_static/images/basics/gas_turbine_oxygen_darkmode.svg new file mode 100644 index 000000000..2a719b25a --- /dev/null +++ b/docs/_static/images/basics/gas_turbine_oxygen_darkmode.svg @@ -0,0 +1,1100 @@ + + + + + + + + 2022-09-23T14:40:09.282863 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/gas_turbine_parametric_darkmode.svg b/docs/_static/images/basics/gas_turbine_parametric_darkmode.svg new file mode 100644 index 000000000..5c42e5ddd --- /dev/null +++ b/docs/_static/images/basics/gas_turbine_parametric_darkmode.svg @@ -0,0 +1,1903 @@ + + + + + + + + 2022-09-23T14:40:06.522079 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/heat_pump_parametric_darkmode.svg b/docs/_static/images/basics/heat_pump_parametric_darkmode.svg new file mode 100644 index 000000000..7c41880c8 --- /dev/null +++ b/docs/_static/images/basics/heat_pump_parametric_darkmode.svg @@ -0,0 +1,1784 @@ + + + + + + + + 2022-09-23T14:40:50.524312 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/rankine_parametric_darkmode.svg b/docs/_static/images/basics/rankine_parametric_darkmode.svg new file mode 100644 index 000000000..6c88388d5 --- /dev/null +++ b/docs/_static/images/basics/rankine_parametric_darkmode.svg @@ -0,0 +1,1997 @@ + + + + + + + + 2022-09-23T14:40:35.129321 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/rankine_partload_darkmode.svg b/docs/_static/images/basics/rankine_partload_darkmode.svg new file mode 100644 index 000000000..55fe9df64 --- /dev/null +++ b/docs/_static/images/basics/rankine_partload_darkmode.svg @@ -0,0 +1,1001 @@ + + + + + + + + 2022-09-23T14:40:39.514183 + image/svg+xml + + + Matplotlib v3.5.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 970d0929306c2d2f0906dd49ee0e96c38df59ce9 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Fri, 23 Sep 2022 14:58:27 +0200 Subject: [PATCH 107/120] Add darkmode flowsheet for SEGS --- .../advanced/exergy/flowsheet_darkmode.svg | 3125 +++++++++++++++++ docs/advanced/exergy.rst | 6 + 2 files changed, 3131 insertions(+) create mode 100644 docs/_static/images/advanced/exergy/flowsheet_darkmode.svg diff --git a/docs/_static/images/advanced/exergy/flowsheet_darkmode.svg b/docs/_static/images/advanced/exergy/flowsheet_darkmode.svg new file mode 100644 index 000000000..cef608186 --- /dev/null +++ b/docs/_static/images/advanced/exergy/flowsheet_darkmode.svg @@ -0,0 +1,3125 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HP1 + HP2 + LP1 + LP2 + LP3 + LP4 + LP5 + G + SolarField + FWT + CON + CP + FWP + EV + RH + FP + + + SH + ECO + DR + PCC + PTCC + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 23 + 24 + 32 + 33 + 34 + 35 + 36 + 37 + 45 + 46 + 47 + 58 + 70 + 71 + 72 + 75 + 76 + 77 + 78 + 79 + + + 62 + 63 + 2 + + + + + + + + + 17 + 18 + 19 + 22 + 26 + 40 + 42 + 44 + 50 + 55 + + + + 61 + LPP1 + LPP2 + LPP3 + HPP1 + HPP2 + 1 + 3 + 4 + 5 + 1 + 7 + + 1 + + 2 + + 3 + + 4 + + 5 + + 6 + + 5 + CWP + + M + + + M + + + M + + + M + + + + 2 + + 3 + + + + 4 + + + + + + + + + 60 + + + + + + + 20 + 21 + 25 + 64 + 65 + CT + 38 + 41 + 48 + 51 + 52 + 53 + 59 + + + + + 66 + + + + Fan + + M + + + + 73 + 74 + CWCC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 27 + 28 + 29 + 30 + 31 + LPsub1 + LPsub2 + LPsub3 + HPsub1 + HPsub2 + 39 + 43 + 49 + 54 + 57 + 56 + + diff --git a/docs/advanced/exergy.rst b/docs/advanced/exergy.rst index 4e0129f5d..66506ff46 100644 --- a/docs/advanced/exergy.rst +++ b/docs/advanced/exergy.rst @@ -137,6 +137,12 @@ model. .. figure:: /_static/images/advanced/exergy/flowsheet.svg :align: center :alt: Topology of the Solar Energy Generating System (SEGS) + :figclass: only-light + +.. figure:: /_static/images/advanced/exergy/flowsheet_darkmode.svg + :align: center + :alt: Topology of the Solar Energy Generating System (SEGS) + :figclass: only-dark The input data are based on literature :cite:`Kearney1988`, which provides measured data. Some parameters are however taken from a follow-up publication, From 3abbd7951302a113d6145ac6ad03cba558ef6051 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 26 Sep 2022 18:05:32 +0200 Subject: [PATCH 108/120] Remove residuals and add example application --- .../examples/GRC_electrical_power_output.svg | 2580 +++++++++++++++++ .../GRC_electrical_power_output_darkmode.svg | 1135 ++++++++ docs/_static/images/heat_pump.svg | 611 ---- docs/_static/images/heat_pump_COP_air.svg | 1234 -------- docs/_static/images/heat_pump_COP_water.svg | 1226 -------- docs/_static/images/heat_pump_example.svg | 641 ---- docs/_static/images/intro_connections.svg | 326 --- .../images/intro_district_heating_scheme.svg | 286 -- .../images/power_plant_two_extractions.svg | 1372 --------- .../scatterplot_efficiency_optimization.svg | 1837 ------------ .../images/subsystem_waste_heat_generator.svg | 1057 ------- docs/_static/images/tutorial_heat_pump.svg | 589 ---- docs/examples.rst | 95 +- docs/index.rst | 1 - 14 files changed, 3739 insertions(+), 9251 deletions(-) create mode 100644 docs/_static/images/examples/GRC_electrical_power_output.svg create mode 100644 docs/_static/images/examples/GRC_electrical_power_output_darkmode.svg delete mode 100644 docs/_static/images/heat_pump.svg delete mode 100644 docs/_static/images/heat_pump_COP_air.svg delete mode 100644 docs/_static/images/heat_pump_COP_water.svg delete mode 100644 docs/_static/images/heat_pump_example.svg delete mode 100644 docs/_static/images/intro_connections.svg delete mode 100644 docs/_static/images/intro_district_heating_scheme.svg delete mode 100644 docs/_static/images/power_plant_two_extractions.svg delete mode 100644 docs/_static/images/scatterplot_efficiency_optimization.svg delete mode 100644 docs/_static/images/subsystem_waste_heat_generator.svg delete mode 100644 docs/_static/images/tutorial_heat_pump.svg diff --git a/docs/_static/images/examples/GRC_electrical_power_output.svg b/docs/_static/images/examples/GRC_electrical_power_output.svg new file mode 100644 index 000000000..4ce9b8ca0 --- /dev/null +++ b/docs/_static/images/examples/GRC_electrical_power_output.svg @@ -0,0 +1,2580 @@ + + + + + + + + 2022-09-26T17:55:01.972857 + image/svg+xml + + + Matplotlib v3.6.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/examples/GRC_electrical_power_output_darkmode.svg b/docs/_static/images/examples/GRC_electrical_power_output_darkmode.svg new file mode 100644 index 000000000..34c94d2ec --- /dev/null +++ b/docs/_static/images/examples/GRC_electrical_power_output_darkmode.svg @@ -0,0 +1,1135 @@ + + + + + + + + 2022-09-26T17:55:18.477115 + image/svg+xml + + + Matplotlib v3.6.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/heat_pump.svg b/docs/_static/images/heat_pump.svg deleted file mode 100644 index 2403df095..000000000 --- a/docs/_static/images/heat_pump.svg +++ /dev/null @@ -1,611 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - source intercool - sink intercool - consumerback flow - consumerfeed flow - sink ambient - source ambient - - - - - coolant in - coolant out - condenser - expansion valve - drum withevaporator - superheater - compressor train - - diff --git a/docs/_static/images/heat_pump_COP_air.svg b/docs/_static/images/heat_pump_COP_air.svg deleted file mode 100644 index 948571e5e..000000000 --- a/docs/_static/images/heat_pump_COP_air.svg +++ /dev/null @@ -1,1234 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_static/images/heat_pump_COP_water.svg b/docs/_static/images/heat_pump_COP_water.svg deleted file mode 100644 index b4ee344d7..000000000 --- a/docs/_static/images/heat_pump_COP_water.svg +++ /dev/null @@ -1,1226 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_static/images/heat_pump_example.svg b/docs/_static/images/heat_pump_example.svg deleted file mode 100644 index a7deb192a..000000000 --- a/docs/_static/images/heat_pump_example.svg +++ /dev/null @@ -1,641 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sink ambient - consumerback flow - consumerfeed flow - sink ambient - sourceambient - - - - - coolant in - coolant out - condenser - expansion valve - drum withevaporator - superheater - compressor train - - - - - - fan/pump - - - diff --git a/docs/_static/images/intro_connections.svg b/docs/_static/images/intro_connections.svg deleted file mode 100644 index 1a1437059..000000000 --- a/docs/_static/images/intro_connections.svg +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - waste steam - flue gas - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_static/images/intro_district_heating_scheme.svg b/docs/_static/images/intro_district_heating_scheme.svg deleted file mode 100644 index 868186429..000000000 --- a/docs/_static/images/intro_district_heating_scheme.svg +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - source - sink - - - pipe feed - pipe back - - - - - heat exchanger - - - central heating plant - consumer - - Q - - - valve - - - - - - diff --git a/docs/_static/images/power_plant_two_extractions.svg b/docs/_static/images/power_plant_two_extractions.svg deleted file mode 100644 index 7070448ee..000000000 --- a/docs/_static/images/power_plant_two_extractions.svg +++ /dev/null @@ -1,1372 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - G - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_static/images/scatterplot_efficiency_optimization.svg b/docs/_static/images/scatterplot_efficiency_optimization.svg deleted file mode 100644 index 7024547b7..000000000 --- a/docs/_static/images/scatterplot_efficiency_optimization.svg +++ /dev/null @@ -1,1837 +0,0 @@ - - - - - - - - - 2021-02-11T10:41:05.717444 - image/svg+xml - - - Matplotlib v3.3.3, https://matplotlib.org/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_static/images/subsystem_waste_heat_generator.svg b/docs/_static/images/subsystem_waste_heat_generator.svg deleted file mode 100644 index 12fd93f52..000000000 --- a/docs/_static/images/subsystem_waste_heat_generator.svg +++ /dev/null @@ -1,1057 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - superheater - evaporator - economizer - drum - - diff --git a/docs/_static/images/tutorial_heat_pump.svg b/docs/_static/images/tutorial_heat_pump.svg deleted file mode 100644 index 178fe9f1c..000000000 --- a/docs/_static/images/tutorial_heat_pump.svg +++ /dev/null @@ -1,589 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - source intercool - sink intercool - sink ambient - source ambient - - - - condenser - expansion valve - drum withevaporator - superheater - compressor train - coolant cycle closer(coolant in) - - consumer cycle closer - - - diff --git a/docs/examples.rst b/docs/examples.rst index 153e82a13..2fecda194 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -4,91 +4,44 @@ Example Applications ~~~~~~~~~~~~~~~~~~~~ -.. card:: Exergy Analysis of a Solarthermal Powerplant - :link: https://github.com/fwitte/SEGS_exergy +On this page we collect example applications of TESPy. If you want to add your +example here, please open an issue on GitHub and let us know. The source code +of the application should be accessible freely so other users can learn from +your project. - Header - ^^^ - - .. grid:: 1 2 - :outline: - - .. grid-item:: - - Some description - - .. grid-item:: - - .. image:: /_static/images/tutorials/heat_pump_steps/flowsheet.svg - :align: center - :alt: BLABLA - - +++ - Footer - -.. card:: Parametric Optimization of a Geothermal Organic Rankine Cycle - :link: https://github.com/fwitte/ORCSimulator +.. card:: + :link: https://github.com/fwitte/chp_orc - Header + **Combined Heat and Power Organic Rankine Cycle** ^^^ - .. grid:: 1 2 - :outline: + .. grid:: 2 .. grid-item:: - Some description + Starting from well production information for a geothermal energy + reservoir over a lifetime of 40 years, the development of the + electrical power output of an ORC is monitored within different + designs of the plant. The geothermal heat source is exploted to + provide heat to a district heating system and the residual heat is + used to operate the orc cycle. .. grid-item:: - .. image:: /_static/images/tutorials/heat_pump_steps/flowsheet.svg + .. image:: /_static/images/examples/GRC_electrical_power_output.svg :align: center - :alt: BLABLA - - +++ - Footer - -.. card:: District Heating Supply using an Organic Rankine Cycle - :link: https://github.com/fwitte/chp_orc - - Header - ^^^ + :alt: Development of the Electrical Power Output of the ORC for a District with 2 MW Peak Heat Load + :class: only-light - .. grid:: 1 2 - :outline: - - .. grid-item:: - - Some description - - .. grid-item:: - - .. image:: /_static/images/tutorials/heat_pump_steps/flowsheet.svg + .. image:: /_static/images/examples/GRC_electrical_power_output_darkmode.svg :align: center - :alt: BLABLA + :alt: Development of the Electrical Power Output of the ORC for a District with 2 MW Peak Heat Load + :class: only-dark +++ - Footer - - -.. card:: District Heating Supply using an Organic Rankine Cycle - :link: https://github.com/fwitte/sCO2_exergy - - Header - ^^^ - - .. grid:: 1 2 - :outline: + Title: Computational Modeling of Organic Rankine Cycle Combined Heat and + Power for Sedimentary Geothermal Exploitation - .. grid-item:: + Authors: Nicholas Fry, Jessica Eagle-Bluestone, Francesco Witte - Some description - - .. grid-item:: - - .. image:: /_static/images/tutorials/heat_pump_steps/flowsheet.svg - :align: center - :alt: BLABLA - - +++ - Footer + Reference: diff --git a/docs/index.rst b/docs/index.rst index 14d771fb5..3bd4a5b96 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -36,7 +36,6 @@ :hidden: advanced/exergy - advanced/optimization .. toctree:: :maxdepth: 2 From 4549693848bb484905d9aa4486a5c85e9fb3ee3d Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Thu, 29 Sep 2022 08:27:31 +0200 Subject: [PATCH 109/120] Fix styling issue --- src/tespy/tools/optimization.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index 88dbefd16..0c6014ae2 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -164,7 +164,6 @@ def collect_constraints(self, border, build=False): else: return evaluation - def fitness(self, x): """Evaluate the fitness function of an individual. From f576a990b76232e1eb81f997f7db4009cfd1753e Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 09:45:10 +0200 Subject: [PATCH 110/120] Add darkmode api images --- .../heat_pump_stepwise/flowsheet.svg | 37 +- .../heat_pump_stepwise/flowsheet_darkmode.svg | 37 +- .../heat_pump_stepwise/flowsheet_p1.svg | 37 +- .../flowsheet_p1_darkmode.svg | 51 +- .../heat_pump_stepwise/flowsheet_p2.svg | 14 +- .../flowsheet_p2_darkmode.svg | 32 +- docs/api/_images/CombustionChamber.svg | 298 +++-- .../_images/CombustionChamber_darkmode.svg | 222 ++++ docs/api/_images/CombustionEngine.svg | 479 +++++--- .../api/_images/CombustionEngine_darkmode.svg | 358 ++++++ docs/api/_images/Compressor.svg | 243 ++-- docs/api/_images/Compressor_darkmode.svg | 189 +++ docs/api/_images/Condenser.svg | 320 +++-- docs/api/_images/Condenser_darkmode.svg | 236 ++++ docs/api/_images/DropletSeparator.svg | 279 +++-- .../api/_images/DropletSeparator_darkmode.svg | 214 ++++ docs/api/_images/Drum.svg | 321 +++-- docs/api/_images/Drum_darkmode.svg | 241 ++++ docs/api/_images/FuelCell.svg | 549 ++++----- docs/api/_images/FuelCell_darkmode.svg | 315 +++++ docs/api/_images/HeatExchanger.svg | 319 +++-- docs/api/_images/HeatExchanger_darkmode.svg | 241 ++++ docs/api/_images/Merge.svg | 430 ++++--- docs/api/_images/Merge_darkmode.svg | 310 +++++ docs/api/_images/Node.svg | 293 ----- docs/api/_images/ParabolicTrough.svg | 1016 +++------------- docs/api/_images/ParabolicTrough_darkmode.svg | 195 +++ docs/api/_images/Pipe.svg | 215 ++-- docs/api/_images/Pipe_darkmode.svg | 175 +++ docs/api/_images/Pump.svg | 238 ++-- docs/api/_images/Pump_darkmode.svg | 182 +++ docs/api/_images/SolarCollector.svg | 1067 +++-------------- docs/api/_images/SolarCollector_darkmode.svg | 183 +++ docs/api/_images/Sp.svg | 309 +++++ docs/api/_images/Splitter.svg | 419 ++++--- docs/api/_images/Splitter_darkmode.svg | 309 +++++ docs/api/_images/SubsystemInterface.svg | 382 +++--- .../_images/SubsystemInterface_darkmode.svg | 290 +++++ docs/api/_images/Turbine.svg | 217 ++-- docs/api/_images/Turbine_darkmode.svg | 175 +++ docs/api/_images/Valve.svg | 220 ++-- docs/api/_images/Valve_darkmode.svg | 175 +++ docs/api/_images/WaterElectrolyzer.svg | 543 +++++---- .../_images/WaterElectrolyzer_darkmode.svg | 315 +++++ docs/api/_images/flowsheet.svg | 873 ++++++++++++++ docs/whats_new/v0-6-1.rst | 10 +- .../components/basics/subsystem_interface.py | 8 +- src/tespy/components/combustion/base.py | 10 +- src/tespy/components/combustion/diabatic.py | 12 +- src/tespy/components/combustion/engine.py | 10 +- src/tespy/components/heat_exchangers/base.py | 10 +- .../components/heat_exchangers/condenser.py | 10 +- .../heat_exchangers/desuperheater.py | 10 +- .../heat_exchangers/parabolic_trough.py | 10 +- .../components/heat_exchangers/simple.py | 10 +- .../heat_exchangers/solar_collector.py | 10 +- .../components/nodes/droplet_separator.py | 10 +- src/tespy/components/nodes/drum.py | 10 +- src/tespy/components/nodes/merge.py | 10 +- src/tespy/components/nodes/separator.py | 10 +- src/tespy/components/nodes/splitter.py | 10 +- src/tespy/components/piping/pipe.py | 10 +- src/tespy/components/piping/valve.py | 10 +- .../components/reactors/water_electrolyzer.py | 12 +- .../components/turbomachinery/compressor.py | 10 +- src/tespy/components/turbomachinery/pump.py | 10 +- .../components/turbomachinery/turbine.py | 10 +- 67 files changed, 9400 insertions(+), 4385 deletions(-) create mode 100644 docs/api/_images/CombustionChamber_darkmode.svg create mode 100644 docs/api/_images/CombustionEngine_darkmode.svg create mode 100644 docs/api/_images/Compressor_darkmode.svg create mode 100644 docs/api/_images/Condenser_darkmode.svg create mode 100644 docs/api/_images/DropletSeparator_darkmode.svg create mode 100644 docs/api/_images/Drum_darkmode.svg create mode 100644 docs/api/_images/FuelCell_darkmode.svg create mode 100644 docs/api/_images/HeatExchanger_darkmode.svg create mode 100644 docs/api/_images/Merge_darkmode.svg delete mode 100644 docs/api/_images/Node.svg create mode 100644 docs/api/_images/ParabolicTrough_darkmode.svg create mode 100644 docs/api/_images/Pipe_darkmode.svg create mode 100644 docs/api/_images/Pump_darkmode.svg create mode 100644 docs/api/_images/SolarCollector_darkmode.svg create mode 100644 docs/api/_images/Sp.svg create mode 100644 docs/api/_images/Splitter_darkmode.svg create mode 100644 docs/api/_images/SubsystemInterface_darkmode.svg create mode 100644 docs/api/_images/Turbine_darkmode.svg create mode 100644 docs/api/_images/Valve_darkmode.svg create mode 100644 docs/api/_images/WaterElectrolyzer_darkmode.svg create mode 100644 docs/api/_images/flowsheet.svg diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg index 271f54355..f4d6f2f2a 100644 --- a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet.svg @@ -67,9 +67,9 @@ inkscape:document-rotation="0" inkscape:current-layer="layer1" inkscape:document-units="mm" - inkscape:cy="593.26259" - inkscape:cx="674.57987" - inkscape:zoom="0.70710678" + inkscape:cy="450.78057" + inkscape:cx="432.74935" + inkscape:zoom="1.4142136" inkscape:pageshadow="2" inkscape:pageopacity="0.0" borderopacity="1.0" @@ -170,7 +170,7 @@ inkscape:connector-curvature="0" sodipodi:nodetypes="ccc" style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 119.5,92.5 v 32.50001 h 47.99998" + d="m 119.99997,92.5 v 32.50001 l 47.50001,0" id="path984-0-9-9-9-7-0-1-5-0-8-4" /> @@ -222,7 +221,7 @@ inkscape:connector-curvature="0" sodipodi:nodetypes="ccc" style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 182.49997,125.00001 h 42.00001 v -7.2646" + d="m 182.49997,125.00001 h 42.5 l 0,-7.2646" id="path984-0-9-9-9-7-6-9" /> @@ -614,7 +606,6 @@ @@ -222,7 +221,7 @@ inkscape:connector-curvature="0" sodipodi:nodetypes="ccc" style="fill:none;stroke:#ffffff;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 182.49997,125.00001 h 42.00001 v -7.2646" + d="m 182.49997,125.00001 h 42.5 v -7.2646" id="path984-0-9-9-9-7-6-9" /> @@ -614,7 +606,6 @@ @@ -222,7 +221,7 @@ inkscape:connector-curvature="0" sodipodi:nodetypes="ccc" style="fill:none;stroke:#c8c8c8;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 182.49997,125.00001 h 42.00001 v -7.2646" + d="m 182.49997,125.00001 h 42.5 v -7.2646" id="path984-0-9-9-9-7-6-9" /> @@ -614,7 +606,6 @@ @@ -222,7 +221,7 @@ inkscape:connector-curvature="0" sodipodi:nodetypes="ccc" style="fill:none;stroke:#323232;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 182.49997,125.00001 h 42.00001 v -7.2646" + d="m 182.49997,125.00001 h 42.5 v -7.2646" id="path984-0-9-9-9-7-6-9" /> 23 - @@ -614,7 +600,6 @@ + diff --git a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2.svg b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2.svg index 592049ea3..2fef054ee 100644 --- a/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2.svg +++ b/docs/_static/images/tutorials/heat_pump_stepwise/flowsheet_p2.svg @@ -67,9 +67,9 @@ inkscape:document-rotation="0" inkscape:current-layer="layer1" inkscape:document-units="mm" - inkscape:cy="423" - inkscape:cx="604" - inkscape:zoom="0.5" + inkscape:cy="620.13265" + inkscape:cx="463.86205" + inkscape:zoom="0.70710678" inkscape:pageshadow="2" inkscape:pageopacity="0.0" borderopacity="1.0" @@ -170,7 +170,7 @@ inkscape:connector-curvature="0" sodipodi:nodetypes="ccc" style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 119.5,92.5 v 32.50001 h 47.99998" + d="m 119.99997,92.5 v 32.50001 l 47.50001,0" id="path984-0-9-9-9-7-0-1-5-0-8-4" /> 23 - + diff --git a/docs/api/_images/CombustionChamber.svg b/docs/api/_images/CombustionChamber.svg index a63c5261a..83e9fc25e 100644 --- a/docs/api/_images/CombustionChamber.svg +++ b/docs/api/_images/CombustionChamber.svg @@ -1,144 +1,222 @@ + viewBox="0 0 94.999975 68.50001" + height="68.500008mm" + width="94.999969mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + + + + + + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false" + inkscape:lockguides="true"> + originx="-47.499986" + originy="-2.4999965" /> - + id="metadata5"> image/svg+xml - - + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-47.49996,-2.4999995)"> + + + + in2 + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="98.310982" + y="22.764622" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-6-3">in2 out1 + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="58.285896" + y="42.764622" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-6-3-3">in1 - in1 - + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 94.999959,11.999998 V 34.499996" + id="path984-0-9-9-9-7-6-60" /> + + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 56.999959,49.999998 H 79.999953" + id="path984-0-9-9-9-7-6-8" /> + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 52.999959,45.999998 4,4 -4,4 z" + id="path4652-12-9-60-5-4-2" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + out1 + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 109.99999,49.999998 h 22.99996" + id="path984-0-9-9-9-7-6-8-6" /> + sodipodi:nodetypes="cccc" /> diff --git a/docs/api/_images/CombustionChamber_darkmode.svg b/docs/api/_images/CombustionChamber_darkmode.svg new file mode 100644 index 000000000..1ff71f737 --- /dev/null +++ b/docs/api/_images/CombustionChamber_darkmode.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + in2 + in1 + + + + + out1 + + + + diff --git a/docs/api/_images/CombustionEngine.svg b/docs/api/_images/CombustionEngine.svg index 237edf947..519952211 100644 --- a/docs/api/_images/CombustionEngine.svg +++ b/docs/api/_images/CombustionEngine.svg @@ -1,235 +1,358 @@ + viewBox="0 0 93.499991 64.762918" + height="64.762917mm" + width="93.499985mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + + + + + + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false" + inkscape:lockguides="true"> + originx="-67.750004" + originy="-32.607178" /> - + id="metadata5"> image/svg+xml - + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-67.749985,-32.607182)"> in4 + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="96.642952" + y="91.382317" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5">in1 out3 + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="104.94641" + y="91.240036" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-5">out1 in3 - + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="116.65549" + y="91.382317" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-9">in2 + in3 + in4 + out2 + out3 + sodipodi:nodetypes="ccccc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 99.999984,84.000005 v -19 l 4.999996,5 5,-5 v 19" + id="path984-0-9-9-9-7-6-8-3" /> + sodipodi:nodetypes="ccccc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 119.99998,84.000005 v -19 l 5,5 5,-5 v 19" + id="path984-0-9-9-9-7-6-8-3-6" /> + + + + + + + + + + + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> - - - out2 - out1 - in2 - in1 - + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 89.999984,39.999993 V 75.000002 H 139.99998 V 39.999993 Z" + id="path1057-2-7-1-9" + sodipodi:nodetypes="ccccc" /> diff --git a/docs/api/_images/CombustionEngine_darkmode.svg b/docs/api/_images/CombustionEngine_darkmode.svg new file mode 100644 index 000000000..a8e1b2f0a --- /dev/null +++ b/docs/api/_images/CombustionEngine_darkmode.svg @@ -0,0 +1,358 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + in1 + out1 + in2 + in3 + in4 + out2 + out3 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/api/_images/Compressor.svg b/docs/api/_images/Compressor.svg index 106db365a..328c86ad2 100644 --- a/docs/api/_images/Compressor.svg +++ b/docs/api/_images/Compressor.svg @@ -1,100 +1,189 @@ + viewBox="0 0 104.99999 42.941693" + height="42.941692mm" + width="104.99998mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + + + + + - + inkscape:window-y="27" + inkscape:window-x="72" + inkscape:window-height="1136" + inkscape:window-width="1848" + inkscape:snap-to-guides="false" + inkscape:guide-bbox="true" + showguides="true" + inkscape:bbox-nodes="false" + inkscape:snap-grids="true" + inkscape:snap-bbox="true" + inkscape:snap-nodes="true" + inkscape:object-paths="true" + inkscape:snap-center="true" + showgrid="true" + inkscape:document-rotation="0" + inkscape:current-layer="layer1" + inkscape:document-units="mm" + inkscape:cy="218.5" + inkscape:cx="150" + inkscape:zoom="1" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" + fit-margin-top="5" + fit-margin-left="5" + fit-margin-right="5" + fit-margin-bottom="5" + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false" + inkscape:lockguides="true"> + + + id="metadata5"> image/svg+xml - - + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-44.999995,-23.52916)"> + + + + in1 + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="55.785919" + y="37.764626" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5">in1 out1 - + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="122.39284" + y="37.480064" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-6">out1 + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 54.49999,45.000004 H 82.499984" + id="path984-0-9-9-9-7-6-8" /> + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 140.5,40.999992 4,4 -4,4 z" + id="path4652-12-9-60-5-4-2" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 50.499994,40.999992 4,4 -4,4 z" + id="path4652-12-9-60-5-4-2-3" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> diff --git a/docs/api/_images/Compressor_darkmode.svg b/docs/api/_images/Compressor_darkmode.svg new file mode 100644 index 000000000..6a52860bc --- /dev/null +++ b/docs/api/_images/Compressor_darkmode.svg @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + in1 + out1 + + + + + diff --git a/docs/api/_images/Condenser.svg b/docs/api/_images/Condenser.svg index 4b98a8454..f5e4981f1 100644 --- a/docs/api/_images/Condenser.svg +++ b/docs/api/_images/Condenser.svg @@ -1,138 +1,236 @@ + viewBox="0 0 78.49998 95.46657" + height="95.466568mm" + width="78.499977mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + + + + + + inkscape:window-y="27" + inkscape:window-x="72" + inkscape:window-height="1136" + inkscape:window-width="1848" + inkscape:snap-to-guides="false" + inkscape:guide-bbox="true" + showguides="true" + inkscape:bbox-nodes="true" + inkscape:snap-grids="true" + inkscape:snap-bbox="true" + inkscape:snap-nodes="true" + inkscape:object-paths="true" + inkscape:snap-center="true" + showgrid="true" + inkscape:document-rotation="0" + inkscape:current-layer="layer1" + inkscape:document-units="mm" + inkscape:cy="166.25" + inkscape:cx="163.5" + inkscape:zoom="2" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" + fit-margin-top="5" + fit-margin-left="5" + fit-margin-right="5" + fit-margin-bottom="5" + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false" + inkscape:snap-others="true"> + originx="-139.87502" + originy="-37.150059" /> - + id="metadata5"> image/svg+xml - - out2 + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-139.875,-37.150058)"> + + + + + - - + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 160.875,47.116657 V 65.116655" + id="path984-0-9-9-9-7-6-6" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 160.875,123.11665 V 104.6501" + id="path984-0-9-9-9-7-6-9" /> in1 - out1 - + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="144.1609" + y="57.881287" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3">in1 in2 + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="170.76784" + y="117.59671" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-3">out1 + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 212.87498,84.650055 -4,4 4,4 z" + id="path4652-12-9-60-5-4-2-0" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 156.87498,42.650057 4,4 4,-4 z" + id="path4652-12-9-60-5-4-2-0-5" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + + + in2 + out2 diff --git a/docs/api/_images/Condenser_darkmode.svg b/docs/api/_images/Condenser_darkmode.svg new file mode 100644 index 000000000..a82df3413 --- /dev/null +++ b/docs/api/_images/Condenser_darkmode.svg @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + in1 + out1 + + + + + in2 + out2 + + diff --git a/docs/api/_images/DropletSeparator.svg b/docs/api/_images/DropletSeparator.svg index a94c9fbae..b41a4eceb 100644 --- a/docs/api/_images/DropletSeparator.svg +++ b/docs/api/_images/DropletSeparator.svg @@ -1,136 +1,213 @@ + viewBox="0 0 69.223438 95.000002" + height="95mm" + width="69.223434mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + + + + + + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false"> + originx="-196.83243" + originy="-62.500002" /> - + id="metadata5"> image/svg+xml - - - in1 - out1 + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-196.83239,-62.500007)"> + + + + + + sodipodi:nodetypes="ccc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 224.55586,116.00001 18.99988,12.00002 13.0001,-2e-5" + id="path984-0-9-9-9-7-6-0-1" /> + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 218.55586,94.529191 V 72.000005" + id="path984-0-9-9-9-7-0-1-5-0-8-4-7-7-8" /> out2 + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="227.50845" + y="83.53054" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-4-9-5">out1 + out2 + in1 + + sodipodi:nodetypes="cccc" /> + sodipodi:nodetypes="cccc" /> diff --git a/docs/api/_images/DropletSeparator_darkmode.svg b/docs/api/_images/DropletSeparator_darkmode.svg new file mode 100644 index 000000000..151e49f47 --- /dev/null +++ b/docs/api/_images/DropletSeparator_darkmode.svg @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + out1 + out2 + in1 + + + + + diff --git a/docs/api/_images/Drum.svg b/docs/api/_images/Drum.svg index 3ab3959d2..d395db3a4 100644 --- a/docs/api/_images/Drum.svg +++ b/docs/api/_images/Drum.svg @@ -1,151 +1,240 @@ + viewBox="0 0 92.037091 94.999971" + height="94.999969mm" + width="92.037086mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + + + + + + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false"> + originx="-184.7222" + originy="-62.500004" /> - + id="metadata5"> image/svg+xml - - - in1 - out2 + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-184.72217,-62.500008)"> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 219.25922,148.00002 v -22.5292" + id="path984-0-9-9-9-7-6-9" /> + + + + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 203.78832,110.00002 234.73014,110" + id="path984-0-9-9-9-7-0-1-5-0-8-4-7-7-5-6-6" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 225.25924,104.00002 18.99988,-12.000016 23.0001,2e-5" + id="path984-0-9-9-9-7-6-0" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 225.25924,116.00002 18.99988,12.00002 23.0001,-2e-5" + id="path984-0-9-9-9-7-6-0-1" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 219.25924,94.529204 V 72.000018" + id="path984-0-9-9-9-7-0-1-5-0-8-4-7-7-8" /> + out1 + in2 out1 + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="201.60489" + y="143.75243" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-4-9-8-56">in1 in2 + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="189.17715" + y="82.48008" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-4-9-58">out2 + + + + diff --git a/docs/api/_images/Drum_darkmode.svg b/docs/api/_images/Drum_darkmode.svg new file mode 100644 index 000000000..b1399c532 --- /dev/null +++ b/docs/api/_images/Drum_darkmode.svg @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + out1 + in2 + in1 + out2 + + + + + + diff --git a/docs/api/_images/FuelCell.svg b/docs/api/_images/FuelCell.svg index 5ca26e758..12b2d6dcd 100644 --- a/docs/api/_images/FuelCell.svg +++ b/docs/api/_images/FuelCell.svg @@ -1,93 +1,99 @@ - - + version="1.1" + viewBox="0 0 72.499994 67.499994" + height="67.499992mm" + width="72.499992mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + id="linearGradient2073" + inkscape:collect="always"> + style="stop-color:#000000;stop-opacity:1;" /> - - - + style="stop-color:#000000;stop-opacity:0;" /> + - - - + gradientTransform="translate(0.29243162,-2.3779876)" + gradientUnits="userSpaceOnUse" + y2="204.98201" + x2="223.36507" + y1="204.98201" + x1="221.6942" + id="linearGradient2075" + xlink:href="#linearGradient2073" + inkscape:collect="always" /> + inkscape:snap-nodes="true" + inkscape:object-paths="true" + inkscape:snap-center="true" + showgrid="true" + inkscape:document-rotation="0" + inkscape:current-layer="layer1" + inkscape:document-units="mm" + inkscape:cy="148.84598" + inkscape:cx="91.923882" + inkscape:zoom="1.4142136" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" + fit-margin-top="5" + fit-margin-left="5" + fit-margin-right="5" + fit-margin-bottom="5" + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false" + inkscape:snap-object-midpoints="true"> + originx="-88.75" + originy="-33.750006" /> @@ -97,208 +103,213 @@ image/svg+xml - - - in2 - - in1 - out1 - out2 - in3 - - - - - - - - - - - - - - - - - - H2 - O2 - H2O - - + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-88.749981,-33.750012)"> + + + + + + out2 + out1 + H2 + in1 + in2 + O2 + H2O + in3 + + + + + + + + + + + diff --git a/docs/api/_images/FuelCell_darkmode.svg b/docs/api/_images/FuelCell_darkmode.svg new file mode 100644 index 000000000..53394fb33 --- /dev/null +++ b/docs/api/_images/FuelCell_darkmode.svg @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + out2 + out1 + H2 + in1 + in2 + O2 + H2O + in3 + + + + + + + + + + + + + diff --git a/docs/api/_images/HeatExchanger.svg b/docs/api/_images/HeatExchanger.svg index 0d4a7b439..1d3ec7e5a 100644 --- a/docs/api/_images/HeatExchanger.svg +++ b/docs/api/_images/HeatExchanger.svg @@ -1,146 +1,241 @@ + viewBox="0 0 115.00002 94.999971" + height="94.999969mm" + width="115.00002mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + + + + + + fit-margin-bottom="5" + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false"> + originx="-167.5" + originy="-32.500003" /> - + id="metadata5"> image/svg+xml - - in2 - out2 + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-167.49997,-32.500008)"> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 225.00001,42.000019 -2e-5,23.000152" + id="path984-0-9-9-9-7-6" /> + + + - + inkscape:connector-curvature="0" + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 210.00003,65.000005 v 30.00002 h 30.00004 v -30.00002 z" + id="path1057-2-7-1-9" + sodipodi:nodetypes="ccccc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 240.00007,80.000019 h 32.9999" + id="path984-0-9-9-9-7-6-4" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 224.99999,118.00002 V 95.000025" + id="path984-0-9-9-9-7-0-1-5-0-8-4-7-7-8" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 210.00003,80.000019 H 176.99997" + id="path984-0-9-9-9-7-6-4-1" /> + in1 + out1 in1 + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="233.95258" + y="113.53056" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-4-7-3-7">out2 out1 + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="227.38422" + y="53.75243" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-4-7-3-7-3">in2 + + + + diff --git a/docs/api/_images/HeatExchanger_darkmode.svg b/docs/api/_images/HeatExchanger_darkmode.svg new file mode 100644 index 000000000..8a8a56a12 --- /dev/null +++ b/docs/api/_images/HeatExchanger_darkmode.svg @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + in1 + out1 + out2 + in2 + + + + + + diff --git a/docs/api/_images/Merge.svg b/docs/api/_images/Merge.svg index f88a7258c..e75c56302 100644 --- a/docs/api/_images/Merge.svg +++ b/docs/api/_images/Merge.svg @@ -1,198 +1,310 @@ - - - + viewBox="0 0 51.161181 48.620084" + height="48.620083mm" + width="51.161179mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + id="defs2"> + transform="scale(-0.4)" + style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt" + d="M 5.77,0 -2.88,5 V -5 Z" + id="path9033" /> + + + + transform="matrix(0.8,0,0,0.8,10,0)" + style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path8897" /> + + + + + + + + + + id="metadata5"> image/svg+xml - + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-153.74997,7.3700866)"> + + in2 + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="159.9464" + y="16.240038" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-4-0">out1 in1 - - - - - + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="171.64293" + y="1.3823198" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-4-0-3">in1 out1 + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="186.65547" + y="6.3823199" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-4-0-3-2">in2 inn - + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="193.62334" + y="21.359591" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-4-0-3-2-6">in3 in3 + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="166.63509" + y="31.38232" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-3-4-0-3-2-2">inn + + + + + + + + + - diff --git a/docs/api/_images/Merge_darkmode.svg b/docs/api/_images/Merge_darkmode.svg new file mode 100644 index 000000000..deb785f7c --- /dev/null +++ b/docs/api/_images/Merge_darkmode.svg @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + out1 + in1 + in2 + in3 + inn + + + + + + + + + + + diff --git a/docs/api/_images/Node.svg b/docs/api/_images/Node.svg deleted file mode 100644 index 7c51228a5..000000000 --- a/docs/api/_images/Node.svg +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - in2 - in1 - - - - - outn - inn - in3 - - - - out2 - out1 - - out3 - - - - - diff --git a/docs/api/_images/ParabolicTrough.svg b/docs/api/_images/ParabolicTrough.svg index 7ca971585..7750d68a5 100644 --- a/docs/api/_images/ParabolicTrough.svg +++ b/docs/api/_images/ParabolicTrough.svg @@ -1,921 +1,193 @@ - - + viewBox="0 0 87.499987 31.987609" + height="31.987608mm" + width="87.499985mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="defs2"> + + + + + + + fit-margin-bottom="5" + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false" + inkscape:snap-object-midpoints="true"> + originx="-93.750002" + originy="-59.500001" /> + id="metadata5"> image/svg+xml - + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-93.749987,-59.500006)"> + sodipodi:nodetypes="cccc" /> + sodipodi:nodetypes="cccc" /> in1 + style="stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + y="71.382317" + x="101.64295" + id="tspan1023-6-9-1-6-2-8-3-2-0-7-6" + sodipodi:role="line">in1 out1 + style="stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + y="71.240028" + x="164.94641" + id="tspan1023-6-9-1-6-2-8-3-2-0-7-6-5" + sodipodi:role="line">out1 + + + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> diff --git a/docs/api/_images/ParabolicTrough_darkmode.svg b/docs/api/_images/ParabolicTrough_darkmode.svg new file mode 100644 index 000000000..363e96515 --- /dev/null +++ b/docs/api/_images/ParabolicTrough_darkmode.svg @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + in1 + out1 + + + + + + + + + diff --git a/docs/api/_images/Pipe.svg b/docs/api/_images/Pipe.svg index 16e9bbfdc..f0db97821 100644 --- a/docs/api/_images/Pipe.svg +++ b/docs/api/_images/Pipe.svg @@ -1,106 +1,175 @@ + viewBox="0 0 72.499994 20.370091" + height="20.37009mm" + width="72.499992mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + + + + + + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false" + inkscape:snap-object-midpoints="true"> + originx="-93.75" + originy="-87.629906" /> - + id="metadata5"> image/svg+xml - + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-93.74998,-87.62991)"> + + + inin1 + id="tspan2432">1 outout1 + id="tspan2432-5">1 + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 158.99998,98.000007 2,2.000003 -2,2 z" + id="path4652-12-9-60-5-4-2-2" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> - + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 98.999979,98.000007 2.000001,2.000003 -2.000001,2 z" + id="path4652-12-9-60-5-4-2-2-3" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> diff --git a/docs/api/_images/Pipe_darkmode.svg b/docs/api/_images/Pipe_darkmode.svg new file mode 100644 index 000000000..de9aba628 --- /dev/null +++ b/docs/api/_images/Pipe_darkmode.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + in1 + out1 + + + + diff --git a/docs/api/_images/Pump.svg b/docs/api/_images/Pump.svg index e35ce3e5d..4aa38c567 100644 --- a/docs/api/_images/Pump.svg +++ b/docs/api/_images/Pump.svg @@ -1,100 +1,182 @@ + viewBox="0 0 94.999982 37.738267" + height="37.738266mm" + width="94.999977mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + + + + + - + inkscape:window-y="27" + inkscape:window-x="72" + inkscape:window-height="1136" + inkscape:window-width="1848" + inkscape:snap-to-guides="false" + inkscape:guide-bbox="true" + showguides="true" + inkscape:bbox-nodes="false" + inkscape:snap-grids="true" + inkscape:snap-bbox="true" + inkscape:snap-nodes="true" + inkscape:object-paths="true" + inkscape:snap-center="true" + showgrid="true" + inkscape:document-rotation="0" + inkscape:current-layer="layer1" + inkscape:document-units="mm" + inkscape:cy="78.135299" + inkscape:cx="77.781746" + inkscape:zoom="1.4142136" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" + fit-margin-top="5" + fit-margin-left="5" + fit-margin-right="5" + fit-margin-bottom="5" + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false"> + + + id="metadata5"> image/svg+xml - - + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-97.499981,-0.69534715)"> + + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 145.00012,32.435493 12,-11.99998 -12,-11.9999998" + id="path4585-2-7-1" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" /> - in1 - out1 + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 102.99998,24.435533 4,-4 -4,-4 z" + id="path4652-12-9-60-5-4-2-3" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 182.99998,24.435533 4,-4 -4,-4 z" + id="path4652-12-9-60-5-4-2-3-5" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 182.99998,20.435533 H 156.99812" + id="path984-0-9-9-9-7-0-1-5-0-8-4-7-7-8-8" /> + + in1 + out1 diff --git a/docs/api/_images/Pump_darkmode.svg b/docs/api/_images/Pump_darkmode.svg new file mode 100644 index 000000000..bacf3d1a6 --- /dev/null +++ b/docs/api/_images/Pump_darkmode.svg @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + in1 + out1 + + diff --git a/docs/api/_images/SolarCollector.svg b/docs/api/_images/SolarCollector.svg index abf6d8d2b..3c6c8a22a 100644 --- a/docs/api/_images/SolarCollector.svg +++ b/docs/api/_images/SolarCollector.svg @@ -1,974 +1,183 @@ - - + viewBox="0 0 70.499965 52.499989" + height="52.499989mm" + width="70.499962mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + fit-margin-bottom="5" + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false"> + originx="-119.75004" + originy="-43.750011" /> + id="metadata5"> image/svg+xml - - - - - - - - + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-119.75,-43.750016)"> in1 + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="131.64293" + y="86.382317" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-7-3-1">in1 out1 + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="164.9464" + y="56.240036" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-7-3-1-9">out1 - + + sodipodi:nodetypes="cccc" /> + sodipodi:nodetypes="cccc" /> - - - - - + sodipodi:nodetypes="cccccccccccccccc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 129.99996,89.000005 v -10 h 32 l 3,-3 h -32 l 3,-3 h 32 l 3,-3 h -32 l 3,-3 h 32 l 3,-3 h -32 l 3,-3 h 32 v -10" + id="path984-0-9-9-9-7-2" /> diff --git a/docs/api/_images/SolarCollector_darkmode.svg b/docs/api/_images/SolarCollector_darkmode.svg new file mode 100644 index 000000000..50259e5cc --- /dev/null +++ b/docs/api/_images/SolarCollector_darkmode.svg @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + in1 + out1 + + + + + + diff --git a/docs/api/_images/Sp.svg b/docs/api/_images/Sp.svg new file mode 100644 index 000000000..af97dfcef --- /dev/null +++ b/docs/api/_images/Sp.svg @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + in1 + out1 + out2 + out3 + outn + + + + + + + + + + + diff --git a/docs/api/_images/Splitter.svg b/docs/api/_images/Splitter.svg index 63978612d..a1fecb9bb 100644 --- a/docs/api/_images/Splitter.svg +++ b/docs/api/_images/Splitter.svg @@ -1,198 +1,309 @@ - - - + viewBox="0 0 56.082793 49.455621" + height="49.45562mm" + width="56.08279mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + id="defs2"> + transform="scale(-0.4)" + style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt" + d="M 5.77,0 -2.88,5 V -5 Z" + id="path9033" /> + + + + transform="matrix(0.8,0,0,0.8,10,0)" + style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path8897" /> + + + + + + + + + + id="metadata5"> image/svg+xml - + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-153.74997,7.2278038)"> + + inin1 + id="tspan2879">1 outout1 - - - - - - + id="tspan4210">1 outout2 + id="tspan4210-1">2 outout3 + id="tspan4210-1-6">3 outoutn + id="tspan4210-1-0">n + + + + + + + + + - diff --git a/docs/api/_images/Splitter_darkmode.svg b/docs/api/_images/Splitter_darkmode.svg new file mode 100644 index 000000000..478f16bd6 --- /dev/null +++ b/docs/api/_images/Splitter_darkmode.svg @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + in1 + out1 + out2 + out3 + outn + + + + + + + + + + + diff --git a/docs/api/_images/SubsystemInterface.svg b/docs/api/_images/SubsystemInterface.svg index ebd755145..bba4241b6 100644 --- a/docs/api/_images/SubsystemInterface.svg +++ b/docs/api/_images/SubsystemInterface.svg @@ -1,51 +1,52 @@ - - - + viewBox="0 0 67.688335 47.63987" + height="47.63987mm" + width="67.688332mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + id="defs2"> + + + + + + - - - + + + + id="metadata5"> image/svg+xml - + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-122.10837,-52.610142)"> system border + in1 + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="174.9464" + y="71.240036" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-7">out1 out1 - + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="174.9464" + y="76.240036" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-7-3">out2 + in1 inn + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="126.64294" + y="76.382324" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-7-3-1-9">in2 outn + style="font-size:4.9389px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round" + x="126.64294" + y="91.382324" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-7-3-1-2">inn + outn + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 138.99999,67.999991 2,2 -2,2 z" + id="path4652-12-9-60-5-4-2-4-3" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 169.99999,67.999991 2,2 -2,2 z" + id="path4652-12-9-60-5-4-2-4-6" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 169.99997,70.000011 h -29" + id="path984-0-9-9-9-7" /> - system border + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:0.5, 2;stroke-dashoffset:0;stroke-opacity:1" + d="m 154.99997,95.000011 v -30" + id="path984-0-9-9-9-7-9" /> + + + + + + diff --git a/docs/api/_images/SubsystemInterface_darkmode.svg b/docs/api/_images/SubsystemInterface_darkmode.svg new file mode 100644 index 000000000..8faa3ee23 --- /dev/null +++ b/docs/api/_images/SubsystemInterface_darkmode.svg @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + system border + out1 + out2 + in1 + in2 + inn + outn + + + + + + + + + + + + diff --git a/docs/api/_images/Turbine.svg b/docs/api/_images/Turbine.svg index 2c18e2c72..1e5c355aa 100644 --- a/docs/api/_images/Turbine.svg +++ b/docs/api/_images/Turbine.svg @@ -1,114 +1,175 @@ - - + viewBox="0 0 104.99999 69.999902" + height="69.999901mm" + width="104.99998mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + id="defs2"> + + + + + + + + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false" + inkscape:lockguides="true"> + originx="-120.00004" + originy="-47.750066" /> + id="metadata5"> image/svg+xml - + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-120,-47.750067)"> + in1 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-0-9" + x="130.78593" + y="70.014618" + style="fill:#000000;fill-opacity:1;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round">in1 out1 + id="tspan1295-2-3-0-3-5-7-3-5-0-5-24-7-1-0-9-3" + x="197.39284" + y="69.730057" + style="fill:#000000;fill-opacity:1;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round">out1 + + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 187.50004,71.750011 -6e-5,-14.500018 H 215.5" + id="path984-0-9-9-9-7-6-8-4" /> + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 125.5,53.249995 4,4 -4,4 z" + id="path4652-12-9-60-5-4-2-9" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 215.5,53.249995 4,4 -4,4 z" + id="path4652-12-9-60-5-4-2-9-3" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> diff --git a/docs/api/_images/Turbine_darkmode.svg b/docs/api/_images/Turbine_darkmode.svg new file mode 100644 index 000000000..0aa7d4154 --- /dev/null +++ b/docs/api/_images/Turbine_darkmode.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + in1 + out1 + + + + + + diff --git a/docs/api/_images/Valve.svg b/docs/api/_images/Valve.svg index b20049bcd..5154c2561 100644 --- a/docs/api/_images/Valve.svg +++ b/docs/api/_images/Valve.svg @@ -1,89 +1,175 @@ + viewBox="0 0 94.999957 30.74012" + height="30.74012mm" + width="94.999954mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + + + + + - + inkscape:window-y="27" + inkscape:window-x="72" + inkscape:window-height="1136" + inkscape:window-width="1848" + inkscape:snap-to-guides="false" + inkscape:guide-bbox="true" + showguides="true" + inkscape:bbox-nodes="false" + inkscape:snap-grids="true" + inkscape:snap-bbox="true" + inkscape:snap-nodes="true" + inkscape:object-paths="true" + inkscape:snap-center="true" + showgrid="true" + inkscape:document-rotation="0" + inkscape:current-layer="layer1" + inkscape:document-units="mm" + inkscape:cy="121" + inkscape:cx="256" + inkscape:zoom="0.5" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" + fit-margin-top="5" + fit-margin-left="5" + fit-margin-right="5" + fit-margin-bottom="5" + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false" + inkscape:snap-object-midpoints="true"> + + + id="metadata5"> image/svg+xml - + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-112.5,-82.444879)"> + + + in1 + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="179.89284" + y="94.665131" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-03">out1 out1 - + inkscape:export-ydpi="1012" + inkscape:export-xdpi="1012" + xml:space="preserve" + style="font-size:9.8778px;line-height:1.25;font-family:sans-serif;stroke-width:0.529166;stroke-linecap:round;stroke-linejoin:round" + x="123.28594" + y="94.949692" + id="text1297-0-9-8-6-9-4-7-6-7-8-6-9-5-5">in1 + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 118,98.185072 4,4.000008 -4,4 z" + id="path4652-12-9-60-5-4-2-2" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 197.99998,98.185064 4,4.000016 -4,4 z" + id="path4652-12-9-60-5-4-2-2-3" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccc" /> diff --git a/docs/api/_images/Valve_darkmode.svg b/docs/api/_images/Valve_darkmode.svg new file mode 100644 index 000000000..b5687ac84 --- /dev/null +++ b/docs/api/_images/Valve_darkmode.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + out1 + in1 + + + + diff --git a/docs/api/_images/WaterElectrolyzer.svg b/docs/api/_images/WaterElectrolyzer.svg index e7e4f68a2..d321ebb45 100644 --- a/docs/api/_images/WaterElectrolyzer.svg +++ b/docs/api/_images/WaterElectrolyzer.svg @@ -1,93 +1,99 @@ - - + version="1.1" + viewBox="0 0 72.499994 67.499994" + height="67.499992mm" + width="72.499992mm" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + id="linearGradient2073" + inkscape:collect="always"> + style="stop-color:#000000;stop-opacity:1;" /> - - - + style="stop-color:#000000;stop-opacity:0;" /> + - - - + gradientTransform="translate(0.29243162,-2.3779876)" + gradientUnits="userSpaceOnUse" + y2="204.98201" + x2="223.36507" + y1="204.98201" + x1="221.6942" + id="linearGradient2075" + xlink:href="#linearGradient2073" + inkscape:collect="always" /> + inkscape:snap-nodes="true" + inkscape:object-paths="true" + inkscape:snap-center="true" + showgrid="true" + inkscape:document-rotation="0" + inkscape:current-layer="layer1" + inkscape:document-units="mm" + inkscape:cy="148.84598" + inkscape:cx="91.923882" + inkscape:zoom="1.4142136" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" + fit-margin-top="5" + fit-margin-left="5" + fit-margin-right="5" + fit-margin-bottom="5" + inkscape:pagecheckerboard="0" + inkscape:snap-intersection-paths="true" + inkscape:bbox-paths="false" + inkscape:snap-object-midpoints="true"> + originx="-88.75" + originy="-33.750006" /> @@ -97,200 +103,213 @@ image/svg+xml - - - out2 - - in1 - out1 - in2 - out3 - - - - - - - - - - - - - - H2 - O2 - H2O - - + inkscape:groupmode="layer" + inkscape:label="Ebene 1" + transform="translate(-88.749981,-33.750012)"> + + + + + + in2 + out1 + H2 + in1 + out2 + O2 + H2O + out3 + + + + + + + + + + + diff --git a/docs/api/_images/WaterElectrolyzer_darkmode.svg b/docs/api/_images/WaterElectrolyzer_darkmode.svg new file mode 100644 index 000000000..c83c5bb4e --- /dev/null +++ b/docs/api/_images/WaterElectrolyzer_darkmode.svg @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + in2 + out1 + H2 + in1 + out2 + O2 + H2O + out3 + + + + + + + + + + + + + diff --git a/docs/api/_images/flowsheet.svg b/docs/api/_images/flowsheet.svg new file mode 100644 index 000000000..a0e96ceb9 --- /dev/null +++ b/docs/api/_images/flowsheet.svg @@ -0,0 +1,873 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + compressor 1 + condenser + evaporator + expansion valve + 1 + 6 + + + + + + + + consumer + 20 + 21 + 22 + + + 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 2 + 3 + 4 + 5 + 7 + 8 + 9 + 11 + 12 + 14 + 15 + 16 + 17 + 13 + 18 + 19 + superheater + compressor 2 + + + + + diff --git a/docs/whats_new/v0-6-1.rst b/docs/whats_new/v0-6-1.rst index 04cb044aa..5632686ad 100644 --- a/docs/whats_new/v0-6-1.rst +++ b/docs/whats_new/v0-6-1.rst @@ -16,15 +16,11 @@ New Features (`PR #329 `_). - Integration of an optimization suite using pygmo :cite:`Biscani2020` to apply a variety of state of the art optimization algorithms to your TESPy model -<<<<<<< HEAD - (`PR #296 `_). It has been further - improved in `PR #357 `_. -======= - (`PR #296 `_). + (`PR #296 `__). It has been further + improved in `PR #357 `__. - Volumetric flow can be referenced using the :py:class:`tespy.connections.connection.Ref` class - (`Discussion #352 `_). ->>>>>>> 968a2c2cb7b74522b6f4b3d289bdae1daa04cea7 + (`Discussion #352 `__). Documentation ############# diff --git a/src/tespy/components/basics/subsystem_interface.py b/src/tespy/components/basics/subsystem_interface.py index c5dd3e0c4..62d208f89 100644 --- a/src/tespy/components/basics/subsystem_interface.py +++ b/src/tespy/components/basics/subsystem_interface.py @@ -34,8 +34,14 @@ class SubsystemInterface(Component): Image .. image:: /api/_images/SubsystemInterface.svg - :alt: alternative text + :alt: flowsheet of the subsystem interface :align: center + :class: only-light + + .. image:: /api/_images/SubsystemInterface_darkmode.svg + :alt: flowsheet of the subsystem interface + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/combustion/base.py b/src/tespy/components/combustion/base.py index db12f6f8a..eeeca15e7 100644 --- a/src/tespy/components/combustion/base.py +++ b/src/tespy/components/combustion/base.py @@ -53,9 +53,15 @@ class CombustionChamber(Component): Image - .. image:: _images/CombustionChamber.svg - :alt: alternative text + .. image:: /api/_images/CombustionChamber.svg + :alt: flowsheet of the combustion chamber :align: center + :class: only-light + + .. image:: /api/_images/CombustionChamber_darkmode.svg + :alt: flowsheet of the combustion chamber + :align: center + :class: only-dark .. note:: diff --git a/src/tespy/components/combustion/diabatic.py b/src/tespy/components/combustion/diabatic.py index 7e57b7e57..92351fef6 100644 --- a/src/tespy/components/combustion/diabatic.py +++ b/src/tespy/components/combustion/diabatic.py @@ -47,15 +47,21 @@ class DiabaticCombustionChamber(CombustionChamber): Image - .. image:: _images/CombustionChamber.svg - :alt: alternative text + .. image:: /api/_images/CombustionChamber.svg + :alt: flowsheet of the combustion chamber :align: center + :class: only-light + + .. image:: /api/_images/CombustionChamber_darkmode.svg + :alt: flowsheet of the combustion chamber + :align: center + :class: only-dark .. note:: The fuel and the air components can be connected to either of the inlets. The pressure of inlet 2 is disconnected from the pressure of - inlet 1. A warning is promted, if the pressure at inlet 2 is lower than + inlet 1. A warning is prompted, if the pressure at inlet 2 is lower than the pressure at inlet 1. Parameters diff --git a/src/tespy/components/combustion/engine.py b/src/tespy/components/combustion/engine.py index 49e408bf5..bdf9a072e 100644 --- a/src/tespy/components/combustion/engine.py +++ b/src/tespy/components/combustion/engine.py @@ -74,9 +74,15 @@ class CombustionEngine(CombustionChamber): Image - .. image:: _images/CombustionEngine.svg - :alt: alternative text + .. image:: /api/_images/CombustionEngine.svg + :alt: flowsheet of the combustion engine :align: center + :class: only-light + + .. image:: /api/_images/CombustionEngine_darkmode.svg + :alt: flowsheet of the combustion engine + :align: center + :class: only-dark .. note:: diff --git a/src/tespy/components/heat_exchangers/base.py b/src/tespy/components/heat_exchangers/base.py index a7a69fcc2..ec890aa0d 100644 --- a/src/tespy/components/heat_exchangers/base.py +++ b/src/tespy/components/heat_exchangers/base.py @@ -56,9 +56,15 @@ class HeatExchanger(Component): Image - .. image:: _images/HeatExchanger.svg - :alt: alternative text + .. image:: /api/_images/HeatExchanger.svg + :alt: flowsheet of the heat exchanger :align: center + :class: only-light + + .. image:: /api/_images/HeatExchanger_darkmode.svg + :alt: flowsheet of the heat exchanger + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/heat_exchangers/condenser.py b/src/tespy/components/heat_exchangers/condenser.py index 178235548..2f21d36da 100644 --- a/src/tespy/components/heat_exchangers/condenser.py +++ b/src/tespy/components/heat_exchangers/condenser.py @@ -61,9 +61,15 @@ class Condenser(HeatExchanger): Image - .. image:: _images/Condenser.svg - :alt: alternative text + .. image:: /api/_images/Condenser.svg + :alt: flowsheet of the condenser :align: center + :class: only-light + + .. image:: /api/_images/Condenser_darkmode.svg + :alt: flowsheet of the condenser + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/heat_exchangers/desuperheater.py b/src/tespy/components/heat_exchangers/desuperheater.py index 64cc974ff..f9906792a 100644 --- a/src/tespy/components/heat_exchangers/desuperheater.py +++ b/src/tespy/components/heat_exchangers/desuperheater.py @@ -47,9 +47,15 @@ class Desuperheater(HeatExchanger): Image - .. image:: _images/HeatExchanger.svg - :alt: alternative text + .. image:: /api/_images/HeatExchanger.svg + :alt: flowsheet of the desuperheater :align: center + :class: only-light + + .. image:: /api/_images/HeatExchanger_darkmode.svg + :alt: flowsheet of the desuperheater + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/heat_exchangers/parabolic_trough.py b/src/tespy/components/heat_exchangers/parabolic_trough.py index 387eb426a..5f445a49c 100644 --- a/src/tespy/components/heat_exchangers/parabolic_trough.py +++ b/src/tespy/components/heat_exchangers/parabolic_trough.py @@ -45,9 +45,15 @@ class ParabolicTrough(HeatExchangerSimple): Image - .. image:: _images/ParabolicTrough.svg - :alt: alternative text + .. image:: /api/_images/ParabolicTrough.svg + :alt: flowsheet of the parabolic trough :align: center + :class: only-light + + .. image:: /api/_images/ParabolicTrough_darkmode.svg + :alt: flowsheet of the parabolic trough + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/heat_exchangers/simple.py b/src/tespy/components/heat_exchangers/simple.py index f2468afc5..91b68e5be 100644 --- a/src/tespy/components/heat_exchangers/simple.py +++ b/src/tespy/components/heat_exchangers/simple.py @@ -60,9 +60,15 @@ class HeatExchangerSimple(Component): Image - .. image:: _images/Pipe.svg - :alt: alternative text + .. image:: /api/_images/Pipe.svg + :alt: flowsheet of the simple heat exchanger :align: center + :class: only-light + + .. image:: /api/_images/Pipe_darkmode.svg + :alt: flowsheet of the simple heat exchanger + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/heat_exchangers/solar_collector.py b/src/tespy/components/heat_exchangers/solar_collector.py index 669b07226..b66680204 100644 --- a/src/tespy/components/heat_exchangers/solar_collector.py +++ b/src/tespy/components/heat_exchangers/solar_collector.py @@ -45,9 +45,15 @@ class SolarCollector(HeatExchangerSimple): Image - .. image:: _images/SolarCollector.svg - :alt: alternative text + .. image:: /api/_images/SolarCollector.svg + :alt: flowsheet of the solar collector :align: center + :class: only-light + + .. image:: /api/_images/SolarCollector_darkmode.svg + :alt: flowsheet of the solar collector + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/nodes/droplet_separator.py b/src/tespy/components/nodes/droplet_separator.py index 276e0d0cb..74943bbd6 100644 --- a/src/tespy/components/nodes/droplet_separator.py +++ b/src/tespy/components/nodes/droplet_separator.py @@ -40,9 +40,15 @@ class DropletSeparator(NodeBase): Image - .. image:: _images/DropletSeparator.svg - :alt: alternative text + .. image:: /api/_images/DropletSeparator.svg + :alt: flowsheet of the droplet separator :align: center + :class: only-light + + .. image:: /api/_images/DropletSeparator_darkmode.svg + :alt: flowsheet of the droplet separator + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/nodes/drum.py b/src/tespy/components/nodes/drum.py index f67984f86..657573ef3 100644 --- a/src/tespy/components/nodes/drum.py +++ b/src/tespy/components/nodes/drum.py @@ -35,9 +35,15 @@ class Drum(DropletSeparator): Image - .. image:: _images/Drum.svg - :alt: alternative text + .. image:: /api/_images/Drum.svg + :alt: flowsheet of the drum :align: center + :class: only-light + + .. image:: /api/_images/Drum_darkmode.svg + :alt: flowsheet of the drum + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/nodes/merge.py b/src/tespy/components/nodes/merge.py index 53e7bd25d..ceda8c098 100644 --- a/src/tespy/components/nodes/merge.py +++ b/src/tespy/components/nodes/merge.py @@ -37,9 +37,15 @@ class Merge(NodeBase): Image - .. image:: _images/Merge.svg - :alt: alternative text + .. image:: /api/_images/Merge.svg + :alt: flowsheet of the merge :align: center + :class: only-light + + .. image:: /api/_images/Merge_darkmode.svg + :alt: flowsheet of the merge + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/nodes/separator.py b/src/tespy/components/nodes/separator.py index ab107cc1b..48661293c 100644 --- a/src/tespy/components/nodes/separator.py +++ b/src/tespy/components/nodes/separator.py @@ -39,9 +39,15 @@ class Separator(NodeBase): Image - .. image:: _images/Splitter.svg - :alt: alternative text + .. image:: /api/_images/Splitter.svg + :alt: flowsheet of the splitter :align: center + :class: only-light + + .. image:: /api/_images/Splitter_darkmode.svg + :alt: flowsheet of the splitter + :align: center + :class: only-dark Note ---- diff --git a/src/tespy/components/nodes/splitter.py b/src/tespy/components/nodes/splitter.py index c010d7453..b8bde6885 100644 --- a/src/tespy/components/nodes/splitter.py +++ b/src/tespy/components/nodes/splitter.py @@ -35,9 +35,15 @@ class Splitter(NodeBase): Image - .. image:: _images/Splitter.svg - :alt: alternative text + .. image:: /api/_images/Splitter.svg + :alt: flowsheet of the splitter :align: center + :class: only-light + + .. image:: /api/_images/Splitter_darkmode.svg + :alt: flowsheet of the splitter + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/piping/pipe.py b/src/tespy/components/piping/pipe.py index 7be2d211f..53bf10984 100644 --- a/src/tespy/components/piping/pipe.py +++ b/src/tespy/components/piping/pipe.py @@ -38,9 +38,15 @@ class Pipe(HeatExchangerSimple): Image - .. image:: _images/Pipe.svg - :alt: alternative text + .. image:: /api/_images/Pipe.svg + :alt: flowsheet of the pipe :align: center + :class: only-light + + .. image:: /api/_images/Pipe_darkmode.svg + :alt: flowsheet of the pipe + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/piping/valve.py b/src/tespy/components/piping/valve.py index bc86864c6..4d7b85361 100644 --- a/src/tespy/components/piping/valve.py +++ b/src/tespy/components/piping/valve.py @@ -42,9 +42,15 @@ class Valve(Component): Image - .. image:: _images/Valve.svg - :alt: alternative text + .. image:: /api/_images/Valve.svg + :alt: flowsheet of the valve :align: center + :class: only-light + + .. image:: /api/_images/Valve_darkmode.svg + :alt: flowsheet of the valve + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/reactors/water_electrolyzer.py b/src/tespy/components/reactors/water_electrolyzer.py index ae981d499..aa2a30c1a 100644 --- a/src/tespy/components/reactors/water_electrolyzer.py +++ b/src/tespy/components/reactors/water_electrolyzer.py @@ -27,8 +27,6 @@ from tespy.tools.global_vars import molar_masses from tespy.tools.helpers import TESPyComponentError -# %% - class WaterElectrolyzer(Component): r""" @@ -61,9 +59,15 @@ class WaterElectrolyzer(Component): Image - .. image:: _images/WaterElectrolyzer.svg - :alt: alternative text + .. image:: /api/_images/WaterElectrolyzer.svg + :alt: flowsheet of the water electrolyzer + :align: center + :class: only-light + + .. image:: /api/_images/WaterElectrolyzer_darkmode.svg + :alt: flowsheet of the water electrolyzer :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/turbomachinery/compressor.py b/src/tespy/components/turbomachinery/compressor.py index f9173c287..02bc41c86 100644 --- a/src/tespy/components/turbomachinery/compressor.py +++ b/src/tespy/components/turbomachinery/compressor.py @@ -51,9 +51,15 @@ class Compressor(Turbomachine): Image - .. image:: _images/Compressor.svg - :alt: alternative text + .. image:: /api/_images/Compressor.svg + :alt: flowsheet of the compressor :align: center + :class: only-light + + .. image:: /api/_images/Compressor_darkmode.svg + :alt: flowsheet of the compressor + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/turbomachinery/pump.py b/src/tespy/components/turbomachinery/pump.py index 1fb6e0ab4..7335253e3 100644 --- a/src/tespy/components/turbomachinery/pump.py +++ b/src/tespy/components/turbomachinery/pump.py @@ -46,9 +46,15 @@ class Pump(Turbomachine): Image - .. image:: _images/Pump.svg - :alt: alternative text + .. image:: /api/_images/Pump.svg + :alt: flowsheet of the pump :align: center + :class: only-light + + .. image:: /api/_images/Pump_darkmode.svg + :alt: flowsheet of the pump + :align: center + :class: only-dark Parameters ---------- diff --git a/src/tespy/components/turbomachinery/turbine.py b/src/tespy/components/turbomachinery/turbine.py index 386f9d908..8d363ab0f 100644 --- a/src/tespy/components/turbomachinery/turbine.py +++ b/src/tespy/components/turbomachinery/turbine.py @@ -47,9 +47,15 @@ class Turbine(Turbomachine): Image - .. image:: _images/Turbine.svg - :alt: alternative text + .. image:: /api/_images/Turbine.svg + :alt: flowsheet of the turbine :align: center + :class: only-light + + .. image:: /api/_images/Turbine_darkmode.svg + :alt: flowsheet of the turbine + :align: center + :class: only-dark Parameters ---------- From 6ccdd48c544163c89382f39726a594ee8938d6b9 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 10:49:31 +0200 Subject: [PATCH 111/120] Change order of adding components to network --- src/tespy/networks/network.py | 118 +++++++++++++++------------- tests/test_errors.py | 3 +- tests/test_networks/test_network.py | 27 +++++++ 3 files changed, 93 insertions(+), 55 deletions(-) diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index 3d638986b..c8108970f 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -175,7 +175,10 @@ def set_defaults(self): # connection dataframe self.conns = pd.DataFrame( columns=['object', 'source', 'source_id', 'target', 'target_id'], - dtype='object') + dtype='object' + ) + # component dataframe + self.comps = pd.DataFrame(dtype='object') # user defined function dictionary for fast access self.user_defined_eq = {} # bus dictionary @@ -471,6 +474,7 @@ def add_conns(self, *args): logging.debug(msg) # set status "checked" to false, if connection is added to network. self.checked = False + self._add_comps(*args) def del_conns(self, *args): """ @@ -525,6 +529,40 @@ def check_conns(self): logging.error(msg) raise hlp.TESPyNetworkError(msg) + def _add_comps(self, *args): + r""" + Add to network's component DataFrame from added connections. + + Parameters + ---------- + c : tespy.connections.connection.Connection + The connections, which have been added to the network. The + components are extracted from these information. + """ + # get unique components in new connections + comps = list(set([cp for c in args for cp in [c.source, c.target]])) + # add to the dataframe of components + for comp in comps: + if comp.label in self.comps.index: + if self.comps.loc[comp.label, 'object'] == comp: + continue + else: + comp_type = comp.__class__.__name__ + other_obj = self.comps.loc[comp.label, "object"] + other_comp_type = other_obj.__class__.__name__ + msg = ( + f"The component with the label {comp.label} of type " + f"{comp_type} cannot be added to the network as a " + f"different component of type {other_comp_type} with " + "the same label has already been added. All " + "components must have unique values!" + ) + raise hlp.TESPyNetworkError(msg) + + comp_type = comp.__class__.__name__ + self.comps.loc[comp.label, 'comp_type'] = comp_type + self.comps.loc[comp.label, 'object'] = comp + def add_ude(self, *args): r""" Add a user defined function to the network. @@ -644,21 +682,21 @@ def check_network(self): if len(self.conns) == 0: msg = ( 'No connections have been added to the network, please make ' - 'sure to add your connections with the .add_conns() method.') + 'sure to add your connections with the .add_conns() method.' + ) logging.error(msg) raise hlp.TESPyNetworkError(msg) if len(self.fluids) == 0: - msg = ('Network has no fluids, please specify a list with fluids ' - 'on network creation.') + msg = ( + 'Network has no fluids, please specify a list with fluids on ' + 'network creation.' + ) logging.error(msg) raise hlp.TESPyNetworkError(msg) self.check_conns() - # get unique components in connections dataframe - comps = pd.unique(self.conns[['source', 'target']].values.ravel()) - # build the dataframe for components - self.init_components(comps) + self.init_components() # count number of incoming and outgoing connections and compare to # expected values for comp in self.comps['object']: @@ -686,32 +724,9 @@ def check_network(self): msg = 'Networkcheck successful.' logging.info(msg) - def init_components(self, comps): - r""" - Set up a dataframe for the network's components. - - Additionally, check, if all components have unique labels. - - Parameters - ---------- - comps : pandas.core.frame.DataFrame - DataFrame containing all components of the network gathered from - the network's connection information. - - Note - ---- - The dataframe for the components is derived from the network's - connections. Thus it does not hold any additional information, the - dataframe is used to simplify the code, only. - """ - self.comps = pd.DataFrame(dtype='object') - - labels = [] - for comp in comps: - # this is required for printing and saving - comp_type = comp.__class__.__name__ - self.comps.loc[comp, 'comp_type'] = comp_type - self.comps.loc[comp, 'label'] = comp.label + def init_components(self): + r"""Set up necessary component information.""" + for comp in self.comps["object"]: # get incoming and outgoing connections of a component sources = self.conns[self.conns['source'] == comp] sources = sources['source_id'].sort_values().index.tolist() @@ -723,13 +738,14 @@ def init_components(self, comps): comp.outl = self.conns.loc[sources, 'object'].tolist() comp.num_i = len(comp.inlets()) comp.num_o = len(comp.outlets()) - labels += [comp.label] # save the connection locations to the components comp.conn_loc = [] for c in comp.inl + comp.outl: comp.conn_loc += [self.conns.index.get_loc(c.label)] + # set up restults and specification dataframes + comp_type = comp.__class__.__name__ if comp_type not in self.results: cols = [col for col, data in comp.variables.items() if isinstance(data, dc_cp)] @@ -751,18 +767,6 @@ def init_components(self, comps): 'properties': pd.DataFrame(columns=cols, dtype='bool') } - self.comps = self.comps.reset_index().set_index('label') - self.comps.rename(columns={'index': 'object'}, inplace=True) - - # check for duplicates in the component labels - if len(labels) != len(list(set(labels))): - duplicates = [ - item for item, count in Counter(labels).items() if count > 1] - msg = ('All Components must have unique labels, duplicate labels ' - 'are: "' + '", "'.join(duplicates) + '".') - logging.error(msg) - raise hlp.TESPyNetworkError(msg) - def initialise(self): r""" Initilialise the network depending on calclation mode. @@ -2627,9 +2631,12 @@ def print_results(self, colored=True, colors={}): if len(df) > 0: # printout with tabulate print('##### RESULTS (' + cp + ') #####') - print(tabulate( - df, headers='keys', tablefmt='psql', - floatfmt='.2e')) + print( + tabulate( + df, headers='keys', tablefmt='psql', + floatfmt='.2e' + ) + ) # connection properties df = self.results['Connection'].loc[:, ['m', 'p', 'h', 'T']] @@ -2648,7 +2655,8 @@ def print_results(self, colored=True, colors={}): if len(df) > 0: print('##### RESULTS (Connection) #####') print( - tabulate(df, headers='keys', tablefmt='psql', floatfmt='.3e')) + tabulate(df, headers='keys', tablefmt='psql', floatfmt='.3e') + ) for b in self.busses.values(): if b.printout: @@ -2661,8 +2669,12 @@ def print_results(self, colored=True, colors={}): coloring['set'] + str(df.loc['total', 'bus value']) + coloring['end']) print('##### RESULTS (Bus: ' + b.label + ') #####') - print(tabulate(df, headers='keys', tablefmt='psql', - floatfmt='.3e')) + print( + tabulate( + df, headers='keys', tablefmt='psql', + floatfmt='.3e' + ) + ) def print_components(self, c, *args): """ diff --git a/tests/test_errors.py b/tests/test_errors.py index b5a9419f8..58a516b7d 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -515,9 +515,8 @@ def test_component_label_duplicates(self): source = Source('label') sink = Sink('label') a = Connection(source, 'out1', sink, 'in1') - self.nw.add_conns(a) with raises(TESPyNetworkError): - self.nw.check_network() + self.nw.add_conns(a) def test_missing_offdesign_path(self): source = Source('source') diff --git a/tests/test_networks/test_network.py b/tests/test_networks/test_network.py index ab856c3dc..8078f2c20 100644 --- a/tests/test_networks/test_network.py +++ b/tests/test_networks/test_network.py @@ -253,6 +253,33 @@ def test_Network_missing_connection_in_design_path(self): shutil.rmtree('./tmp', ignore_errors=True) + def test_Network_get_comp_without_connections_added(self): + """Test if components are found prior to initialization.""" + self.setup_Network_tests() + pi = Pipe('pipe') + a = Connection(self.source, 'out1', pi, 'in1') + b = Connection(pi, 'out1', self.sink, 'in1') + self.nw.add_conns(a) + msg = ( + "A component with the label 'sink' has been created but must not " + "be part of the network as the respective connection has not " + "been added." + ) + assert self.nw.get_comp("sink") == None, msg + + def test_Network_get_comp_before_initialization(self): + """Test if components are found prior to initialization.""" + self.setup_Network_tests() + pi = Pipe('pipe') + a = Connection(self.source, 'out1', pi, 'in1') + b = Connection(pi, 'out1', self.sink, 'in1') + self.nw.add_conns(a, b) + msg = ( + "A component with the label 'pipe' is part of the network " + "and therefore must be found in the DataFrame." + ) + assert self.nw.get_comp("pipe") == pi, msg + class TestNetworkIndividualOffdesign: From 8e598ce3a9a4fd3611b18e99243a77f21db0a576 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 10:52:16 +0200 Subject: [PATCH 112/120] Update What's New --- docs/whats_new/v0-6-1.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/whats_new/v0-6-1.rst b/docs/whats_new/v0-6-1.rst index 5632686ad..c15f844c0 100644 --- a/docs/whats_new/v0-6-1.rst +++ b/docs/whats_new/v0-6-1.rst @@ -22,6 +22,14 @@ New Features :py:class:`tespy.connections.connection.Ref` class (`Discussion #352 `__). +Bug Fixes +######### +- The Network's component DataFrame is now available as soon as a connection + is added to the network. It is possible to use the + :py:meth:`tespy.networks.network.Network.get_comp` method prior to + initializing or solving + (`PR #361 `_). + Documentation ############# - Fix some typos in the online documentation From 2bad18d6861902281dd0aec26cab4b1c64c11a17 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 10:53:21 +0200 Subject: [PATCH 113/120] Fix typos --- docs/whats_new/v0-6-1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/whats_new/v0-6-1.rst b/docs/whats_new/v0-6-1.rst index c15f844c0..70e889fe6 100644 --- a/docs/whats_new/v0-6-1.rst +++ b/docs/whats_new/v0-6-1.rst @@ -28,7 +28,7 @@ Bug Fixes is added to the network. It is possible to use the :py:meth:`tespy.networks.network.Network.get_comp` method prior to initializing or solving - (`PR #361 `_). + (`PR #362 `_). Documentation ############# From 87b5c73c89c0ac0d5f3ee4be3ace15606113933f Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 10:59:51 +0200 Subject: [PATCH 114/120] Improve wording --- docs/tutorials/heat_pump_steps.rst | 18 +++++++++--------- tests/test_models/test_heat_pump_model.py | 6 +++--- tutorial/advanced/stepwise.py | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/tutorials/heat_pump_steps.rst b/docs/tutorials/heat_pump_steps.rst index 6814f8d33..9cbee94a7 100644 --- a/docs/tutorials/heat_pump_steps.rst +++ b/docs/tutorials/heat_pump_steps.rst @@ -45,10 +45,10 @@ container of the model and will be required in all following sections. First, it is necessary to specify a list of the fluids used in the plant. In this example we will work with water (H\ :sub:`2`\O) and ammonia (NH\ :sub:`3`\). Water is used for the cold side of the heat exchanger, for the consumer and -for the hot side of the environmental temperature. Ammonia is used as coolant -within the heat pump circuit. If you don’t specify the unit system, the -variables are set to SI-Units. We also keep the working fluid a variable to -make reusing the script with a different working fluid easy. +for the hot side of the environmental temperature. Ammonia is used as +refrigerant within the heat pump circuit. If you don’t specify the unit +system, the variables are set to SI-Units. We also keep the working fluid a +variable to make reusing the script with a different working fluid easy. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python @@ -86,7 +86,7 @@ first step, so the imports will not need further adjustment. .. tip:: - We label the sink for the coolant :code:`"valve"`, as for our next + We label the sink for the refrigerant :code:`"valve"`, as for our next calculation the valve will be attached there instead of the sink. In this way, the fluid properties can be initialized at the interface-connection, too. @@ -332,8 +332,8 @@ Components This part contains two compressors with intermittent cooling between them. The cold side of the heat exchanger will be connected to a pump upstream and to the superheater downstream. The bypass is used to give the system flexibility -in the temperature levels between the heat exchangers. We will also replac -the source for the coolant of :code:`c0` at the condenser with another +in the temperature levels between the heat exchangers. We will also replace +the source for the refrigerant of :code:`c0` at the condenser with another CycleCloser to make sure the fluid properties after the second compressor are identical to the fluid properties at the condenser's inlet. @@ -343,8 +343,8 @@ identical to the fluid properties at the condenser's inlet. however used to increase the evaporation pressure of the working fluid due to the higher temperature level of the heat source, the reduction is very limited. We use a two stage compressor, because in a single stage - compression, the outlet temperature of the coolant might violate technical - boundary conditions of the real-world component. + compression, the outlet temperature of the refrigerant might violate + technical boundary conditions of the real-world component. .. literalinclude:: /../tutorial/advanced/stepwise.py :language: python diff --git a/tests/test_models/test_heat_pump_model.py b/tests/test_models/test_heat_pump_model.py index 7bc582384..58e3ebd47 100644 --- a/tests/test_models/test_heat_pump_model.py +++ b/tests/test_models/test_heat_pump_model.py @@ -38,7 +38,7 @@ def setup(self): # %% components # sources & sinks - cc_coolant = CycleCloser('coolant cycle closer') + cc_refrigerant = CycleCloser('refrigerant cycle closer') cc_consumer = CycleCloser('consumer cycle closer') amb_in = Source('source ambient') amb_out = Sink('sink ambient') @@ -73,7 +73,7 @@ def setup(self): # %% connections # consumer system - c_in_cd = Connection(cc_coolant, 'out1', cd, 'in1') + c_in_cd = Connection(cc_refrigerant, 'out1', cd, 'in1') cb_rp = Connection(cc_consumer, 'out1', rp, 'in1') rp_cd = Connection(rp, 'out1', cd, 'in2') @@ -110,7 +110,7 @@ def setup(self): # compressor-system cp1_he = Connection(cp1, 'out1', he, 'in1') he_cp2 = Connection(he, 'out1', cp2, 'in1') - cp2_c_out = Connection(cp2, 'out1', cc_coolant, 'in1') + cp2_c_out = Connection(cp2, 'out1', cc_refrigerant, 'in1') ic_in_he = Connection(ic_in, 'out1', he, 'in2') he_ic_out = Connection(he, 'out2', ic_out, 'in1') diff --git a/tutorial/advanced/stepwise.py b/tutorial/advanced/stepwise.py index 7c850fe0d..ec64ea71b 100644 --- a/tutorial/advanced/stepwise.py +++ b/tutorial/advanced/stepwise.py @@ -15,7 +15,7 @@ from tespy.components import Source # sources & sinks -c_in = Source("coolant in") +c_in = Source("refrigerant in") cons_closer = CycleCloser("consumer cycle closer") va = Sink("valve") From 9ac0e53ad8f88685b8d46b02b575e4784f0bf5ad Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 11:03:14 +0200 Subject: [PATCH 115/120] Fix broken link --- docs/development/how.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/development/how.rst b/docs/development/how.rst index f7b1c388c..1d0647d3e 100644 --- a/docs/development/how.rst +++ b/docs/development/how.rst @@ -136,8 +136,8 @@ Docstrings ^^^^^^^^^^ We decided to use the style of the numpydoc docstrings. See the following -link for an -`example `_. +link for more information +`numpy docstrings `_. Code commenting From 1ab172f58f7db13af22d559a480106f11901ff63 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 11:05:12 +0200 Subject: [PATCH 116/120] Make checks work --- src/tespy/networks/network.py | 1 - tests/test_networks/test_network.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index c8108970f..1e71f5efe 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -17,7 +17,6 @@ import json import logging import os -from collections import Counter from collections import OrderedDict from time import time diff --git a/tests/test_networks/test_network.py b/tests/test_networks/test_network.py index 8078f2c20..cdfb519ad 100644 --- a/tests/test_networks/test_network.py +++ b/tests/test_networks/test_network.py @@ -258,14 +258,14 @@ def test_Network_get_comp_without_connections_added(self): self.setup_Network_tests() pi = Pipe('pipe') a = Connection(self.source, 'out1', pi, 'in1') - b = Connection(pi, 'out1', self.sink, 'in1') + Connection(pi, 'out1', self.sink, 'in1') self.nw.add_conns(a) msg = ( "A component with the label 'sink' has been created but must not " "be part of the network as the respective connection has not " "been added." ) - assert self.nw.get_comp("sink") == None, msg + assert self.nw.get_comp("sink") is None, msg def test_Network_get_comp_before_initialization(self): """Test if components are found prior to initialization.""" From 41d735c5336c24c44f19abee8ea8fa5723b366cc Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 11:13:21 +0200 Subject: [PATCH 117/120] Fix broken link --- docs/benchmarks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/benchmarks.rst b/docs/benchmarks.rst index d73ec5a4a..3d3f13852 100644 --- a/docs/benchmarks.rst +++ b/docs/benchmarks.rst @@ -27,7 +27,7 @@ The code for the full models is accessible open source on GitHub: - `So called "Solar Energy Generating System" `__ - `Supercritical CO2 power cycle `__ -- `Air refrigeration machine `__ +- `Air refrigeration machine `__ - `CGAM process `__ From f3ceebea72b4fe44e84eafa5b52271c288df1f64 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 11:17:33 +0200 Subject: [PATCH 118/120] Update Version and Release --- docs/whats_new/v0-6-1.rst | 4 ++-- setup.py | 2 +- src/tespy/__init__.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/whats_new/v0-6-1.rst b/docs/whats_new/v0-6-1.rst index 70e889fe6..59322fa20 100644 --- a/docs/whats_new/v0-6-1.rst +++ b/docs/whats_new/v0-6-1.rst @@ -1,5 +1,5 @@ -v0.6.1 - Upcoming features -++++++++++++++++++++++++++ +v0.6.1 - Leidenfrost's Library (October, 02, 2022) +++++++++++++++++++++++++++++++++++++++++++++++++++ We have completely revised the documentation improving the overall structure and introducing a modern look (`PR #355 `_). Have fun exploring the diff --git a/setup.py b/setup.py index dd1423e6c..45ee3a7d1 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ def read(*names, **kwargs): setup( name='TESPy', - version='0.6.1.dev0', + version='0.6.1', license='MIT', description='Thermal Engineering Systems in Python (TESPy)', long_description='%s' % ( diff --git a/src/tespy/__init__.py b/src/tespy/__init__.py index a4f0adfa3..590e30e16 100644 --- a/src/tespy/__init__.py +++ b/src/tespy/__init__.py @@ -2,7 +2,7 @@ from pkg_resources import resource_filename __datapath__ = resource_filename('tespy', 'data/') -__version__ = '0.6.1 - dev' +__version__ = '0.6.1 - Leidenfrost\'s Library' # tespy data and connections import from . import connections # noqa: F401 From 78834593ef23449d90a81347a81a052f8bf1e118 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 11:40:22 +0200 Subject: [PATCH 119/120] Fix broken link in README --- README.rst | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 5d1e70b7c..001eda200 100644 --- a/README.rst +++ b/README.rst @@ -146,12 +146,9 @@ Examples ======== For a short introduction on how TESPy works and how you can use it, we provide -some -`examples and tutorials `_, -go and check them out. You can download the python scripts of all example plants -from the -`tespy_examples `_ -repository. +an extensive `user guide `__. You can +download all python scripts of the examples and tutorials from this GitHub +repository. They are included in the "tutorial" directory. Citation ======== From c1cba5b49b96c6b543da99f6c8e0075bcde5d6f0 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 2 Oct 2022 14:30:11 +0200 Subject: [PATCH 120/120] Update version number --- setup.py | 2 +- src/tespy/__init__.py | 2 +- src/tespy/components/heat_exchangers/condenser.py | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 45ee3a7d1..759a98cf8 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ def read(*names, **kwargs): setup( name='TESPy', - version='0.6.1', + version='0.6.2.dev0', license='MIT', description='Thermal Engineering Systems in Python (TESPy)', long_description='%s' % ( diff --git a/src/tespy/__init__.py b/src/tespy/__init__.py index 590e30e16..199c19002 100644 --- a/src/tespy/__init__.py +++ b/src/tespy/__init__.py @@ -2,7 +2,7 @@ from pkg_resources import resource_filename __datapath__ = resource_filename('tespy', 'data/') -__version__ = '0.6.1 - Leidenfrost\'s Library' +__version__ = '0.6.2 - dev' # tespy data and connections import from . import connections # noqa: F401 diff --git a/src/tespy/components/heat_exchangers/condenser.py b/src/tespy/components/heat_exchangers/condenser.py index 2f21d36da..ae3fa2e05 100644 --- a/src/tespy/components/heat_exchangers/condenser.py +++ b/src/tespy/components/heat_exchangers/condenser.py @@ -161,15 +161,15 @@ class Condenser(HeatExchanger): >>> import shutil >>> nw = Network(fluids=['water', 'air'], T_unit='C', p_unit='bar', ... h_unit='kJ / kg', m_range=[0.01, 1000], iterinfo=False) - >>> amb_in = Sink('ambient air inlet') - >>> amb_out = Source('air outlet') + >>> amb_in = Source('ambient air inlet') + >>> amb_out = Sink('air outlet') >>> waste_steam = Source('waste steam') >>> c = Sink('condensate sink') >>> cond = Condenser('condenser') >>> cond.component() 'condenser' - >>> amb_he = Connection(amb_out, 'out1', cond, 'in2') - >>> he_amb = Connection(cond, 'out2', amb_in, 'in1') + >>> amb_he = Connection(amb_in, 'out1', cond, 'in2') + >>> he_amb = Connection(cond, 'out2', amb_out, 'in1') >>> ws_he = Connection(waste_steam, 'out1', cond, 'in1') >>> he_c = Connection(cond, 'out1', c, 'in1') >>> nw.add_conns(amb_he, he_amb, ws_he, he_c)