diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6a40ad8fe..30a659782 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -85,7 +85,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install pytest python-igraph pytest-split + python -m pip install pytest igraph pytest-split if ${{ matrix.python-version != '3.11' }}; then python -m pip install numba; fi - name: Install pandapipes from TestPyPI if: ${{ inputs.upload_server == 'testpypi'}} diff --git a/.github/workflows/run_tests_develop.yml b/.github/workflows/run_tests_develop.yml index 43c2877b0..a172d407a 100644 --- a/.github/workflows/run_tests_develop.yml +++ b/.github/workflows/run_tests_develop.yml @@ -28,7 +28,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install pytest python-igraph pytest-split + python -m pip install pytest igraph pytest-split if ${{ matrix.python-version != '3.11' }}; then python -m pip install numba; fi if [ -f requirements.txt ]; then pip install -r requirements.txt; fi python -m pip install git+https://github.com/e2nIEE/pandapower@develop#egg=pandapower @@ -97,7 +97,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install pytest nbmake pytest-xdist pytest-split python-igraph + python -m pip install pytest nbmake pytest-xdist pytest-split igraph if ${{ matrix.python-version != '3.11' }}; then python -m pip install numba; fi if [ -f requirements.txt ]; then pip install -r requirements.txt; fi python -m pip install git+https://github.com/e2nIEE/pandapower@develop#egg=pandapower diff --git a/.github/workflows/run_tests_master.yml b/.github/workflows/run_tests_master.yml index 3561b3719..ad856db14 100644 --- a/.github/workflows/run_tests_master.yml +++ b/.github/workflows/run_tests_master.yml @@ -28,10 +28,10 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install pytest python-igraph pytest-split + python -m pip install pytest igraph pytest-split if ${{ matrix.python-version != '3.11' }}; then python -m pip install numba; fi if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - python -m pip install git+https://github.com/e2nIEE/pandapower@master#egg=pandapower + python -m pip install git+https://github.com/e2nIEE/pandapower@master#egg=pandapower; pip install . - name: List all installed packages run: | @@ -65,7 +65,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install pytest nbmake pytest-xdist pytest-split python-igraph + python -m pip install pytest nbmake pytest-xdist pytest-split igraph if ${{ matrix.python-version != '3.11' }}; then python -m pip install numba; fi if [ -f requirements.txt ]; then pip install -r requirements.txt; fi python -m pip install git+https://github.com/e2nIEE/pandapower@master#egg=pandapower diff --git a/.readthedocs.yml b/.readthedocs.yml index 9fcbb7ac8..b6911a40a 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,9 +1,10 @@ version: 2 +build: + os: ubuntu-22.04 + tools: + python: "3.9" + python: - version: 3.7 install: - - method: pip - path: . - extra_requirements: - - docs + - requirements: doc/requirements.txt \ No newline at end of file diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 903afc7ed..58ff9bc6f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,20 @@ Change Log - [ADDED] multiple creation of heat exchanger - [ADDED] support Python 3.11 (now included in test pipeline) - [CHANGED] dropped support for Python 3.7 (no longer included in test pipeline) +- [CHANGED] connectivity check now separated by hydraulics and heat_transfer calculation, so that also results can differ in some rows (NaN or not) +- [CHANGED] dynamic creation of lookups for getting pit as pandas tables +- [CHANGED] components can have their own internal arrays for specific calculations (e.g. for compressor pressure ratio), so that the pit does not need to include such component specific entries +- [CHANGED] .readthedocs.yml due to deprecation +- [FIXED] in STANET converter: bug fix for heat exchanger creation and external temperatures of pipes added +- [REMOVED] broken travis badge removed from readme + +[0.8.5] - 2023-06-19 +------------------------------- +- [FIXED] consider ambient pressure in calculation of compression power for pumps/compressors +- [FIXED] np.bool error in pipeflow calculation due to deprecation of np.bool +- [FIXED] use igraph package instead of python-igraph (has been renamed) +- [ADDED] gas specific calculation of heat capacity ration kappa = cp/cv (for pumps/compressors) +- [REMOVED] Python 3.7 removed from test pipeline due to inconsistencies with pandapower [0.8.4] - 2023-02-02 ------------------------------- diff --git a/README.rst b/README.rst index 361db9b26..6a3886497 100644 --- a/README.rst +++ b/README.rst @@ -18,10 +18,6 @@ :target: http://pandapipes.readthedocs.io/ :alt: docs -.. image:: https://travis-ci.org/e2nIEE/pandapipes.svg?branch=master - :target: https://travis-ci.org/e2nIEE/pandapipes/branches - :alt: travis - .. image:: https://codecov.io/gh/e2nIEE/pandapipes/branch/master/graph/badge.svg :target: https://codecov.io/github/e2nIEE/pandapipes?branch=master :alt: codecov diff --git a/doc/source/about/license.rst b/doc/source/about/license.rst index ee323bc74..cc6c655d9 100644 --- a/doc/source/about/license.rst +++ b/doc/source/about/license.rst @@ -7,32 +7,7 @@ License .. highlight:: none -pandapipes is published under the following 3-clause BSD license: :: +pandapipes is published under the following 3-clause BSD license: - - Copyright (c) 2020-2023 by Fraunhofer Institute for Energy Economics and - Energy System Technology (IEE) Kassel and individual contributors - (see AUTHORS file for details). All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted - provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions - and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of - conditions and the following disclaimer in the documentation and/or other materials provided - with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to - endorse or promote products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY - WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + .. literalinclude:: ../../../LICENSE diff --git a/doc/source/conf.py b/doc/source/conf.py index 06c4067f9..5738f187f 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -49,7 +49,7 @@ # The short X.Y version. version = "0.8" # The full version, including alpha/beta/rc tags. -release = "0.8.4" +release = "0.8.5" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/fluid_properties/composition.csv b/doc/source/fluid_properties/composition.csv new file mode 100644 index 000000000..6f88aa3f0 --- /dev/null +++ b/doc/source/fluid_properties/composition.csv @@ -0,0 +1,9 @@ +;**Biomethane pure**;**Biomethane treated** +methane; 96.15% ; 90.94% +nitrogen; 0.75 % ;0.69 % +carbon dioxide; 2.9 % ;2.68 % +oxygen; 0.2 % ; 0.19 % +propane; 0 % ; 5 % +butane; 0 %; 0.5 % +Wobbe-Index (normal conditions) :math:`[\frac{KWh}{m^3}]` ; 13.9 ; 14.9 +HHV (normal conditions) :math:`[\frac{KWh}{m^3}]`; 10.6 ; 11.6 \ No newline at end of file diff --git a/doc/source/fluid_properties/create_fluids.rst b/doc/source/fluid_properties/create_fluids.rst index 3c5dd9d88..ec2fbd1b7 100644 --- a/doc/source/fluid_properties/create_fluids.rst +++ b/doc/source/fluid_properties/create_fluids.rst @@ -10,8 +10,16 @@ Fluid from Library ================== In the fluid library some default fluids are already implemented. Currently it is -possible to work with the default fluids high and low calorific natural -gas (hgas and lgas), hydrogen, methane, water and air. The values are loaded from txt-files in +possible to work with the default fluids: + +- ``hgas`` and ``lgas`` (high and low calorific natural gas), +- ``hydrogen``, +- ``methane``, +- ``water``, +- ``biomethane_pure`` and ``biomathane_treated`` (see `here `_ for the compositions), +- ``air``. + +The values are loaded from txt-files in the 'pandapipes/properties/[fluid name]' folder. One of these default fluids can be created and added to an existing network by calling the following function. diff --git a/doc/source/fluid_properties/fluids.rst b/doc/source/fluid_properties/fluids.rst index 2689b0049..d3e63a038 100644 --- a/doc/source/fluid_properties/fluids.rst +++ b/doc/source/fluid_properties/fluids.rst @@ -4,9 +4,29 @@ Fluid Properties in pandapipes The pipelines in the pandapipes network are run with a certain fluid. This can be chosen individually for the net from the fluid library or by own creation. The fluids -are defined by certain properties. In the fluid library currently high and low calorific natural -gas (hgas and lgas), hydrogen, methane, water and air are implemented with default properties. +are defined by certain properties. +The following fluids currently exist in the library: + +- ``hgas`` and ``lgas`` (high and low calorific natural gas), +- ``hydrogen``, +- ``methane``, +- ``water``, +- ``biomethane_pure`` and ``biomathane_treated`` (compositions below) +- ``air``. + + +.. Note:: + **Biomethane(s)**: + A particularity of injecting biomethane in the gas grid in Germany is the addition of LPG to enhance + the Wobbe-Index and the heating value of the gas and thus make it equivalent to the (high-calorific) natural gas transported + in the grid. This addition is done in a gas treatment unit (Biogaseinspeiseanlage) upstream of the biomethane + feed-in junction. The properties of the biomethane(s) were computed based on the package `CoolProp `_. + + .. csv-table:: + :file: composition.csv + :delim: ; + :widths: 10, 10, 10 The Fluid Class =============== diff --git a/pandapipes/__init__.py b/pandapipes/__init__.py index 007e04dc9..371d6941b 100644 --- a/pandapipes/__init__.py +++ b/pandapipes/__init__.py @@ -2,7 +2,7 @@ # and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved. # Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. -__version__ = '0.8.4' +__version__ = '0.8.5' __format_version__ = '0.8.0' import pandas as pd diff --git a/pandapipes/component_models/abstract_models/base_component.py b/pandapipes/component_models/abstract_models/base_component.py index cdfb0f091..105035f3d 100644 --- a/pandapipes/component_models/abstract_models/base_component.py +++ b/pandapipes/component_models/abstract_models/base_component.py @@ -33,7 +33,7 @@ def init_results(cls, net): return res_table @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): """ Function that extracts certain results. @@ -43,10 +43,8 @@ def extract_results(cls, net, options, branch_results, nodes_connected, branches :type options: :param branch_results: :type branch_results: - :param nodes_connected: - :type nodes_connected: - :param branches_connected: - :type branches_connected: + :param mode: + :type mode: :return: No Output. """ raise NotImplementedError @@ -80,6 +78,15 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo def adaption_after_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): pass + @classmethod + def adaption_before_derivatives_thermal(cls, net, branch_pit, node_pit, idx_lookups, options): + pass + + @classmethod + def adaption_after_derivatives_thermal(cls, net, branch_pit, node_pit, idx_lookups, options): + pass + + @classmethod def create_node_lookups(cls, net, ft_lookups, table_lookup, idx_lookups, current_start, current_table, internal_nodes_lookup): @@ -128,65 +135,43 @@ def create_branch_lookups(cls, net, ft_lookups, table_lookup, idx_lookups, curre return current_start, current_table @classmethod - def create_pit_node_entries(cls, net, node_pit): + def create_component_array(cls, net, component_pits): """ - Function which creates pit branch entries. + Function which creates an internal array of the component in analogy to the pit, but with + component specific entries, that are not needed in the pit. :param net: The pandapipes network :type net: pandapipesNet - :param node_pit: - :type node_pit: - :return: No Output. + :param component_pits: dictionary of component specific arrays + :type component_pits: dict + :return: + :rtype: """ pass @classmethod - def create_pit_branch_entries(cls, net, branch_pit): + def create_pit_node_entries(cls, net, node_pit): """ Function which creates pit branch entries. :param net: The pandapipes network :type net: pandapipesNet - :param branch_pit: - :type branch_pit: - :return: No Output. - """ - pass - - @classmethod - def calculate_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): - """ - Function which creates derivatives. - - :param net: The pandapipes network - :type net: pandapipesNet - :param branch_pit: - :type branch_pit: :param node_pit: :type node_pit: - :param idx_lookups: - :type idx_lookups: - :param options: - :type options: :return: No Output. """ pass @classmethod - def calculate_derivatives_thermal(cls, net, branch_pit, node_pit, idx_lookups, options): + def create_pit_branch_entries(cls, net, branch_pit): """ - Function which creates derivatives. + Function which creates pit branch entries. :param net: The pandapipes network :type net: pandapipesNet :param branch_pit: :type branch_pit: - :param node_pit: - :type node_pit: - :param idx_lookups: - :type idx_lookups: - :param options: - :type options: :return: No Output. """ pass + diff --git a/pandapipes/component_models/abstract_models/branch_models.py b/pandapipes/component_models/abstract_models/branch_models.py index c79e9f170..f9d98d6e8 100644 --- a/pandapipes/component_models/abstract_models/branch_models.py +++ b/pandapipes/component_models/abstract_models/branch_models.py @@ -5,12 +5,8 @@ import numpy as np from pandapipes.component_models.abstract_models.base_component import Component -from pandapipes.idx_branch import LENGTH, D, AREA, RHO, VINIT, ALPHA, QEXT, TEXT, branch_cols, \ - T_OUT, CP, VINIT_T, FROM_NODE_T, TL, JAC_DERIV_DT, JAC_DERIV_DT1, JAC_DERIV_DT_NODE, \ - LOAD_VEC_BRANCHES_T, LOAD_VEC_NODES_T -from pandapipes.idx_branch import T_OUT_OLD -from pandapipes.idx_node import TINIT as TINIT_NODE -from pandapipes.pf.pipeflow_setup import get_table_number, get_lookup, get_net_option +from pandapipes.idx_branch import VINIT, branch_cols +from pandapipes.pf.pipeflow_setup import get_table_number, get_lookup try: import pandaplan.core.pplog as logging @@ -96,84 +92,5 @@ def create_pit_branch_entries(cls, net, branch_pit): return branch_component_pit, node_pit, from_nodes, to_nodes @classmethod - def calculate_derivatives_thermal(cls, net, branch_pit, node_pit, idx_lookups, options): - """ - Function which creates derivatives of the temperature. - - :param net: - :type net: - :param branch_pit: - :type branch_pit: - :param node_pit: - :type node_pit: - :param idx_lookups: - :type idx_lookups: - :param options: - :type options: - :return: No Output. - """ - f, t = idx_lookups[cls.table_name()] - branch_component_pit = branch_pit[f:t, :] - cp = branch_component_pit[:, CP] - rho = branch_component_pit[:, RHO] - v_init = branch_component_pit[:, VINIT_T] - from_nodes = branch_component_pit[:, FROM_NODE_T].astype(np.int32) - t_init_i = node_pit[from_nodes, TINIT_NODE] - t_init_i1 = branch_component_pit[:, T_OUT] - t_amb = branch_component_pit[:, TEXT] - area = branch_component_pit[:, AREA] - length = branch_component_pit[:, LENGTH] - alpha = branch_component_pit[:, ALPHA] * np.pi * branch_component_pit[:, D] * length - cls.calculate_temperature_lift(net, branch_component_pit, node_pit) - tl = branch_component_pit[:, TL] - qext = branch_component_pit[:, QEXT] - spec_heat = rho * area * cp - - if get_net_option(net, "transient"): - tvor = branch_component_pit[:, T_OUT_OLD] - delta_t = get_net_option(net, "dt") - - branch_component_pit[:, LOAD_VEC_BRANCHES_T] = \ - -(spec_heat * (t_init_i1 - tvor) * (1 / delta_t) * length - + spec_heat * v_init * (-t_init_i + t_init_i1 - tl) - - alpha * (t_amb - t_init_i1) + qext) - - branch_component_pit[:, JAC_DERIV_DT] = - spec_heat * v_init - branch_component_pit[:, JAC_DERIV_DT1] = spec_heat / delta_t * length \ - + spec_heat * v_init + alpha - - else: - t_m = (t_init_i1 + t_init_i) / 2 - branch_component_pit[:, LOAD_VEC_BRANCHES_T] = \ - -(spec_heat * v_init * (-t_init_i + t_init_i1 - tl) - - alpha * (t_amb - t_m) + qext) - - branch_component_pit[:, JAC_DERIV_DT] = - spec_heat * v_init + alpha / 2 - branch_component_pit[:, JAC_DERIV_DT1] = spec_heat * v_init + alpha / 2 - - branch_component_pit[:, JAC_DERIV_DT_NODE] = rho * v_init * branch_component_pit[:, AREA] - branch_component_pit[:, LOAD_VEC_NODES_T] = rho * v_init \ - * branch_component_pit[:, AREA] * t_init_i1 - - @classmethod - def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): - pass - - @classmethod - def calculate_temperature_lift(cls, net, branch_component_pit, node_pit): - """ - - :param net: - :type net: - :param branch_component_pit: - :type branch_component_pit: - :param node_pit: - :type node_pit: - :return: - :rtype: - """ - raise NotImplementedError - - @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): raise NotImplementedError diff --git a/pandapipes/component_models/abstract_models/branch_w_internals_models.py b/pandapipes/component_models/abstract_models/branch_w_internals_models.py index 6861223ee..0478254a9 100644 --- a/pandapipes/component_models/abstract_models/branch_w_internals_models.py +++ b/pandapipes/component_models/abstract_models/branch_w_internals_models.py @@ -6,7 +6,7 @@ from pandapipes.component_models.abstract_models.branch_models import BranchComponent from pandapipes.component_models.component_toolbox import set_entry_check_repeat -from pandapipes.idx_branch import ACTIVE, FROM_NODE, TO_NODE, TINIT, RHO, ETA, CP, ELEMENT_IDX +from pandapipes.idx_branch import ACTIVE, FROM_NODE, TO_NODE, RHO, ETA, CP, ELEMENT_IDX, TOUTINIT from pandapipes.idx_node import L, node_cols, TINIT as TINIT_NODE from pandapipes.pf.pipeflow_setup import add_table_lookup, get_lookup, get_table_number from pandapipes.properties.fluids import get_fluid @@ -196,13 +196,12 @@ def create_pit_branch_entries(cls, net, branch_pit): internal_pipe_number, has_internals) branch_w_internals_pit[:, FROM_NODE] = from_nodes branch_w_internals_pit[:, TO_NODE] = to_nodes - branch_w_internals_pit[:, TINIT] = (node_pit[from_nodes, TINIT_NODE] + node_pit[ - to_nodes, TINIT_NODE]) / 2 + branch_w_internals_pit[:, TOUTINIT] = node_pit[to_nodes, TINIT_NODE] + tm = (node_pit[from_nodes, TINIT_NODE] + branch_w_internals_pit[:, TOUTINIT]) / 2 fluid = get_fluid(net) - branch_w_internals_pit[:, RHO] = fluid.get_density(branch_w_internals_pit[:, TINIT]) - branch_w_internals_pit[:, ETA] = fluid.get_viscosity(branch_w_internals_pit[:, TINIT]) - branch_w_internals_pit[:, CP] = fluid.get_heat_capacity(branch_w_internals_pit[:, TINIT]) - + branch_w_internals_pit[:, RHO] = fluid.get_density(tm) + branch_w_internals_pit[:, ETA] = fluid.get_viscosity(tm) + branch_w_internals_pit[:, CP] = fluid.get_heat_capacity(tm) return branch_w_internals_pit, internal_pipe_number @classmethod @@ -217,7 +216,7 @@ def get_internal_pipe_number(cls, net): return np.array(net[cls.table_name()].sections.values) @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): raise NotImplementedError @classmethod diff --git a/pandapipes/component_models/abstract_models/branch_wo_internals_models.py b/pandapipes/component_models/abstract_models/branch_wo_internals_models.py index 0efa325a9..2867c241b 100644 --- a/pandapipes/component_models/abstract_models/branch_wo_internals_models.py +++ b/pandapipes/component_models/abstract_models/branch_wo_internals_models.py @@ -4,7 +4,7 @@ from pandapipes.component_models.abstract_models.branch_models import BranchComponent -from pandapipes.idx_branch import FROM_NODE, TO_NODE, TINIT, ELEMENT_IDX, RHO, ETA, CP, ACTIVE +from pandapipes.idx_branch import FROM_NODE, TO_NODE, TOUTINIT, ELEMENT_IDX, RHO, ETA, CP, ACTIVE from pandapipes.idx_node import TINIT as TINIT_NODE from pandapipes.pf.pipeflow_setup import add_table_lookup @@ -82,12 +82,12 @@ def create_pit_branch_entries(cls, net, branch_pit): branch_wo_internals_pit[:, ELEMENT_IDX] = net[cls.table_name()].index.values branch_wo_internals_pit[:, FROM_NODE] = from_nodes branch_wo_internals_pit[:, TO_NODE] = to_nodes - branch_wo_internals_pit[:, TINIT] = (node_pit[from_nodes, TINIT_NODE] - + node_pit[to_nodes, TINIT_NODE]) / 2 + branch_wo_internals_pit[:, TOUTINIT] = node_pit[to_nodes, TINIT_NODE] + tm = (node_pit[from_nodes, TINIT_NODE] + branch_wo_internals_pit[:, TOUTINIT]) / 2 fluid = get_fluid(net) - branch_wo_internals_pit[:, RHO] = fluid.get_density(branch_wo_internals_pit[:, TINIT]) - branch_wo_internals_pit[:, ETA] = fluid.get_viscosity(branch_wo_internals_pit[:, TINIT]) - branch_wo_internals_pit[:, CP] = fluid.get_heat_capacity(branch_wo_internals_pit[:, TINIT]) + branch_wo_internals_pit[:, RHO] = fluid.get_density(tm) + branch_wo_internals_pit[:, ETA] = fluid.get_viscosity(tm) + branch_wo_internals_pit[:, CP] = fluid.get_heat_capacity(tm) branch_wo_internals_pit[:, ACTIVE] = net[cls.table_name()][cls.active_identifier()].values return branch_wo_internals_pit @@ -100,5 +100,5 @@ def get_connected_node_type(cls): raise NotImplementedError @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): raise NotImplementedError diff --git a/pandapipes/component_models/abstract_models/branch_wzerolength_models.py b/pandapipes/component_models/abstract_models/branch_wzerolength_models.py index dc224f8a1..b9da3028f 100644 --- a/pandapipes/component_models/abstract_models/branch_wzerolength_models.py +++ b/pandapipes/component_models/abstract_models/branch_wzerolength_models.py @@ -61,7 +61,7 @@ def create_pit_branch_entries(cls, net, branch_pit): return branch_wzerolength_pit @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): raise NotImplementedError @classmethod diff --git a/pandapipes/component_models/abstract_models/circulation_pump.py b/pandapipes/component_models/abstract_models/circulation_pump.py index 3e4cb5e54..1a22abfc3 100644 --- a/pandapipes/component_models/abstract_models/circulation_pump.py +++ b/pandapipes/component_models/abstract_models/circulation_pump.py @@ -95,18 +95,12 @@ def create_pit_branch_entries(cls, net, branch_pit): return circ_pump_pit @classmethod - def calculate_temperature_lift(cls, net, pipe_pit, node_pit): - raise NotImplementedError - - @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): """ Function that extracts certain results. - :param nodes_connected: - :type nodes_connected: - :param branches_connected: - :type branches_connected: + :param mode: + :type mode: :param branch_results: :type branch_results: :param net: The pandapipes network diff --git a/pandapipes/component_models/abstract_models/const_flow_models.py b/pandapipes/component_models/abstract_models/const_flow_models.py index c49a58ec4..a10a4d0e4 100644 --- a/pandapipes/component_models/abstract_models/const_flow_models.py +++ b/pandapipes/component_models/abstract_models/const_flow_models.py @@ -51,14 +51,12 @@ def create_pit_node_entries(cls, net, node_pit): node_pit[index, LOAD] += loads_sum @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): """ Function that extracts certain results. - :param nodes_connected: - :type nodes_connected: - :param branches_connected: - :type branches_connected: + :param mode: + :type mode: :param branch_results: :type branch_results: :param net: The pandapipes network @@ -74,8 +72,8 @@ def extract_results(cls, net, options, branch_results, nodes_connected, branches is_loads = loads.in_service.values fj, tj = get_lookup(net, "node", "from_to")[cls.get_connected_node_type().table_name()] junct_pit = net["_pit"]["node"][fj:tj, :] - nodes_connected = get_lookup(net, "node", "active")[fj:tj] - is_juncts = np.isin(loads.junction.values, junct_pit[nodes_connected, ELEMENT_IDX]) + nodes_connected_hyd = get_lookup(net, "node", "active_hydraulics")[fj:tj] + is_juncts = np.isin(loads.junction.values, junct_pit[nodes_connected_hyd, ELEMENT_IDX]) is_calc = is_loads & is_juncts res_table["mdot_kg_per_s"].values[is_calc] = loads.mdot_kg_per_s.values[is_calc] \ diff --git a/pandapipes/component_models/abstract_models/node_element_models.py b/pandapipes/component_models/abstract_models/node_element_models.py index 04e594e2d..0792fa531 100644 --- a/pandapipes/component_models/abstract_models/node_element_models.py +++ b/pandapipes/component_models/abstract_models/node_element_models.py @@ -51,5 +51,5 @@ def create_pit_node_entries(cls, net, node_pit): raise NotImplementedError @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): raise NotImplementedError diff --git a/pandapipes/component_models/abstract_models/node_models.py b/pandapipes/component_models/abstract_models/node_models.py index 5a917bef9..0ce18e4a9 100644 --- a/pandapipes/component_models/abstract_models/node_models.py +++ b/pandapipes/component_models/abstract_models/node_models.py @@ -66,5 +66,5 @@ def get_result_table(cls, net): raise NotImplementedError @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): raise NotImplementedError diff --git a/pandapipes/component_models/circulation_pump_mass_component.py b/pandapipes/component_models/circulation_pump_mass_component.py index d18e299d3..699d1e416 100644 --- a/pandapipes/component_models/circulation_pump_mass_component.py +++ b/pandapipes/component_models/circulation_pump_mass_component.py @@ -72,6 +72,3 @@ def create_pit_node_entries(cls, net, node_pit): index = junction_idx_lookups[juncts] node_pit[index, LOAD] += loads_sum - @classmethod - def calculate_temperature_lift(cls, net, pipe_pit, node_pit): - pass diff --git a/pandapipes/component_models/circulation_pump_pressure_component.py b/pandapipes/component_models/circulation_pump_pressure_component.py index 8a63d984f..6cfbf2eb9 100644 --- a/pandapipes/component_models/circulation_pump_pressure_component.py +++ b/pandapipes/component_models/circulation_pump_pressure_component.py @@ -63,10 +63,3 @@ def create_pit_node_entries(cls, net, node_pit): p_in = press - circ_pump.plift_bar.values set_fixed_node_entries(net, node_pit, junction, circ_pump.type.values, p_in, None, cls.get_connected_node_type(), "p") - - - - - @classmethod - def calculate_temperature_lift(cls, net, pipe_pit, node_pit): - pass diff --git a/pandapipes/component_models/component_toolbox.py b/pandapipes/component_models/component_toolbox.py index 62c99fd82..b9e7cff54 100644 --- a/pandapipes/component_models/component_toolbox.py +++ b/pandapipes/component_models/component_toolbox.py @@ -5,6 +5,7 @@ import numpy as np import pandas as pd +from pandapipes import get_fluid from pandapipes.constants import NORMAL_PRESSURE, TEMP_GRADIENT_KPM, AVG_TEMPERATURE_K, \ HEIGHT_EXPONENT from pandapipes.idx_branch import LOAD_VEC_NODES, FROM_NODE, TO_NODE @@ -197,3 +198,45 @@ def get_mass_flow_at_nodes(net, node_pit, branch_pit, eg_nodes, comp): raise UserWarning("In component %s: Something went wrong with the mass flow balance. " "Please report this error at github." % comp.__name__) return sum_mass_flows, inverse_nodes, counts + + +def standard_branch_wo_internals_result_lookup(net): + required_results_hyd = [ + ("p_from_bar", "p_from"), ("p_to_bar", "p_to"), ("mdot_to_kg_per_s", "mf_to"), + ("mdot_from_kg_per_s", "mf_from"), ("vdot_norm_m3_per_s", "vf"), ("lambda", "lambda"), + ("reynolds", "reynolds") + ] + required_results_ht = [("t_from_k", "temp_from"), ("t_to_k", "temp_to")] + + if get_fluid(net).is_gas: + required_results_hyd.extend([ + ("v_from_m_per_s", "v_gas_from"), ("v_to_m_per_s", "v_gas_to"), + ("v_mean_m_per_s", "v_gas_mean"), ("normfactor_from", "normfactor_from"), + ("normfactor_to", "normfactor_to") + ]) + else: + required_results_hyd.extend([("v_mean_m_per_s", "v_mps")]) + + return required_results_hyd, required_results_ht + + +def get_component_array(net, component_name, component_type="branch", only_active=True): + """ + Returns the internal array of a component. + + :param net: The pandapipes network + :type net: pandapipesNet + :param component_name: Table name of the component for which to extract internal array + :type component_name: str + :param component_type: Type of component that is considered ("branch" or "node") + :type component_type: str, default "branch" + :param only_active: If True, only return entries of active elements (included in _active_pit) + :type only_active: bool + :return: component_array - internal array of the component + :rtype: numpy.ndarray + """ + f_all, t_all = get_lookup(net, component_type, "from_to")[component_name] + if not only_active: + return net["_pit"]["components"][component_name] + in_service_elm = get_lookup(net, component_type, "active_hydraulics")[f_all:t_all] + return net["_pit"]["components"][component_name][in_service_elm] diff --git a/pandapipes/component_models/compressor_component.py b/pandapipes/component_models/compressor_component.py index 7c09300ae..d9d5e8113 100644 --- a/pandapipes/component_models/compressor_component.py +++ b/pandapipes/component_models/compressor_component.py @@ -5,10 +5,10 @@ import numpy as np from numpy import dtype +from pandapipes.component_models.component_toolbox import get_component_array from pandapipes.component_models.junction_component import Junction from pandapipes.component_models.pump_component import Pump -from pandapipes.idx_branch import VINIT, D, AREA, LOSS_COEFFICIENT as LC, FROM_NODE, PL,\ - PRESSURE_RATIO +from pandapipes.idx_branch import VINIT, D, AREA, LOSS_COEFFICIENT as LC, FROM_NODE, PL from pandapipes.idx_node import PINIT, PAMB @@ -16,6 +16,9 @@ class Compressor(Pump): """ """ + PRESSURE_RATIO = 0 + + internal_cols = 1 @classmethod def table_name(cls): @@ -41,23 +44,42 @@ def create_pit_branch_entries(cls, net, branch_pit): compressor_pit[:, D] = 0.1 compressor_pit[:, AREA] = compressor_pit[:, D] ** 2 * np.pi / 4 compressor_pit[:, LC] = 0 - compressor_pit[:, PRESSURE_RATIO] = net[cls.table_name()].pressure_ratio.values + + @classmethod + def create_component_array(cls, net, component_pits): + """ + Function which creates an internal array of the component in analogy to the pit, but with + component specific entries, that are not needed in the pit. + + :param net: The pandapipes network + :type net: pandapipesNet + :param component_pits: dictionary of component specific arrays + :type component_pits: dict + :return: + :rtype: + """ + tbl = net[cls.table_name()] + compr_array = np.zeros(shape=(len(tbl), cls.internal_cols), dtype=np.float64) + compr_array[:, cls.PRESSURE_RATIO] = net[cls.table_name()].pressure_ratio.values + component_pits[cls.table_name()] = compr_array @classmethod def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): # calculation of pressure lift f, t = idx_lookups[cls.table_name()] - compressor_pit = branch_pit[f:t, :] + compressor_branch_pit = branch_pit[f:t, :] + compressor_array = get_component_array(net, cls.table_name()) - from_nodes = compressor_pit[:, FROM_NODE].astype(np.int32) + from_nodes = compressor_branch_pit[:, FROM_NODE].astype(np.int32) p_from = node_pit[from_nodes, PAMB] + node_pit[from_nodes, PINIT] - p_to_calc = p_from * compressor_pit[:, PRESSURE_RATIO] + + p_to_calc = p_from * compressor_array[:, cls.PRESSURE_RATIO] pl_abs = p_to_calc - p_from - v_mps = compressor_pit[:, VINIT] + v_mps = compressor_branch_pit[:, VINIT] pl_abs[v_mps < 0] = 0 # force pressure lift = 0 for reverse flow - compressor_pit[:, PL] = pl_abs + compressor_branch_pit[:, PL] = pl_abs @classmethod def get_component_input(cls): diff --git a/pandapipes/component_models/dynamic_circulation_pump_component.py b/pandapipes/component_models/dynamic_circulation_pump_component.py index 7820de3a4..93fa1150e 100644 --- a/pandapipes/component_models/dynamic_circulation_pump_component.py +++ b/pandapipes/component_models/dynamic_circulation_pump_component.py @@ -2,23 +2,20 @@ # and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved. # Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. +from operator import itemgetter + import numpy as np from numpy import dtype -from operator import itemgetter -from pandapipes.component_models.junction_component import Junction + from pandapipes.component_models.abstract_models.circulation_pump import CirculationPump -from pandapipes.component_models.component_toolbox import set_fixed_node_entries, update_fixed_node_entries -from pandapipes.idx_node import PINIT, NODE_TYPE, P, EXT_GRID_OCCURENCE -from pandapipes.pf.pipeflow_setup import get_lookup, get_net_option -from pandapipes.idx_branch import STD_TYPE, VINIT, D, AREA, ACTIVE, LOSS_COEFFICIENT as LC, FROM_NODE, \ - TINIT, PL, ACTUAL_POS, DESIRED_MV, RHO, TO_NODE, JAC_DERIV_DP, JAC_DERIV_DP1, JAC_DERIV_DV, LOAD_VEC_BRANCHES -from pandapipes.idx_node import PINIT, PAMB, TINIT as TINIT_NODE, HEIGHT, RHO as RHO_node -from pandapipes.constants import NORMAL_TEMPERATURE, NORMAL_PRESSURE, P_CONVERSION, GRAVITATION_CONSTANT -from pandapipes.properties.fluids import get_fluid -from pandapipes.component_models.component_toolbox import p_correction_height_air from pandapipes.component_models.component_toolbox import set_fixed_node_entries, \ get_mass_flow_at_nodes -from pandapipes.pf.result_extraction import extract_branch_results_without_internals +from pandapipes.component_models.component_toolbox import update_fixed_node_entries +from pandapipes.component_models.junction_component import Junction +from pandapipes.constants import P_CONVERSION, GRAVITATION_CONSTANT +from pandapipes.idx_branch import ACTIVE, TOUTINIT +from pandapipes.idx_node import PINIT, TINIT as TINIT_NODE, RHO as RHO_node +from pandapipes.pf.pipeflow_setup import get_lookup, get_net_option try: import pandaplan.core.pplog as logging @@ -29,7 +26,6 @@ class DynamicCirculationPump(CirculationPump): - # class attributes kwargs = None prev_act_pos = None @@ -67,7 +63,6 @@ def create_pit_node_entries(cls, net, node_pit): set_fixed_node_entries(net, node_pit, junction, dyn_circ_pump.type.values, p_in, None, cls.get_connected_node_type(), "p") - @classmethod def create_pit_branch_entries(cls, net, branch_pit): """ @@ -143,7 +138,7 @@ def plant_dynamics(cls, dt, desired_mv, dyn_pump_tbl): def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): dt = net['_options']['dt'] circ_pump_tbl = net[cls.table_name()] - junction_lookup = get_lookup(net, "node", "index")[ cls.get_connected_node_type().table_name()] + junction_lookup = get_lookup(net, "node", "index")[cls.get_connected_node_type().table_name()] fn_col, tn_col = cls.from_to_node_cols() # get indices in internal structure for flow_junctions in circ_pump tables which are # "active" @@ -162,7 +157,7 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo desired_mv = circ_pump_tbl.desired_mv.values cur_actual_pos = circ_pump_tbl.actual_pos.values - #if not np.isnan(desired_mv) and get_net_option(net, "time_step") == cls.time_step: + # if not np.isnan(desired_mv) and get_net_option(net, "time_step") == cls.time_step: if get_net_option(net, "time_step") == cls.time_step: # a controller timeseries is running actual_pos = cls.plant_dynamics(dt, desired_mv, circ_pump_tbl) @@ -172,7 +167,7 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo circ_pump_tbl.actual_pos = actual_pos cls.time_step += 1 - else: # Steady state analysis + else: # Steady state analysis actual_pos = circ_pump_tbl.actual_pos.values std_types_lookup = np.array(list(net.std_types['dynamic_pump'].keys())) @@ -181,8 +176,8 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo std_types = np.array(list(net.std_types['dynamic_pump'].keys()))[std_type] fcts = itemgetter(*std_types)(net['std_types']['dynamic_pump']) fcts = [fcts] if not isinstance(fcts, tuple) else fcts - m_head = np.array(list(map(lambda x, y, z: x.get_m_head(y, z), fcts, vol_m3_s, actual_pos))) # m head - prsr_lift = np.divide((rho * GRAVITATION_CONSTANT * m_head), P_CONVERSION)[0] # bar + m_head = np.array(list(map(lambda x, y, z: x.get_m_head(y, z), fcts, vol_m3_s, actual_pos))) # m head + prsr_lift = np.divide((rho * GRAVITATION_CONSTANT * m_head), P_CONVERSION)[0] # bar circ_pump_tbl.p_lift = prsr_lift circ_pump_tbl.m_head = m_head @@ -202,7 +197,6 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo update_fixed_node_entries(net, node_pit, junction, circ_pump_tbl.type.values, (prsr_lift + p_static), t_flow_k, cls.get_connected_node_type(), "pt") - @classmethod def get_result_table(cls, net): """ @@ -240,7 +234,6 @@ def get_component_input(cls): def calculate_temperature_lift(cls, net, pipe_pit, node_pit): pass - @classmethod def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): """ @@ -287,8 +280,7 @@ def extract_results(cls, net, options, branch_results, nodes_connected, branches return_junctions = circ_pump_tbl[fn_col].values return_node = junction_lookup[return_junctions] - - #res_table["vdot_norm_m3_per_s"] = np.divide(- (sum_mass_flows / counts)[inverse_nodes], rho) + # res_table["vdot_norm_m3_per_s"] = np.divide(- (sum_mass_flows / counts)[inverse_nodes], rho) return_junctions = circ_pump_tbl[fn_col].values return_nodes = junction_lookup[return_junctions] @@ -297,8 +289,8 @@ def extract_results(cls, net, options, branch_results, nodes_connected, branches res_table["p_static_bar"].values[in_service] = circ_pump_tbl.p_static_bar.values res_table["p_flow_bar"].values[in_service] = node_pit[flow_nodes, PINIT] res_table["deltap_bar"].values[in_service] = deltap_bar[in_service] - res_table["t_from_k"].values[p_grids] = node_pit[return_node, TINIT] - res_table["t_to_k"].values[p_grids] = node_pit[flow_nodes, TINIT] + res_table["t_from_k"].values[p_grids] = node_pit[return_node, TOUTINIT] + res_table["t_to_k"].values[p_grids] = node_pit[flow_nodes, TOUTINIT] res_table["rho"].values[p_grids] = node_pit[return_node, RHO_node] res_table["p_lift"].values[p_grids] = circ_pump_tbl.p_lift.values res_table["m_head"].values[p_grids] = circ_pump_tbl.m_head.values diff --git a/pandapipes/component_models/dynamic_pump_component.py b/pandapipes/component_models/dynamic_pump_component.py index 244bec614..e435f88f9 100644 --- a/pandapipes/component_models/dynamic_pump_component.py +++ b/pandapipes/component_models/dynamic_pump_component.py @@ -7,14 +7,14 @@ import numpy as np from numpy import dtype -from pandapipes.component_models.junction_component import Junction -from pandapipes.component_models.pump_component import Pump from pandapipes.component_models.abstract_models.branch_wzerolength_models import \ BranchWZeroLengthComponent -from pandapipes.constants import NORMAL_TEMPERATURE, NORMAL_PRESSURE, R_UNIVERSAL, P_CONVERSION, \ - GRAVITATION_CONSTANT -from pandapipes.idx_branch import STD_TYPE, VINIT, D, AREA, TL, LOSS_COEFFICIENT as LC, FROM_NODE, \ - TINIT, PL, Kv_max, ACTUAL_POS, DESIRED_MV, RHO +from pandapipes.component_models.component_toolbox import get_component_array +from pandapipes.component_models.junction_component import Junction +from pandapipes.constants import NORMAL_PRESSURE, R_UNIVERSAL, P_CONVERSION, \ + GRAVITATION_CONSTANT +from pandapipes.idx_branch import VINIT, D, AREA, TL, LOSS_COEFFICIENT as LC, FROM_NODE, \ + TOUTINIT, PL, ACTUAL_POS, DESIRED_MV, RHO from pandapipes.idx_node import PINIT, PAMB, TINIT as TINIT_NODE from pandapipes.pf.pipeflow_setup import get_fluid, get_net_option, get_lookup from pandapipes.pf.result_extraction import extract_branch_results_without_internals @@ -35,6 +35,10 @@ class DynamicPump(BranchWZeroLengthComponent): prev_act_pos = None time_step = 0 + STD_TYPE = 0 + + internal_cols = 1 + @classmethod def from_to_node_cols(cls): return "from_junction", "to_junction" @@ -51,6 +55,27 @@ def active_identifier(cls): def get_connected_node_type(cls): return Junction + @classmethod + def create_component_array(cls, net, component_pits): + """ + Function which creates an internal array of the component in analogy to the pit, but with + component specific entries, that are not needed in the pit. + + :param net: The pandapipes network + :type net: pandapipesNet + :param component_pits: dictionary of component specific arrays + :type component_pits: dict + :return: + :rtype: + """ + tbl = net[cls.table_name()] + pump_array = np.zeros(shape=(len(tbl), cls.internal_cols), dtype=np.float64) + std_types_lookup = get_std_type_lookup(net, cls.table_name()) + std_type, pos = np.where(net[cls.table_name()]['std_type'].values + == std_types_lookup[:, np.newaxis]) + pump_array[pos, cls.STD_TYPE] = std_type + component_pits[cls.table_name()] = pump_array + @classmethod def create_pit_branch_entries(cls, net, branch_pit): """ @@ -61,11 +86,8 @@ def create_pit_branch_entries(cls, net, branch_pit): :type branch_pit: :return: No Output. """ + pump_pit = super().create_pit_branch_entries(net, branch_pit) - std_types_lookup = np.array(list(net.std_types[cls.table_name()].keys())) - std_type, pos = np.where(net[cls.table_name()]['std_type'].values - == std_types_lookup[:, np.newaxis]) - pump_pit[pos, STD_TYPE] = std_type pump_pit[:, D] = 0.1 pump_pit[:, AREA] = pump_pit[:, D] ** 2 * np.pi / 4 pump_pit[:, LC] = 0 @@ -126,14 +148,15 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo dyn_pump_tbl = net[cls.table_name()] pump_pit = branch_pit[f:t, :] area = pump_pit[:, AREA] - idx = pump_pit[:, STD_TYPE].astype(int) + pump_array = get_component_array(net, cls.table_name()) + idx = pump_array[:, cls.STD_TYPE].astype(np.int32) std_types = np.array(list(net.std_types['dynamic_pump'].keys()))[idx] from_nodes = pump_pit[:, FROM_NODE].astype(np.int32) # to_nodes = pump_pit[:, TO_NODE].astype(np.int32) fluid = get_fluid(net) p_from = node_pit[from_nodes, PAMB] + node_pit[from_nodes, PINIT] # p_to = node_pit[to_nodes, PAMB] + node_pit[to_nodes, PINIT] - numerator = NORMAL_PRESSURE * pump_pit[:, TINIT] + numerator = NORMAL_PRESSURE * pump_pit[:, TOUTINIT] v_mps = pump_pit[:, VINIT] desired_mv = dyn_pump_tbl.desired_mv.values cur_actual_pos = dyn_pump_tbl.actual_pos.values @@ -154,11 +177,10 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo else: # Steady state analysis actual_pos = dyn_pump_tbl.actual_pos.values - fcts = itemgetter(*std_types)(net['std_types']['dynamic_pump']) fcts = [fcts] if not isinstance(fcts, tuple) else fcts m_head = np.array(list(map(lambda x, y, z: x.get_m_head(y, z), fcts, vol_m3_s, actual_pos))) # m head - rho= pump_pit[:, RHO] + rho = pump_pit[:, RHO] prsr_lift = np.divide((rho * GRAVITATION_CONSTANT * m_head), P_CONVERSION)[0] # bar dyn_pump_tbl.p_lift = prsr_lift dyn_pump_tbl.m_head = m_head @@ -278,13 +300,17 @@ def get_result_table(cls, net): "v_from_m_per_s", "v_to_m_per_s", "p_from_bar", "p_to_bar", "t_from_k", "t_to_k", "mdot_from_kg_per_s", "mdot_to_kg_per_s", - "vdot_norm_m3_per_s", "normfactor_from", "normfactor_to", "desired_mv", "actual_pos"] + "vdot_norm_m3_per_s", "normfactor_from", "normfactor_to", "desired_mv", "actual_pos"] # TODO: inwieweit sind diese Angaben bei imaginärem Durchmesser sinnvoll? else: output = ["deltap_bar", "v_mean_m_per_s", "p_from_bar", "p_to_bar", "t_from_k", "t_to_k", "mdot_from_kg_per_s", "mdot_to_kg_per_s", "vdot_norm_m3_per_s", - "desired_mv", "actual_pos"] + "desired_mv", "actual_pos"] if calc_compr_pow: output += ["compr_power_mw"] - return output, True \ No newline at end of file + return output, True + + +def get_std_type_lookup(net, table_name): + return np.array(list(net.std_types[table_name].keys())) diff --git a/pandapipes/component_models/dynamic_valve_component.py b/pandapipes/component_models/dynamic_valve_component.py index be8faf5b4..ec624bc25 100644 --- a/pandapipes/component_models/dynamic_valve_component.py +++ b/pandapipes/component_models/dynamic_valve_component.py @@ -2,17 +2,19 @@ # and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved. # Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. +from operator import itemgetter + import numpy as np from numpy import dtype -from operator import itemgetter -from pandapipes.constants import NORMAL_TEMPERATURE, NORMAL_PRESSURE, R_UNIVERSAL, P_CONVERSION + from pandapipes.component_models.abstract_models.branch_wzerolength_models import \ BranchWZeroLengthComponent +from pandapipes.component_models.component_toolbox import get_component_array from pandapipes.component_models.junction_component import Junction -from pandapipes.pf.pipeflow_setup import get_net_option, get_net_options -from pandapipes.idx_node import PINIT, PAMB, TINIT as TINIT_NODE, NODE_TYPE, P, ACTIVE as ACTIVE_ND, LOAD -from pandapipes.idx_branch import D, AREA, TL, Kv_max, ACTUAL_POS, STD_TYPE, FROM_NODE, TO_NODE, \ - VINIT, RHO, PL, LOSS_COEFFICIENT as LC, DESIRED_MV, ACTIVE, LOAD_VEC_NODES +from pandapipes.idx_branch import D, AREA, TL, Kv_max, ACTUAL_POS, FROM_NODE, TO_NODE, \ + RHO, LOSS_COEFFICIENT as LC, DESIRED_MV +from pandapipes.idx_node import PINIT, PAMB +from pandapipes.pf.pipeflow_setup import get_net_option from pandapipes.pf.result_extraction import extract_branch_results_without_internals from pandapipes.properties.fluids import get_fluid @@ -28,6 +30,10 @@ class DynamicValve(BranchWZeroLengthComponent): prev_act_pos = None time_step = 0 + STD_TYPE = 0 + + internal_cols = 1 + @classmethod def from_to_node_cols(cls): return "from_junction", "to_junction" @@ -44,6 +50,26 @@ def active_identifier(cls): def get_connected_node_type(cls): return Junction + @classmethod + def create_component_array(cls, net, component_pits): + """ + Function which creates an internal array of the component in analogy to the pit, but with + component specific entries, that are not needed in the pit. + + :param net: The pandapipes network + :type net: pandapipesNet + :param component_pits: dictionary of component specific arrays + :type component_pits: dict + :return: + :rtype: + """ + tbl = net[cls.table_name()] + valve_array = np.zeros(shape=(len(tbl), cls.internal_cols), dtype=np.float64) + std_types_lookup = get_std_type_lookup(net, cls.table_name()) + std_type, pos = np.where(net[cls.table_name()]['std_type'].values + == std_types_lookup[:, np.newaxis]) + valve_array[pos, cls.STD_TYPE] = std_type + component_pits[cls.table_name()] = valve_array @classmethod def create_pit_branch_entries(cls, net, branch_pit): @@ -58,13 +84,12 @@ def create_pit_branch_entries(cls, net, branch_pit): """ valve_grids = net[cls.table_name()] valve_pit = super().create_pit_branch_entries(net, branch_pit) - valve_pit[:, D] = 0.05 #0.1 #net[cls.table_name()].diameter_m.values + valve_pit[:, D] = 0.05 # 0.1 #net[cls.table_name()].diameter_m.values valve_pit[:, AREA] = valve_pit[:, D] ** 2 * np.pi / 4 valve_pit[:, Kv_max] = net[cls.table_name()].Kv_max.values valve_pit[:, ACTUAL_POS] = net[cls.table_name()].actual_pos.values valve_pit[:, DESIRED_MV] = net[cls.table_name()].desired_mv.values - # # # Update in_service status if valve actual position becomes 0% # vlv_status = valve_pit[:, ACTIVE] # in_active_pos = np.where(valve_pit[:, ACTUAL_POS] == 0) @@ -74,7 +99,6 @@ def create_pit_branch_entries(cls, net, branch_pit): std_types_lookup = np.array(list(net.std_types[cls.table_name()].keys())) std_type, pos = np.where(net[cls.table_name()]['std_type'].values == std_types_lookup[:, np.newaxis]) - valve_pit[pos, STD_TYPE] = std_type @classmethod def plant_dynamics(cls, dt, desired_mv, dyn_valve_tbl): @@ -130,7 +154,8 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo dyn_valve_tbl = net[cls.table_name()] valve_pit = branch_pit[f:t, :] area = valve_pit[:, AREA] - idx = valve_pit[:, STD_TYPE].astype(int) + valve_array = get_component_array(net, cls.table_name()) + idx = valve_array[:, cls.STD_TYPE].astype(np.int32) std_types = np.array(list(net.std_types['dynamic_valve'].keys()))[idx] from_nodes = valve_pit[:, FROM_NODE].astype(np.int32) to_nodes = valve_pit[:, TO_NODE].astype(np.int32) @@ -140,7 +165,6 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo desired_mv = valve_pit[:, DESIRED_MV] cur_actual_pos = valve_pit[:, ACTUAL_POS] - if get_net_option(net, "time_step") == cls.time_step: # a controller timeseries is running actual_pos = cls.plant_dynamics(dt, desired_mv, dyn_valve_tbl) @@ -151,7 +175,7 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo dyn_valve_tbl.actual_pos = actual_pos cls.time_step += 1 - else: # Steady state analysis - recycle for Newton-Raphson loop + else: # Steady state analysis - recycle for Newton-Raphson loop actual_pos = valve_pit[:, ACTUAL_POS] fcts = itemgetter(*std_types)(net['std_types']['dynamic_valve']) @@ -160,13 +184,13 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo lift = np.divide(actual_pos, 100) relative_flow = np.array(list(map(lambda x, y: x.get_relative_flow(y), fcts, lift))) - kv_at_travel = relative_flow * valve_pit[:, Kv_max] # m3/h.Bar + kv_at_travel = relative_flow * valve_pit[:, Kv_max] # m3/h.Bar delta_p = np.abs(p_from - p_to) # bar - #if get_net_option(net, "time_step") == None or get_net_option(net, "time_step") == cls.time_step: - # On first loop initialise delta P to 0.1 if delta is zero - #delta_p = np.where(delta_p == 0, 0.1, delta_p) - #delta_p = np.where(np.ma.masked_where(delta_p == 0, lift == 1.0).mask, 0.1, delta_p) + # if get_net_option(net, "time_step") == None or get_net_option(net, "time_step") == cls.time_step: + # On first loop initialise delta P to 0.1 if delta is zero + # delta_p = np.where(delta_p == 0, 0.1, delta_p) + # delta_p = np.where(np.ma.masked_where(delta_p == 0, lift == 1.0).mask, 0.1, delta_p) positions_delta_p = np.where(delta_p == 0.0) positions_lift = np.where(lift != 1.0) # get common element values (indexes that appear in both position arrays) @@ -260,3 +284,7 @@ def get_result_table(cls, net): "mdot_from_kg_per_s", "mdot_to_kg_per_s", "vdot_norm_m3_per_s", "reynolds", "lambda", "desired_mv", "actual_pos", "LC"] return output, True + + +def get_std_type_lookup(net, table_name): + return np.array(list(net.std_types[table_name].keys())) diff --git a/pandapipes/component_models/ext_grid_component.py b/pandapipes/component_models/ext_grid_component.py index 9570f51e1..d78028320 100644 --- a/pandapipes/component_models/ext_grid_component.py +++ b/pandapipes/component_models/ext_grid_component.py @@ -62,20 +62,18 @@ def create_pit_node_entries(cls, net, node_pit): return ext_grids, press @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): """ Function that extracts certain results. - :param nodes_connected: - :type nodes_connected: - :param branches_connected: - :type branches_connected: :param branch_results: :type branch_results: :param net: The pandapipes network :type net: pandapipesNet :param options: :type options: + :param mode: + :type mode: :return: No Output. """ ext_grids = net[cls.table_name()] diff --git a/pandapipes/component_models/flow_control_component.py b/pandapipes/component_models/flow_control_component.py index d42f58155..67e25487e 100644 --- a/pandapipes/component_models/flow_control_component.py +++ b/pandapipes/component_models/flow_control_component.py @@ -5,10 +5,12 @@ import numpy as np from numpy import dtype -from pandapipes.component_models.junction_component import Junction from pandapipes.component_models.abstract_models import BranchWZeroLengthComponent, get_fluid -from pandapipes.idx_branch import D, AREA, TL, JAC_DERIV_DP, JAC_DERIV_DP1, JAC_DERIV_DV, VINIT, \ - RHO, LOAD_VEC_BRANCHES, ELEMENT_IDX +from pandapipes.component_models.component_toolbox import \ + standard_branch_wo_internals_result_lookup, get_component_array +from pandapipes.component_models.junction_component import Junction +from pandapipes.idx_branch import D, AREA, JAC_DERIV_DP, JAC_DERIV_DP1, JAC_DERIV_DV, VINIT, \ + RHO, LOAD_VEC_BRANCHES from pandapipes.pf.result_extraction import extract_branch_results_without_internals @@ -16,6 +18,9 @@ class FlowControlComponent(BranchWZeroLengthComponent): """ """ + CONTROL_ACTIVE = 0 + + internal_cols = 1 @classmethod def table_name(cls): @@ -43,64 +48,50 @@ def create_pit_branch_entries(cls, net, branch_pit): :type branch_pit: :return: No Output. """ - fc_pit = super().create_pit_branch_entries(net, branch_pit) - fc_pit[:, D] = net[cls.table_name()].diameter_m.values - fc_pit[:, AREA] = fc_pit[:, D] ** 2 * np.pi / 4 - fc_pit[:, VINIT] = net[cls.table_name()].controlled_mdot_kg_per_s.values / \ - (fc_pit[:, AREA] * fc_pit[:, RHO]) - - @classmethod - def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): - pass - - @classmethod - def adaption_after_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): - # set all pressure derivatives to 0 and velocity to 1; load vector must be 0, as no change - # of velocity is allowed during the pipeflow iteration - f, t = idx_lookups[cls.table_name()] - fc_pit = branch_pit[f:t, :] - in_service_elm = np.isin(net[cls.table_name()].index.values, - fc_pit[:, ELEMENT_IDX].astype(np.int32)) - active = net[cls.table_name()].control_active.values[in_service_elm] - fc_pit[active, JAC_DERIV_DP] = 0 - fc_pit[active, JAC_DERIV_DP1] = 0 - fc_pit[active, JAC_DERIV_DV] = 1 - fc_pit[active, LOAD_VEC_BRANCHES] = 0 + fc_branch_pit = super().create_pit_branch_entries(net, branch_pit) + fc_branch_pit[:, D] = net[cls.table_name()].diameter_m.values + fc_branch_pit[:, AREA] = fc_branch_pit[:, D] ** 2 * np.pi / 4 + fc_branch_pit[:, VINIT] = net[cls.table_name()].controlled_mdot_kg_per_s.values / \ + (fc_branch_pit[:, AREA] * fc_branch_pit[:, RHO]) @classmethod - def calculate_temperature_lift(cls, net, branch_component_pit, node_pit): + def create_component_array(cls, net, component_pits): """ + Function which creates an internal array of the component in analogy to the pit, but with + component specific entries, that are not needed in the pit. - :param net: - :type net: - :param branch_component_pit: - :type branch_component_pit: - :param node_pit: - :type node_pit: + :param net: The pandapipes network + :type net: pandapipesNet + :param component_pits: dictionary of component specific arrays + :type component_pits: dict :return: :rtype: """ - branch_component_pit[:, TL] = 0 + tbl = net[cls.table_name()] + fc_pit = np.zeros(shape=(len(tbl), cls.internal_cols), dtype=np.float64) + fc_pit[:, cls.CONTROL_ACTIVE] = tbl.control_active.values + component_pits[cls.table_name()] = fc_pit + @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): - required_results = [ - ("p_from_bar", "p_from"), ("p_to_bar", "p_to"), ("t_from_k", "temp_from"), - ("t_to_k", "temp_to"), ("mdot_to_kg_per_s", "mf_to"), ("mdot_from_kg_per_s", "mf_from"), - ("vdot_norm_m3_per_s", "vf"), ("lambda", "lambda"), ("reynolds", "reynolds") - ] + def adaption_after_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): + # set all pressure derivatives to 0 and velocity to 1; load vector must be 0, as no change + # of velocity is allowed during the pipeflow iteration + f, t = idx_lookups[cls.table_name()] + fc_branch_pit = branch_pit[f:t, :] + fc_array = get_component_array(net, cls.table_name()) + active = fc_array[:, cls.CONTROL_ACTIVE].astype(np.bool_) + fc_branch_pit[active, JAC_DERIV_DP] = 0 + fc_branch_pit[active, JAC_DERIV_DP1] = 0 + fc_branch_pit[active, JAC_DERIV_DV] = 1 + fc_branch_pit[active, LOAD_VEC_BRANCHES] = 0 - if get_fluid(net).is_gas: - required_results.extend([ - ("v_from_m_per_s", "v_gas_from"), ("v_to_m_per_s", "v_gas_to"), - ("v_mean_m_per_s", "v_gas_mean"), ("normfactor_from", "normfactor_from"), - ("normfactor_to", "normfactor_to") - ]) - else: - required_results.extend([("v_mean_m_per_s", "v_mps")]) + @classmethod + def extract_results(cls, net, options, branch_results, mode): + required_results_hyd, required_results_ht = standard_branch_wo_internals_result_lookup(net) - extract_branch_results_without_internals(net, branch_results, required_results, - cls.table_name(), branches_connected) + extract_branch_results_without_internals(net, branch_results, required_results_hyd, + required_results_ht, cls.table_name(), mode) @classmethod def get_component_input(cls): diff --git a/pandapipes/component_models/heat_exchanger_component.py b/pandapipes/component_models/heat_exchanger_component.py index cdd414fc7..ed89b1c0c 100644 --- a/pandapipes/component_models/heat_exchanger_component.py +++ b/pandapipes/component_models/heat_exchanger_component.py @@ -5,10 +5,11 @@ import numpy as np from numpy import dtype +from pandapipes.component_models import standard_branch_wo_internals_result_lookup from pandapipes.component_models.abstract_models.branch_wzerolength_models import \ BranchWZeroLengthComponent from pandapipes.component_models.junction_component import Junction -from pandapipes.idx_branch import TL, ALPHA, TEXT, QEXT, T_OUT, D, AREA, LOSS_COEFFICIENT as LC +from pandapipes.idx_branch import ALPHA, TEXT, QEXT, D, AREA, LOSS_COEFFICIENT as LC, TOUTINIT from pandapipes.pf.pipeflow_setup import get_fluid from pandapipes.pf.result_extraction import extract_branch_results_without_internals @@ -57,27 +58,30 @@ def create_pit_branch_entries(cls, net, branch_pit): heat_exchanger_pit[:, ALPHA] = 0 heat_exchanger_pit[:, QEXT] = net[cls.table_name()].qext_w.values heat_exchanger_pit[:, TEXT] = 293.15 - heat_exchanger_pit[:, T_OUT] = 307 + heat_exchanger_pit[:, TOUTINIT] = 307 @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): - required_results = [ + def extract_results(cls, net, options, branch_results, mode): + _, required_results_ht = standard_branch_wo_internals_result_lookup(net) + + required_results_hyd = [ ("p_from_bar", "p_from"), ("p_to_bar", "p_to"), ("t_from_k", "temp_from"), ("t_to_k", "temp_to"), ("mdot_to_kg_per_s", "mf_to"), ("mdot_from_kg_per_s", "mf_from"), ("vdot_norm_m3_per_s", "vf"), ("lambda", "lambda"), ("reynolds", "reynolds"), ("qext_w", "qext_w") ] if get_fluid(net).is_gas: - required_results.extend([ + required_results_hyd.extend([ ("v_from_m_per_s", "v_gas_from"), ("v_to_m_per_s", "v_gas_to"), ("v_mean_m_per_s", "v_gas_mean"), ("normfactor_from", "normfactor_from"), ("normfactor_to", "normfactor_to") ]) else: - required_results.extend([("v_mean_m_per_s", "v_mps")]) + required_results_hyd.extend([("v_mean_m_per_s", "v_mps")]) + + extract_branch_results_without_internals(net, branch_results, required_results_hyd, + required_results_ht, cls.table_name(), mode) - extract_branch_results_without_internals(net, branch_results, required_results, - cls.table_name(), branches_connected) @classmethod def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): @@ -85,20 +89,6 @@ def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lo heat_exchanger_pit = branch_pit[f:t, :] heat_exchanger_pit[:, QEXT] = net[cls.table_name()].qext_w.values - @classmethod - def calculate_temperature_lift(cls, net, branch_component_pit, node_pit): - """ - - :param net: - :type net: - :param branch_component_pit: - :type branch_component_pit: - :param node_pit: - :type node_pit: - :return: - :rtype: - """ - branch_component_pit[:, TL] = 0 @classmethod def get_component_input(cls): diff --git a/pandapipes/component_models/junction_component.py b/pandapipes/component_models/junction_component.py index 328ab9302..491313530 100644 --- a/pandapipes/component_models/junction_component.py +++ b/pandapipes/component_models/junction_component.py @@ -91,20 +91,20 @@ def create_pit_node_entries(cls, net, node_pit): junction_pit[:, ACTIVE_ND] = junctions.in_service.values @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): """ Function that extracts certain results. - :param nodes_connected: - :type nodes_connected: - :param branches_connected: - :type branches_connected: - :param branch_results: - :type branch_results: + :param mode: + :type mode: :param net: The pandapipes network :type net: pandapipesNet :param options: :type options: + :param branch_results: + :type branch_results: + :param mode: + :type mode: :return: No Output. """ res_table = net["res_" + cls.table_name()] @@ -119,17 +119,25 @@ def extract_results(cls, net, options, branch_results, nodes_connected, branches net["res_internal"]["t_k"] = net["_active_pit"]["node"][:, TINIT] f, t = get_lookup(net, "node", "from_to")[cls.table_name()] - fa, ta = get_lookup(net, "node", "from_to_active")[cls.table_name()] - junction_pit = net["_active_pit"]["node"][fa:ta, :] - junctions_active = get_lookup(net, "node", "active")[f:t] - - if np.any(junction_pit[:, PINIT] < 0): - warn(UserWarning('Pipeflow converged, however, the results are physically incorrect ' - 'as pressure is negative at nodes %s' - % junction_pit[junction_pit[:, PINIT] < 0, ELEMENT_IDX])) - - res_table["p_bar"].values[junctions_active] = junction_pit[:, PINIT] - res_table["t_k"].values[junctions_active] = junction_pit[:, TINIT] + junction_pit = net["_pit"]["node"][f:t, :] + + if mode in ["hydraulics", "all"]: + junctions_connected_hydraulic = get_lookup(net, "node", "active_hydraulics")[f:t] + + if np.any(junction_pit[junctions_connected_hydraulic, PINIT] < 0): + warn(UserWarning('Pipeflow converged, however, the results are physically incorrect ' + 'as pressure is negative at nodes %s' + % junction_pit[junction_pit[:, PINIT] < 0, ELEMENT_IDX])) + + # res_table["p_bar"].values[junctions_connected_hydraulic] = junction_pit[:, PINIT] + # if mode == "hydraulics": + # res_table["t_k"].values[junctions_connected_hydraulic] = junction_pit[:, TINIT] + # + # if mode in ["heat", "all"]: + # junctions_connected_ht = get_lookup(net, "node", "active_heat_transfer")[f:t] + # res_table["t_k"].values[junctions_connected_ht] = junction_pit[:, TINIT] + res_table["p_bar"].values[:] = junction_pit[:, PINIT] + res_table["t_k"].values[:] = junction_pit[:, TINIT] @classmethod def get_component_input(cls): diff --git a/pandapipes/component_models/pipe_component.py b/pandapipes/component_models/pipe_component.py index f8f38aa18..99b2f098a 100644 --- a/pandapipes/component_models/pipe_component.py +++ b/pandapipes/component_models/pipe_component.py @@ -11,7 +11,7 @@ from pandapipes.component_models.junction_component import Junction from pandapipes.constants import NORMAL_TEMPERATURE, NORMAL_PRESSURE from pandapipes.idx_branch import FROM_NODE, TO_NODE, LENGTH, D, AREA, K, \ - VINIT, ALPHA, QEXT, TEXT, LOSS_COEFFICIENT as LC, T_OUT, TL + VINIT, ALPHA, QEXT, TEXT, LOSS_COEFFICIENT as LC from pandapipes.idx_node import PINIT, HEIGHT, TINIT as TINIT_NODE, \ RHO as RHO_NODES, PAMB, ACTIVE as ACTIVE_ND from pandapipes.pf.pipeflow_setup import get_fluid, get_lookup @@ -151,47 +151,38 @@ def create_pit_branch_entries(cls, net, branch_pit): set_entry_check_repeat( pipe_pit, LC, net[tbl].loss_coefficient.values, internal_pipe_number, has_internals) - pipe_pit[:, T_OUT] = 293 pipe_pit[:, AREA] = pipe_pit[:, D] ** 2 * np.pi / 4 @classmethod - def calculate_temperature_lift(cls, net, branch_component_pit, node_pit): - """ - - :param net: - :type net: - :param branch_component_pit: - :type branch_component_pit: - :param node_pit: - :type node_pit: - :return: - :rtype: - """ - branch_component_pit[:, TL] = 0 - - @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): - res_nodes_from = [("p_from_bar", "p_from"), ("t_from_k", "temp_from"), - ("mdot_from_kg_per_s", "mf_from")] - res_nodes_to = [("p_to_bar", "p_to"), ("t_to_k", "temp_to"), ("mdot_to_kg_per_s", "mf_to")] - res_mean = [("vdot_norm_m3_per_s", "vf"), ("lambda", "lambda"), ("reynolds", "reynolds")] + def extract_results(cls, net, options, branch_results, mode): + res_nodes_from_hyd = [("p_from_bar", "p_from"), ("mdot_from_kg_per_s", "mf_from")] + res_nodes_from_ht = [("t_from_k", "temp_from")] + res_nodes_to_hyd = [("p_to_bar", "p_to"), ("mdot_to_kg_per_s", "mf_to")] + res_nodes_to_ht = [("t_to_k", "temp_to")] + res_mean_hyd = [("vdot_norm_m3_per_s", "vf"), ("lambda", "lambda"), + ("reynolds", "reynolds")] if get_fluid(net).is_gas: - res_nodes_from.extend( - [("v_from_m_per_s", "v_gas_from"), ("normfactor_from", "normfactor_from")]) - res_nodes_to.extend([("v_to_m_per_s", "v_gas_to"), ("normfactor_to", "normfactor_to")]) - res_mean.extend([("v_mean_m_per_s", "v_gas_mean")]) + res_nodes_from_hyd.extend([("v_from_m_per_s", "v_gas_from"), + ("normfactor_from", "normfactor_from")]) + res_nodes_to_hyd.extend([("v_to_m_per_s", "v_gas_to"), + ("normfactor_to", "normfactor_to")]) + res_mean_hyd.extend([("v_mean_m_per_s", "v_gas_mean")]) else: - res_mean.extend([("v_mean_m_per_s", "v_mps")]) + res_mean_hyd.extend([("v_mean_m_per_s", "v_mps")]) if np.any(cls.get_internal_pipe_number(net) > 1): extract_branch_results_with_internals( - net, branch_results, cls.table_name(), res_nodes_from, res_nodes_to, res_mean, - cls.get_connected_node_type().table_name(), branches_connected) + net, branch_results, cls.table_name(), res_nodes_from_hyd, res_nodes_from_ht, + res_nodes_to_hyd, res_nodes_to_ht, res_mean_hyd, [], + cls.get_connected_node_type().table_name(), mode) else: - required_results = res_nodes_from + res_nodes_to + res_mean - extract_branch_results_without_internals(net, branch_results, required_results, - cls.table_name(), branches_connected) + required_results_hyd = res_nodes_from_hyd + res_nodes_to_hyd + res_mean_hyd + required_results_ht = res_nodes_from_ht + res_nodes_to_ht + extract_branch_results_without_internals( + net, branch_results, required_results_hyd, required_results_ht, cls.table_name(), + mode + ) @classmethod def get_internal_results(cls, net, pipe): diff --git a/pandapipes/component_models/pressure_control_component.py b/pandapipes/component_models/pressure_control_component.py index abd4b2479..e582925bb 100644 --- a/pandapipes/component_models/pressure_control_component.py +++ b/pandapipes/component_models/pressure_control_component.py @@ -8,7 +8,7 @@ from pandapipes.component_models.abstract_models.branch_wzerolength_models import \ BranchWZeroLengthComponent from pandapipes.component_models.junction_component import Junction -from pandapipes.idx_branch import D, AREA, TL, \ +from pandapipes.idx_branch import D, AREA, \ JAC_DERIV_DP, JAC_DERIV_DP1, JAC_DERIV_DV, BRANCH_TYPE, LOSS_COEFFICIENT as LC from pandapipes.idx_node import PINIT, NODE_TYPE, PC from pandapipes.pf.pipeflow_setup import get_lookup @@ -80,29 +80,12 @@ def adaption_after_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_loo press_pit[pc_branch, JAC_DERIV_DV] = 0 @classmethod - def calculate_temperature_lift(cls, net, branch_component_pit, node_pit): - """ - - :param net: - :type net: - :param branch_component_pit: - :type branch_component_pit: - :param node_pit: - :type node_pit: - :return: - :rtype: - """ - branch_component_pit[:, TL] = 0 - - @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): """ Function that extracts certain results. - :param nodes_connected: - :type nodes_connected: - :param branches_connected: - :type branches_connected: + :param mode: + :type mode: :param branch_results: :type branch_results: :param net: The pandapipes network @@ -111,22 +94,22 @@ def extract_results(cls, net, options, branch_results, nodes_connected, branches :type options: :return: No Output. """ - required_results = [ - ("p_from_bar", "p_from"), ("p_to_bar", "p_to"), ("t_from_k", "temp_from"), - ("t_to_k", "temp_to"), ("mdot_to_kg_per_s", "mf_to"), ("mdot_from_kg_per_s", "mf_from"), - ("vdot_norm_m3_per_s", "vf") + required_results_hyd = [ + ("p_from_bar", "p_from"), ("p_to_bar", "p_to"), ("mdot_from_kg_per_s", "mf_from"), + ("mdot_to_kg_per_s", "mf_to"), ("vdot_norm_m3_per_s", "vf") ] + required_results_ht = [("t_from_k", "temp_from"), ("t_to_k", "temp_to")] if get_fluid(net).is_gas: - required_results.extend([ + required_results_hyd.extend([ ("v_from_m_per_s", "v_gas_from"), ("v_to_m_per_s", "v_gas_to"), ("normfactor_from", "normfactor_from"), ("normfactor_to", "normfactor_to") ]) else: - required_results.extend([("v_mean_m_per_s", "v_mps")]) + required_results_hyd.extend([("v_mean_m_per_s", "v_mps")]) - extract_branch_results_without_internals(net, branch_results, required_results, - cls.table_name(), branches_connected) + extract_branch_results_without_internals(net, branch_results, required_results_hyd, + required_results_ht, cls.table_name(), mode) res_table = net["res_" + cls.table_name()] f, t = get_lookup(net, "branch", "from_to")[cls.table_name()] diff --git a/pandapipes/component_models/pump_component.py b/pandapipes/component_models/pump_component.py index 7c433ad88..ac009850e 100644 --- a/pandapipes/component_models/pump_component.py +++ b/pandapipes/component_models/pump_component.py @@ -7,12 +7,12 @@ import numpy as np from numpy import dtype -from pandapipes.component_models.junction_component import Junction from pandapipes.component_models.abstract_models.branch_wzerolength_models import \ BranchWZeroLengthComponent +from pandapipes.component_models.component_toolbox import get_component_array +from pandapipes.component_models.junction_component import Junction from pandapipes.constants import NORMAL_TEMPERATURE, NORMAL_PRESSURE, R_UNIVERSAL, P_CONVERSION -from pandapipes.idx_branch import STD_TYPE, VINIT, D, AREA, TL, LOSS_COEFFICIENT as LC, FROM_NODE, \ - TINIT, PL +from pandapipes.idx_branch import VINIT, D, AREA, LOSS_COEFFICIENT as LC, FROM_NODE, PL from pandapipes.idx_node import PINIT, PAMB, TINIT as TINIT_NODE from pandapipes.pf.pipeflow_setup import get_fluid, get_net_option, get_lookup from pandapipes.pf.result_extraction import extract_branch_results_without_internals @@ -27,7 +27,11 @@ class Pump(BranchWZeroLengthComponent): """ + """ + STD_TYPE = 0 + + internal_cols = 1 @classmethod def from_to_node_cols(cls): @@ -49,6 +53,7 @@ def get_connected_node_type(cls): def create_pit_branch_entries(cls, net, branch_pit): """ Function which creates pit branch entries with a specific table. + :param net: The pandapipes network :type net: pandapipesNet :param branch_pit: @@ -56,99 +61,106 @@ def create_pit_branch_entries(cls, net, branch_pit): :return: No Output. """ pump_pit = super().create_pit_branch_entries(net, branch_pit) - std_types_lookup = np.array(list(net.std_types[cls.table_name()].keys())) - std_type, pos = np.where(net[cls.table_name()]['std_type'].values - == std_types_lookup[:, np.newaxis]) - pump_pit[pos, STD_TYPE] = std_type pump_pit[:, D] = 0.1 pump_pit[:, AREA] = pump_pit[:, D] ** 2 * np.pi / 4 pump_pit[:, LC] = 0 + @classmethod + def create_component_array(cls, net, component_pits): + """ + Function which creates an internal array of the component in analogy to the pit, but with + component specific entries, that are not needed in the pit. + + :param net: The pandapipes network + :type net: pandapipesNet + :param component_pits: dictionary of component specific arrays + :type component_pits: dict + :return: + :rtype: + """ + tbl = net[cls.table_name()] + pump_array = np.zeros(shape=(len(tbl), cls.internal_cols), dtype=np.float64) + std_types_lookup = get_std_type_lookup(net, cls.table_name()) + std_type, pos = np.where(net[cls.table_name()]['std_type'].values + == std_types_lookup[:, np.newaxis]) + pump_array[pos, cls.STD_TYPE] = std_type + component_pits[cls.table_name()] = pump_array + @classmethod def adaption_before_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): # calculation of pressure lift f, t = idx_lookups[cls.table_name()] - pump_pit = branch_pit[f:t, :] - area = pump_pit[:, AREA] - idx = pump_pit[:, STD_TYPE].astype(int) - std_types = np.array(list(net.std_types['pump'].keys()))[idx] - from_nodes = pump_pit[:, FROM_NODE].astype(np.int32) - # to_nodes = pump_pit[:, TO_NODE].astype(np.int32) + pump_branch_pit = branch_pit[f:t, :] + area = pump_branch_pit[:, AREA] + + pump_array = get_component_array(net, cls.table_name()) + idx = pump_array[:, cls.STD_TYPE].astype(np.int32) + std_types = get_std_type_lookup(net, cls.table_name())[idx] + + from_nodes = pump_branch_pit[:, FROM_NODE].astype(np.int32) + # to_nodes = pump_branch_pit[:, TO_NODE].astype(np.int32) fluid = get_fluid(net) p_from = node_pit[from_nodes, PAMB] + node_pit[from_nodes, PINIT] # p_to = node_pit[to_nodes, PAMB] + node_pit[to_nodes, PINIT] - numerator = NORMAL_PRESSURE * pump_pit[:, TINIT] - v_mps = pump_pit[:, VINIT] + t_from = node_pit[from_nodes, TINIT_NODE] + numerator_from = NORMAL_PRESSURE * t_from + v_mps = pump_branch_pit[:, VINIT] if fluid.is_gas: # consider volume flow at inlet - normfactor_from = numerator * fluid.get_property("compressibility", p_from) \ + normfactor_from = numerator_from * fluid.get_property("compressibility", p_from) \ / (p_from * NORMAL_TEMPERATURE) - v_mean = v_mps * normfactor_from + v_from = v_mps * normfactor_from else: - v_mean = v_mps - vol = v_mean * area + v_from = v_mps + vol = v_from * area if len(std_types): fcts = itemgetter(*std_types)(net['std_types']['pump']) fcts = [fcts] if not isinstance(fcts, tuple) else fcts pl = np.array(list(map(lambda x, y: x.get_pressure(y), fcts, vol))) - pump_pit[:, PL] = pl - - @classmethod - def calculate_temperature_lift(cls, net, branch_component_pit, node_pit): - """ - :param net: - :type net: - :param branch_component_pit: - :type branch_component_pit: - :param node_pit: - :type node_pit: - :return: - :rtype: - """ - branch_component_pit[:, TL] = 0 + pump_branch_pit[:, PL] = pl @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): + def extract_results(cls, net, options, branch_results, mode): """ Function that extracts certain results. - :param nodes_connected: - :type nodes_connected: - :param branches_connected: - :type branches_connected: + :param branch_results: :type branch_results: :param net: The pandapipes network :type net: pandapipesNet :param options: :type options: + :param mode: + :type mode: :return: No Output. """ calc_compr_pow = options['calc_compression_power'] - required_results = [ - ("p_from_bar", "p_from"), ("p_to_bar", "p_to"), ("t_from_k", "temp_from"), - ("t_to_k", "temp_to"), ("mdot_to_kg_per_s", "mf_to"), ("mdot_from_kg_per_s", "mf_from"), - ("vdot_norm_m3_per_s", "vf"), ("deltap_bar", "pl") + required_results_hyd = [ + ("p_from_bar", "p_from"), ("p_to_bar", "p_to"), ("mdot_to_kg_per_s", "mf_to"), + ("mdot_from_kg_per_s", "mf_from"), ("vdot_norm_m3_per_s", "vf"), ("deltap_bar", "pl"), ] + required_results_ht = [("t_from_k", "temp_from"), ("t_to_k", "temp_to")] if get_fluid(net).is_gas: - required_results.extend([ + required_results_hyd.extend([ ("v_from_m_per_s", "v_gas_from"), ("v_to_m_per_s", "v_gas_to"), ("normfactor_from", "normfactor_from"), ("normfactor_to", "normfactor_to") ]) else: - required_results.extend([("v_mean_m_per_s", "v_mps")]) + required_results_hyd.extend([("v_mean_m_per_s", "v_mps")]) - extract_branch_results_without_internals(net, branch_results, required_results, - cls.table_name(), branches_connected) + extract_branch_results_without_internals(net, branch_results, required_results_hyd, + required_results_ht, cls.table_name(), mode) if calc_compr_pow: f, t = get_lookup(net, "branch", "from_to")[cls.table_name()] + from_nodes = branch_results["from_nodes"][f:t] + res_table = net["res_" + cls.table_name()] if net.fluid.is_gas: - p_from = branch_results["p_from"][f:t] - p_to = branch_results["p_to"][f:t] - from_nodes = branch_results["from_nodes"][f:t] + p_from = branch_results["p_abs_from"][f:t] + p_to = branch_results["p_abs_to"][f:t] t0 = net["_pit"]["node"][from_nodes, TINIT_NODE] mf_sum_int = branch_results["mf_from"][f:t] # calculate ideal compression power @@ -161,8 +173,9 @@ def extract_results(cls, net, options, branch_results, nodes_connected, branches ' defined') else: r_spec = 1e3 * R_UNIVERSAL / molar_mass # [J/(kg * K)] - # 'kappa' heat capacity ratio: - k = 1.4 # TODO: implement proper calculation of kappa + cp = net.fluid.get_heat_capacity(t0) + cv = cp - r_spec + k = cp / cv # 'kappa' heat capacity ratio w_real_isentr = (k / (k - 1)) * r_spec * compr * t0 * \ (np.divide(p_to, p_from) ** ((k - 1) / k) - 1) res_table['compr_power_mw'].values[:] = \ @@ -175,7 +188,9 @@ def extract_results(cls, net, options, branch_results, nodes_connected, branches @classmethod def get_component_input(cls): """ + Get component input. + :return: :rtype: """ @@ -189,7 +204,9 @@ def get_component_input(cls): @classmethod def get_result_table(cls, net): """ + Gets the result table. + :param net: The pandapipes network :type net: pandapipesNet :return: (columns, all_float) - the column names and whether they are all float type. Only @@ -211,4 +228,8 @@ def get_result_table(cls, net): if calc_compr_pow: output += ["compr_power_mw"] - return output, True \ No newline at end of file + return output, True + + +def get_std_type_lookup(net, table_name): + return np.array(list(net.std_types[table_name].keys())) diff --git a/pandapipes/component_models/valve_component.py b/pandapipes/component_models/valve_component.py index b63173e88..ff2b9451e 100644 --- a/pandapipes/component_models/valve_component.py +++ b/pandapipes/component_models/valve_component.py @@ -5,10 +5,11 @@ import numpy as np from numpy import dtype +from pandapipes.component_models.component_toolbox import standard_branch_wo_internals_result_lookup from pandapipes.component_models.abstract_models.branch_wzerolength_models import \ BranchWZeroLengthComponent from pandapipes.component_models.junction_component import Junction -from pandapipes.idx_branch import D, AREA, LOSS_COEFFICIENT as LC, TL +from pandapipes.idx_branch import D, AREA, LOSS_COEFFICIENT as LC from pandapipes.pf.result_extraction import extract_branch_results_without_internals from pandapipes.properties.fluids import get_fluid @@ -51,21 +52,6 @@ def create_pit_branch_entries(cls, net, branch_pit): valve_pit[:, AREA] = valve_pit[:, D] ** 2 * np.pi / 4 valve_pit[:, LC] = net[cls.table_name()].loss_coefficient.values - @classmethod - def calculate_temperature_lift(cls, net, branch_component_pit, node_pit): - """ - - :param net: - :type net: - :param branch_component_pit: - :type branch_component_pit: - :param node_pit: - :type node_pit: - :return: - :rtype: - """ - branch_component_pit[:, TL] = 0 - @classmethod def get_component_input(cls): """ @@ -82,24 +68,11 @@ def get_component_input(cls): ("type", dtype(object))] @classmethod - def extract_results(cls, net, options, branch_results, nodes_connected, branches_connected): - required_results = [ - ("p_from_bar", "p_from"), ("p_to_bar", "p_to"), ("t_from_k", "temp_from"), - ("t_to_k", "temp_to"), ("mdot_to_kg_per_s", "mf_to"), ("mdot_from_kg_per_s", "mf_from"), - ("vdot_norm_m3_per_s", "vf"), ("lambda", "lambda"), ("reynolds", "reynolds") - ] - - if get_fluid(net).is_gas: - required_results.extend([ - ("v_from_m_per_s", "v_gas_from"), ("v_to_m_per_s", "v_gas_to"), - ("v_mean_m_per_s", "v_gas_mean"), ("normfactor_from", "normfactor_from"), - ("normfactor_to", "normfactor_to") - ]) - else: - required_results.extend([("v_mean_m_per_s", "v_mps")]) + def extract_results(cls, net, options, branch_results, mode): + required_results_hyd, required_results_ht = standard_branch_wo_internals_result_lookup(net) - extract_branch_results_without_internals(net, branch_results, required_results, - cls.table_name(), branches_connected) + extract_branch_results_without_internals(net, branch_results, required_results_hyd, + required_results_ht, cls.table_name(), mode) @classmethod def get_result_table(cls, net): diff --git a/pandapipes/converter/stanet/stanet2pandapipes.py b/pandapipes/converter/stanet/stanet2pandapipes.py index 3ff7d8376..a0a4f6875 100644 --- a/pandapipes/converter/stanet/stanet2pandapipes.py +++ b/pandapipes/converter/stanet/stanet2pandapipes.py @@ -9,7 +9,7 @@ connection_pipe_section_table, get_stanet_raw_data, create_meter_table, create_house_table from pandapipes.converter.stanet.table_creation import create_junctions_from_nodes, \ create_valve_and_pipe, create_pumps, create_junctions_from_connections, \ - create_pipes_from_connections, create_heat_exchangers, create_slider_valves, \ + create_pipes_from_connections, create_heat_exchangers_stanet, create_slider_valves, \ create_pipes_from_remaining_pipe_table, create_nodes_house_connections, \ create_sinks_meters, create_sinks_from_nodes, create_control_components, \ create_sinks_from_customers, create_pipes_house_connections @@ -92,7 +92,8 @@ def stanet_to_pandapipes(stanet_path, name="net", remove_unused_household_connec create_pipes_from_remaining_pipe_table(net, stored_data, connections, index_mapping, pipe_geodata, add_layers) - create_heat_exchangers(net, stored_data, connections, index_mapping, add_layers) + create_heat_exchangers_stanet(net, stored_data, index_mapping, add_layers, + add_flow=kwargs.pop("add_heat_exchanger_flow", False)) # valves always have a length in STANET, therefore, they are created as valve with pipe in # pandapipes diff --git a/pandapipes/converter/stanet/table_creation.py b/pandapipes/converter/stanet/table_creation.py index 4c02c80ee..553a0c3f4 100644 --- a/pandapipes/converter/stanet/table_creation.py +++ b/pandapipes/converter/stanet/table_creation.py @@ -65,7 +65,8 @@ def create_junctions_from_nodes(net, stored_data, net_params, index_mapping, add add_info = {"stanet_id": node_table.STANETID.astype(str).values if "STANETID" in node_table.columns else knams, "p_stanet": node_table.PRECH.values.astype(np.float64), - "stanet_valid": ~node_table.CALCBAD.values.astype(np.bool_)} + "stanet_valid": ~node_table.CALCBAD.values.astype(np.bool_), + "t_stanet": node_table.TEMP.values.astype(np.float64)} if hasattr(node_table, "KFAK"): add_info["K_stanet"] = node_table.KFAK.values.astype(np.float64) if add_layers: @@ -152,11 +153,14 @@ def create_valve_and_pipe(net, stored_data, index_mapping, net_params, stanet_li stanet_nr=-999, stanet_id='aux_' + j_ref['stanet_id'], p_stanet=np.NaN, stanet_active=bool(row.ISACTIVE), **add_info ) + text_k = 293 + if hasattr(row, "TU"): + text_k = row.TU + 273.15 pandapipes.create_pipe_from_parameters( net, node_mapping[from_stanet_nr], j_aux, length_km=row.RORL / 1000, diameter_m=float(row.DM / 1000), k_mm=row.RAU, loss_coefficient=row.ZETA, name="pipe_%s_%s" % (str(row.ANFNAM), 'aux_' + str(row.ENDNAM)), - in_service=bool(row.ISACTIVE), stanet_nr=-999, + text_k=text_k, in_service=bool(row.ISACTIVE), stanet_nr=-999, stanet_id='pipe_valve_' + str(row.STANETID), v_stanet=row.VM, stanet_active=bool(row.ISACTIVE), stanet_valid=False, **add_info ) @@ -559,10 +563,14 @@ def create_geodata_sections(row): if add_layers: add_info["stanet_layer"] = pipes.LAYER.values.astype(str) # TODO: v_stanet might have to be extended by house connections VMA and VMB + text_k = 293 + if "TU" in pipes.columns: + text_k = pipes.TU.values.astype(np.float64) + 273.15 pandapipes.create_pipes_from_parameters( net, pipe_sections.fj.values, pipe_sections.tj.values, pipe_sections.length.values / 1000, pipes.DM.values / 1000, pipes.RAU.values, pipes.ZETA.values, type="main_pipe", - stanet_std_type=pipes.ROHRTYP.values, in_service=pipes.ISACTIVE.values, + stanet_std_type=pipes.ROHRTYP.values, in_service=pipes.ISACTIVE.values, text_k=text_k, + alpha_w_per_m2k=pipes.WDZAHL.values.astype(np.float64), name=["pipe_%s_%s_%s" % (nf, nt, sec) for nf, nt, sec in zip( pipes.ANFNAM.values, pipes.ENDNAM.values, pipe_sections.section_no.values)], stanet_nr=pipes.RECNO.values, stanet_id=pipes.STANETID.values, @@ -574,27 +582,26 @@ def create_geodata_sections(row): ) -def create_heat_exchangers(net, stored_data, connection_table, index_mapping, add_layers): +def create_heat_exchangers_stanet(net, stored_data, index_mapping, add_layers, add_flow=False): """ Creates pandapipes heat exchangers from STANET connections. :param net: :type net: :param stored_data: :type stored_data: - :param connection_table: - :type connection_table: :param index_mapping: :type index_mapping: :param add_layers: :type add_layers: + :param add_flow: + :type add_flow: :return: :rtype: """ if "heat_exchangers" not in stored_data: return - heat_ex_table = stored_data["heat_exchangers"] + heat_exchanger = stored_data["heat_exchangers"] logger.info("Creating all heat exchangers.") - heat_exchanger = heat_ex_table.loc[~heat_ex_table.RECNO.isin(connection_table.SNUM.values)] node_mapping = index_mapping["nodes"] for row in heat_exchanger.itertuples(): @@ -616,9 +623,14 @@ def create_heat_exchangers(net, stored_data, connection_table, index_mapping, ad add_info = dict() if add_layers: add_info["stanet_layer"] = str(row.LAYER) + if add_flow: + add_info["flow_stanet"] = row.FLUSS + qext = 0 + if hasattr(row, "WAERMECALC"): + qext = getattr(row, "WAERMECALC") * (-1000) # TODO: there is no qext given!!! pandapipes.create_heat_exchanger( - net, node_mapping[from_stanet_nr], node_mapping[to_stanet_nr], qext_w=0, + net, node_mapping[from_stanet_nr], node_mapping[to_stanet_nr], qext_w=qext, diameter_m=float(row.DM / 1000), loss_coefficient=row.ZETA, std_type=row.ROHRTYP, in_service=bool(row.ISACTIVE), name="heat_exchanger_%s_%s" % (row.ANFNAM, row.ENDNAM), stanet_nr=int(row.RECNO), stanet_id=str(row.STANETID), v_stanet=row.VM, @@ -679,11 +691,15 @@ def create_pipes_from_remaining_pipe_table(net, stored_data, connection_table, i add_info = dict() if add_layers: add_info["stanet_layer"] = p_tbl.LAYER.values.astype(str) + text_k = 293 + if "TU" in p_tbl.columns: + text_k = p_tbl.TU.values.astype(np.float64) + 273.15 pandapipes.create_pipes_from_parameters( net, from_junctions, to_junctions, length_km=p_tbl.RORL.values.astype(np.float64) / 1000, type="main_pipe", diameter_m=p_tbl.DM.values.astype(np.float64) / 1000, loss_coefficient=p_tbl.ZETA.values, stanet_std_type=p_tbl.ROHRTYP.values, k_mm=p_tbl.RAU.values, in_service=p_tbl.ISACTIVE.values.astype(np.bool_), + alpha_w_per_m2k=p_tbl.WDZAHL.values.astype(np.float64), text_k=text_k, name=["pipe_%s_%s" % (anf, end) for anf, end in zip(from_names[valid], to_names[valid])], stanet_nr=p_tbl.RECNO.values.astype(np.int32), stanet_id=p_tbl.STANETID.values.astype(str), v_stanet=p_tbl.VM.values, geodata=geodata, @@ -990,11 +1006,15 @@ def create_geodata_sections(row): if add_layers: add_info["stanet_layer"] = hp_data.LAYER.values.astype(str) # TODO: v_stanet might have to be extended by house connections VMA and VMB + text_k = 293 + if "TU" in hp_data.columns: + text_k = hp_data.TU.values.astype(np.float64) + 273.15 pandapipes.create_pipes_from_parameters( net, hp_data.fj.values, hp_data.tj.values, hp_data.length.values / 1000, hp_data.DM.values / 1000, hp_data.RAU.values, hp_data.ZETA.values, type="house_pipe", stanet_std_type=hp_data.ROHRTYP.values, - in_service=hp_data.ISACTIVE.values if houses_in_calculation else False, + in_service=hp_data.ISACTIVE.values if houses_in_calculation else False, text_k=text_k, + alpha_w_per_m2k=hp_data.WDZAHL.values.astype(np.float64), name=["pipe_%s_%s_%s" % (nf, nt, sec) for nf, nt, sec in zip( hp_data.CLIENTID.values, hp_data.CLIENT2ID.values, hp_data.section_no.values)], stanet_nr=hp_data.RECNO.values, stanet_id=hp_data.STANETID.values, diff --git a/pandapipes/create.py b/pandapipes/create.py index e4e2b085a..650305d5a 100644 --- a/pandapipes/create.py +++ b/pandapipes/create.py @@ -1824,8 +1824,8 @@ def create_heat_exchangers(net, from_junctions, to_junctions, diameter_m, qext_w def create_fluid_from_lib(net, name, overwrite=True): """ Creates a fluid from library (if there is an entry) and sets net["fluid"] to this value. - Currently, existing fluids in the library are: "hgas", "lgas", "hydrogen", "methane", "water", - "air". + Currently, existing fluids in the library are: "hgas", "lgas", "hydrogen", "methane", "water","biomethane_pure", + "biomethane_treated", "air". :param net: The net for which this fluid should be created :type net: pandapipesNet diff --git a/pandapipes/idx_branch.py b/pandapipes/idx_branch.py index 613523bbf..4d7d2942e 100644 --- a/pandapipes/idx_branch.py +++ b/pandapipes/idx_branch.py @@ -2,6 +2,10 @@ # and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved. # Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. +# branch types +# no types defined + +# branch indices TABLE_IDX = 0 # number of the table that this branch belongs to ELEMENT_IDX = 1 # index of the element that this branch belongs to (within the given table) FROM_NODE = 2 # f, from bus number @@ -13,38 +17,35 @@ RHO = 8 # Density in [kg/m^3 ETA = 9 # Dynamic viscosity in [Pas] K = 10 # Pipe roughness in [m] -TINIT = 11 # Temperature in [K] -VINIT = 12 # velocity in [m/s] -RE = 13 # Reynolds number -LAMBDA = 14 # Lambda -JAC_DERIV_DV = 15 # Slot for the derivative by velocity # df_dv -JAC_DERIV_DP = 16 # Slot for the derivative by pressure from_node # df_dp -JAC_DERIV_DP1 = 17 # Slot for the derivative by pressure to_node # df_dp1 -LOAD_VEC_BRANCHES = 18 # Slot for the load vector for the branches : pressure difference between nodes (Bar) #load_vec -JAC_DERIV_DV_NODE = 19 # Slot for the derivative by velocity for the nodes connected to branch #df_dv_nodes -LOAD_VEC_NODES = 20 # Slot for the load vector of the nodes connected to branch : mass_flow (kg_s) # load_vec_nodes -LOSS_COEFFICIENT = 21 -CP = 22 # Slot for fluid heat capacity at constant pressure : cp = (J/kg.K) -ALPHA = 23 # Slot for heat transfer coefficient: U = (W/m2.K) -JAC_DERIV_DT = 24 # Slot for the derivative by temperature from_node # df_dt -JAC_DERIV_DT1 = 25 # Slot for the derivative by temperature to_node # df_dt1 -LOAD_VEC_BRANCHES_T = 26 -T_OUT = 27 # Internal slot for outlet pipe temperature -JAC_DERIV_DT_NODE = 28 # Slot for the derivative for T for the nodes connected to branch -LOAD_VEC_NODES_T = 29 -VINIT_T = 30 -FROM_NODE_T = 31 -TO_NODE_T = 32 -QEXT = 33 # heat input in [W] -TEXT = 34 -STD_TYPE = 35 -PL = 36 # Pressure lift [bar] -TL = 37 # Temperature lift [K] -BRANCH_TYPE = 38 # branch type relevant for the pressure controller -PRESSURE_RATIO = 39 # boost ratio for compressors with proportional pressure lift -T_OUT_OLD = 40 -Kv_max = 41 # dynamic valve flow characteristics -DESIRED_MV = 42 # Final Control Element (FCE) Desired Manipulated Value percentage opened -ACTUAL_POS = 43 # Final Control Element (FCE) Actual Position Value percentage opened +VINIT = 11 # velocity in [m/s] +RE = 12 # Reynolds number +LAMBDA = 13 # Lambda +JAC_DERIV_DV = 14 # Slot for the derivative by velocity +JAC_DERIV_DP = 15 # Slot for the derivative by pressure from_node +JAC_DERIV_DP1 = 16 # Slot for the derivative by pressure to_node +LOAD_VEC_BRANCHES = 17 # Slot for the load vector for the branches +JAC_DERIV_DV_NODE = 18 # Slot for the derivative by velocity for the nodes connected to branch +LOAD_VEC_NODES = 19 # Slot for the load vector of the nodes connected to branch +LOSS_COEFFICIENT = 20 +CP = 21 # Slot for fluid heat capacity values +ALPHA = 22 # Slot for heat transfer coefficient +JAC_DERIV_DT = 23 +JAC_DERIV_DT1 = 24 +LOAD_VEC_BRANCHES_T = 25 +TOUTINIT = 26 # Internal slot for outlet pipe temperature +JAC_DERIV_DT_NODE = 27 # Slot for the derivative fpr T for the nodes connected to branch +LOAD_VEC_NODES_T = 28 +VINIT_T = 29 +FROM_NODE_T = 30 +TO_NODE_T = 31 +QEXT = 32 # heat input in [W] +TEXT = 33 +PL = 34 +TL = 35 # Temperature lift [K] +BRANCH_TYPE = 36 # branch type relevant for the pressure controller +T_OUT_OLD = 37 +Kv_max = 38 # dynamic valve flow characteristics +DESIRED_MV = 39 # Final Control Element (FCE) Desired Manipulated Value percentage opened +ACTUAL_POS = 40 # Final Control Element (FCE) Actual Position Value percentage opened -branch_cols = 44 \ No newline at end of file +branch_cols = 41 diff --git a/pandapipes/idx_node.py b/pandapipes/idx_node.py index 309e6ed6a..7b1f8b1f7 100644 --- a/pandapipes/idx_node.py +++ b/pandapipes/idx_node.py @@ -2,14 +2,14 @@ # and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved. # Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. -# define bus types +# node types P = 1 # Reference node, pressure is fixed L = 2 # All other nodes T = 10 # Reference node with fixed temperature, otherwise 0 PC = 20 # Controlled node with fixed pressure p NONE = 3 # None -# define the indices +# node indices TABLE_IDX = 0 # number of the table that this node belongs to ELEMENT_IDX = 1 # index of the element that this node belongs to (within the given table) NODE_TYPE = 2 # junction type diff --git a/pandapipes/pf/derivative_calculation.py b/pandapipes/pf/derivative_calculation.py index 0dea2287b..bb95bbefc 100644 --- a/pandapipes/pf/derivative_calculation.py +++ b/pandapipes/pf/derivative_calculation.py @@ -1,9 +1,12 @@ import numpy as np -from pandapipes.idx_branch import LENGTH, ETA, RHO, D, K, RE, LAMBDA, TINIT, LOAD_VEC_BRANCHES, \ +from pandapipes.idx_branch import LENGTH, ETA, RHO, D, K, RE, LAMBDA, LOAD_VEC_BRANCHES, \ JAC_DERIV_DV, JAC_DERIV_DP, JAC_DERIV_DP1, LOAD_VEC_NODES, JAC_DERIV_DV_NODE, VINIT, \ - FROM_NODE, TO_NODE + FROM_NODE, TO_NODE, CP, VINIT_T, FROM_NODE_T, TOUTINIT, TEXT, AREA, ALPHA, TL, QEXT, LOAD_VEC_NODES_T, \ + LOAD_VEC_BRANCHES_T, JAC_DERIV_DT, JAC_DERIV_DT1, JAC_DERIV_DT_NODE, T_OUT_OLD +from pandapipes.idx_node import TINIT as TINIT_NODE from pandapipes.properties.fluids import get_fluid +from pandapipes.pf.pipeflow_setup import get_net_option def calculate_derivatives_hydraulic(net, branch_pit, node_pit, options): @@ -35,7 +38,6 @@ def calculate_derivatives_hydraulic(net, branch_pit, node_pit, options): to_nodes = branch_pit[:, TO_NODE].astype(np.int32) tinit_branch, height_difference, p_init_i_abs, p_init_i1_abs = \ get_derived_values(node_pit, from_nodes, to_nodes, options["use_numba"]) - branch_pit[:, TINIT] = tinit_branch if not gas_mode: if options["use_numba"]: @@ -62,7 +64,7 @@ def calculate_derivatives_hydraulic(net, branch_pit, node_pit, options): der_comp = fluid.get_der_compressibility() * der_p_m der_comp1 = fluid.get_der_compressibility() * der_p_m1 load_vec, load_vec_nodes, df_dv, df_dv_nodes, df_dp, df_dp1 = derivatives_hydraulic_comp( - branch_pit, lambda_, der_lambda, p_init_i_abs, p_init_i1_abs, height_difference, + node_pit, branch_pit, lambda_, der_lambda, p_init_i_abs, p_init_i1_abs, height_difference, comp_fact, der_comp, der_comp1) branch_pit[:, LOAD_VEC_BRANCHES] = load_vec @@ -73,6 +75,50 @@ def calculate_derivatives_hydraulic(net, branch_pit, node_pit, options): branch_pit[:, JAC_DERIV_DV_NODE] = df_dv_nodes +def calculate_derivatives_thermal(net, branch_pit, node_pit, options): + cp = branch_pit[:, CP] + rho = branch_pit[:, RHO] + v_init = branch_pit[:, VINIT_T] + from_nodes = branch_pit[:, FROM_NODE_T].astype(np.int32) + t_init_i = node_pit[from_nodes, TINIT_NODE] + t_init_i1 = branch_pit[:, TOUTINIT] + t_amb = branch_pit[:, TEXT] + area = branch_pit[:, AREA] + length = branch_pit[:, LENGTH] + alpha = branch_pit[:, ALPHA] * np.pi * branch_pit[:, D] + tl = branch_pit[:, TL] + qext = branch_pit[:, QEXT] + t_m = (t_init_i1 + t_init_i) / 2 + + transient = get_net_option(net, "transient") + + tvor = branch_pit[:, T_OUT_OLD] + + delta_t = get_net_option(net, "dt") + + if transient: + branch_pit[:, LOAD_VEC_BRANCHES_T] = \ + -(rho * area * cp * (t_m - tvor) * (1 / delta_t) + rho * area * cp * v_init * ( + -t_init_i + t_init_i1 - tl) / length + - alpha * (t_amb - t_m) + qext) + + branch_pit[:, JAC_DERIV_DT] = - rho * area * cp * v_init / length + alpha \ + + rho * area * cp / delta_t + branch_pit[:, JAC_DERIV_DT1] = rho * area * cp * v_init / length + 0 * alpha \ + + rho * area * cp / delta_t + else: + branch_pit[:, LOAD_VEC_BRANCHES_T] = \ + -(rho * area * cp * v_init * (-t_init_i + t_init_i1 - tl) + - alpha * (t_amb - t_m) * length + qext) + + branch_pit[:, JAC_DERIV_DT] = - rho * area * cp * v_init + alpha / 2 * length + branch_pit[:, JAC_DERIV_DT1] = rho * area * cp * v_init + alpha / 2 * length + + branch_pit[:, JAC_DERIV_DT_NODE] = rho * v_init * branch_pit[:, AREA] + branch_pit[:, LOAD_VEC_NODES_T] = rho * v_init * branch_pit[:, AREA] \ + * t_init_i1 + + def get_derived_values(node_pit, from_nodes, to_nodes, use_numba): if use_numba: from pandapipes.pf.derivative_toolbox_numba import calc_derived_values_numba @@ -110,11 +156,11 @@ def calc_lambda(v, eta, rho, d, k, gas_mode, friction_model, lengths, options): """ if options["use_numba"]: from pandapipes.pf.derivative_toolbox_numba import calc_lambda_nikuradse_incomp_numba as \ - calc_lambda_nikuradse_incomp, colebrook_numba as colebrook,\ + calc_lambda_nikuradse_incomp, colebrook_numba as colebrook, \ calc_lambda_nikuradse_comp_numba as calc_lambda_nikuradse_comp else: from pandapipes.pf.derivative_toolbox import calc_lambda_nikuradse_incomp_np as \ - calc_lambda_nikuradse_incomp, colebrook_np as colebrook,\ + calc_lambda_nikuradse_incomp, colebrook_np as colebrook, \ calc_lambda_nikuradse_comp_np as calc_lambda_nikuradse_comp if gas_mode: re, lambda_laminar, lambda_nikuradse = calc_lambda_nikuradse_comp(v, d, k, eta, rho) @@ -134,7 +180,7 @@ def calc_lambda(v, eta, rho, d, k, gas_mode, friction_model, lengths, options): "argument to the pipeflow.") return lambda_colebrook, re elif friction_model == "swamee-jain": - lambda_swamee_jain = 1.325 / ((np.log10(k/(3.7*d) + 5.74/(re**0.9)))**2) + lambda_swamee_jain = 0.25 / ((np.log10(k / (3.7 * d) + 5.74 / (re ** 0.9))) ** 2) return lambda_swamee_jain, re else: # lambda_tot = np.where(re > 2300, lambda_laminar + lambda_nikuradse, lambda_laminar) @@ -182,7 +228,7 @@ def calc_der_lambda(v, eta, rho, d, k, friction_model, lambda_pipe): return lambda_colebrook_der elif friction_model == "swamee-jain": - param = k/(3.7*d) + 5.74 * (np.abs(eta))**0.9 / ((np.abs(rho*v_corr*d))**0.9) + param = k / (3.7 * d) + 5.74 * (np.abs(eta)) ** 0.9 / ((np.abs(rho * v_corr * d)) ** 0.9) # 0.5 / (log(10) * log(param)^3 * param) * 5.166 * abs(eta)^0.9 / (abs(rho * d)^0.9 # * abs(v_corr)^1.9) lambda_swamee_jain_der = 0.5 / np.log(10) / (np.log(param) ** 3) / param * 5.166 \ diff --git a/pandapipes/pf/derivative_toolbox.py b/pandapipes/pf/derivative_toolbox.py index e2e89ddc4..ba786b937 100644 --- a/pandapipes/pf/derivative_toolbox.py +++ b/pandapipes/pf/derivative_toolbox.py @@ -7,8 +7,8 @@ from pandapipes.constants import P_CONVERSION, GRAVITATION_CONSTANT, NORMAL_PRESSURE, \ NORMAL_TEMPERATURE -from pandapipes.idx_branch import LENGTH, LAMBDA, D, LOSS_COEFFICIENT as LC, RHO, PL, AREA, TINIT, \ - VINIT +from pandapipes.idx_branch import LENGTH, LAMBDA, D, LOSS_COEFFICIENT as LC, RHO, PL, AREA, \ + VINIT, TOUTINIT, FROM_NODE from pandapipes.idx_node import HEIGHT, PINIT, PAMB, TINIT as TINIT_NODE @@ -32,7 +32,7 @@ def derivatives_hydraulic_incomp_np(branch_pit, der_lambda, p_init_i_abs, p_init return load_vec, load_vec_nodes, df_dv, df_dv_nodes, df_dp, df_dp1 -def derivatives_hydraulic_comp_np(branch_pit, lambda_, der_lambda, p_init_i_abs, p_init_i1_abs, +def derivatives_hydraulic_comp_np(node_pit, branch_pit, lambda_, der_lambda, p_init_i_abs, p_init_i1_abs, height_difference, comp_fact, der_comp, der_comp1): # Formulas for gas pressure loss according to laminar version v_init_abs = np.abs(branch_pit[:, VINIT]) @@ -40,12 +40,13 @@ def derivatives_hydraulic_comp_np(branch_pit, lambda_, der_lambda, p_init_i_abs, p_diff = p_init_i_abs - p_init_i1_abs p_sum = p_init_i_abs + p_init_i1_abs p_sum_div = np.divide(1, p_sum) - - const_lambda = np.divide(NORMAL_PRESSURE * branch_pit[:, RHO] * branch_pit[:, TINIT], + from_nodes = branch_pit[:, FROM_NODE].astype(np.int32) + tm = (node_pit[from_nodes, TINIT_NODE] + branch_pit[:, TOUTINIT]) / 2 + const_lambda = np.divide(NORMAL_PRESSURE * branch_pit[:, RHO] * tm, NORMAL_TEMPERATURE * P_CONVERSION) const_height = np.divide( branch_pit[:, RHO] * NORMAL_TEMPERATURE * GRAVITATION_CONSTANT * height_difference, - 2 * NORMAL_PRESSURE * branch_pit[:, TINIT] * P_CONVERSION) + 2 * NORMAL_PRESSURE * tm * P_CONVERSION) friction_term = np.divide(lambda_ * branch_pit[:, LENGTH], branch_pit[:, D]) + branch_pit[:, LC] load_vec = p_diff + branch_pit[:, PL] + const_height * p_sum \ diff --git a/pandapipes/pf/derivative_toolbox_numba.py b/pandapipes/pf/derivative_toolbox_numba.py index a3b7f3eb8..3e125a114 100644 --- a/pandapipes/pf/derivative_toolbox_numba.py +++ b/pandapipes/pf/derivative_toolbox_numba.py @@ -3,8 +3,8 @@ from pandapipes.constants import P_CONVERSION, GRAVITATION_CONSTANT, NORMAL_PRESSURE, \ NORMAL_TEMPERATURE -from pandapipes.idx_branch import LENGTH, LAMBDA, D, LOSS_COEFFICIENT as LC, RHO, PL, AREA, TINIT, \ - VINIT +from pandapipes.idx_branch import LENGTH, LAMBDA, D, LOSS_COEFFICIENT as LC, RHO, PL, AREA, \ + VINIT, FROM_NODE, TO_NODE from pandapipes.idx_node import HEIGHT, PAMB, PINIT, TINIT as TINIT_NODE try: @@ -43,9 +43,9 @@ def derivatives_hydraulic_incomp_numba(branch_pit, der_lambda, p_init_i_abs, p_i return load_vec, load_vec_nodes, df_dv, df_dv_nodes, df_dp, df_dp1 -@jit((float64[:, :], float64[:], float64[:], float64[:], float64[:], float64[:], float64[:], +@jit((float64[:, :], float64[:, :], float64[:], float64[:], float64[:], float64[:], float64[:], float64[:], float64[:], float64[:]), nopython=True, cache=False) -def derivatives_hydraulic_comp_numba(branch_pit, lambda_, der_lambda, p_init_i_abs, p_init_i1_abs, +def derivatives_hydraulic_comp_numba(node_pit, branch_pit, lambda_, der_lambda, p_init_i_abs, p_init_i1_abs, height_difference, comp_fact, der_comp, der_comp1): le = lambda_.shape[0] load_vec = np.zeros_like(lambda_) @@ -54,6 +54,8 @@ def derivatives_hydraulic_comp_numba(branch_pit, lambda_, der_lambda, p_init_i_a df_dp1 = np.zeros_like(lambda_) * (-1) load_vec_nodes = np.zeros_like(der_lambda) df_dv_nodes = np.zeros_like(der_lambda) + from_nodes = branch_pit[:, FROM_NODE].astype(np.int32) + to_nodes = branch_pit[:, TO_NODE].astype(np.int32) # Formulas for gas pressure loss according to laminar version for i in range(le): @@ -63,12 +65,15 @@ def derivatives_hydraulic_comp_numba(branch_pit, lambda_, der_lambda, p_init_i_a p_diff = p_init_i_abs[i] - p_init_i1_abs[i] p_sum = p_init_i_abs[i] + p_init_i1_abs[i] p_sum_div = np.divide(1, p_sum) + fn = from_nodes[i] + tn = to_nodes[i] + tm = (node_pit[fn, TINIT_NODE] + node_pit[tn, TINIT_NODE]) / 2 - const_lambda = np.divide(NORMAL_PRESSURE * branch_pit[i][RHO] * branch_pit[i][TINIT], + const_lambda = np.divide(NORMAL_PRESSURE * branch_pit[i][RHO] * tm, NORMAL_TEMPERATURE * P_CONVERSION) const_height = np.divide( branch_pit[i][RHO] * NORMAL_TEMPERATURE * GRAVITATION_CONSTANT * height_difference[i], - 2 * NORMAL_PRESSURE * branch_pit[i][TINIT] * P_CONVERSION) + 2 * NORMAL_PRESSURE * tm * P_CONVERSION) friction_term = np.divide(lambda_[i] * branch_pit[i][LENGTH], branch_pit[i][D]) + branch_pit[i][LC] diff --git a/pandapipes/pf/pipeflow_setup.py b/pandapipes/pf/pipeflow_setup.py index 6e4e2c996..151537bb0 100644 --- a/pandapipes/pf/pipeflow_setup.py +++ b/pandapipes/pf/pipeflow_setup.py @@ -9,9 +9,10 @@ from scipy.sparse import coo_matrix, csgraph from pandapipes.idx_branch import FROM_NODE, TO_NODE, branch_cols, \ - ACTIVE as ACTIVE_BR + ACTIVE as ACTIVE_BR, VINIT from pandapipes.idx_node import NODE_TYPE, P, NODE_TYPE_T, node_cols, T, ACTIVE as ACTIVE_ND, \ TABLE_IDX as TABLE_IDX_ND, ELEMENT_IDX as ELEMENT_IDX_ND +from pandapipes.pf.internals_toolbox import _sum_by_group from pandapipes.properties.fluids import get_fluid try: @@ -161,8 +162,9 @@ def get_lookup(net, pit_type="node", lookup_type="index"): """ pit_type = pit_type.lower() lookup_type = lookup_type.lower() - all_lookup_types = ["index", "table", "from_to", "active", "length", "from_to_active", - "index_active"] + all_lookup_types = ["index", "table", "from_to", "active_hydraulics", "active_heat_transfer", + "length", "from_to_active_hydraulics", "from_to_active_heat_transfer", + "index_active_hydraulics", "index_active_heat_transfer"] if lookup_type not in all_lookup_types: type_names = "', '".join(all_lookup_types) logger.error("No lookup type '%s' exists. Please choose one of '%s'." @@ -187,7 +189,7 @@ def set_user_pf_options(net, reset=False, **kwargs): :type net: pandapipesNet :param reset: Specifies whether the user_pf_options is removed before setting new options :type reset: bool, default False - :param kwargs: pipeflow options that shall be set, e. g. tol_v = 1e-7 + :param kwargs: pipeflow options that shall be set, e.g. tol_v = 1e-7 :return: No output """ if reset or 'user_pf_options' not in net.keys(): @@ -239,7 +241,7 @@ def init_options(net, local_parameters): automatically with respect to the convergence behaviour. - **mode** (str): "hydraulics" - Define the calculation mode: what shall be calculated - \ - solely hydraulics ('hydraulic'), solely heat transfer('heat') or both combined \ + solely hydraulics ('hydraulics'), solely heat transfer('heat') or both combined \ ('all'). - **only_update_hydraulic_matrix** (bool): False - If True, the system matrix is not \ @@ -350,6 +352,7 @@ def initialize_pit(net): for comp in net['component_list']: comp.create_pit_node_entries(net, pit["node"]) comp.create_pit_branch_entries(net, pit["branch"]) + comp.create_component_array(net, pit["components"]) return pit["node"], pit["branch"] @@ -373,7 +376,8 @@ def create_empty_pit(net): branch_length = get_lookup(net, "branch", "length") # init empty pit pit = {"node": np.empty((node_length, node_cols), dtype=np.float64), - "branch": np.empty((branch_length, branch_cols), dtype=np.float64)} + "branch": np.empty((branch_length, branch_cols), dtype=np.float64), + "components": {}} net["_pit"] = pit return pit @@ -435,7 +439,82 @@ def create_lookups(net): "internal_nodes_lookup": internal_nodes_lookup} -def check_connectivity(net, branch_pit, node_pit, check_heat): +def identify_active_nodes_branches(net, branch_pit, node_pit, hydraulic=True): + """ + Function that creates the connectivity lookup for nodes and branches. If the option \ + "check_connectivity" is set, a full connectivity check is performed based on a sparse matrix \ + graph search. Otherwise, only the nodes and branches are identified that are inactive, which \ + means:\ + - in case of hydraulics, just use the "ACTIVE" identifier of the respective components\ + - in case of heat transfer, use the hydraulic result to check which branches are traversed \ + by the fluid and a simple rule to make sure that active nodes are connected to at least one\ + traversed branch\ + The result of this connectivity search is stored in the lookups (e.g. as \ + net["_lookups"]["node_active_hydraulics"]) + + :param net: the pandapipes net for which to identify the connectivity + :type net: pandapipes.pandapipesNet + :param branch_pit: Internal array with branch entries + :type branch_pit: np.array + :param node_pit: Internal array with node entries + :type node_pit: np.array + :param hydraulic: flag for the mode (if True, do the check for the hydraulic simulation, \ + otherwise for the heat transfer simulation with other considerations) + :type hydraulic: bool, default True + :return: No output + """ + if hydraulic: + # connectivity check for hydraulic simulation + if get_net_option(net, "check_connectivity"): + nodes_connected, branches_connected = check_connectivity(net, branch_pit, node_pit) + else: + # if connectivity check is switched off, still consider oos elements + nodes_connected = node_pit[:, ACTIVE_ND].astype(np.bool_) + branches_connected = branch_pit[:, ACTIVE_BR].astype(np.bool_) + else: + # connectivity check for heat simulation (needs to consider branches with 0 velocity as + # well) + if get_net_option(net, "check_connectivity"): + # full connectivity check for hydraulic simulation + nodes_connected, branches_connected = check_connectivity(net, branch_pit, node_pit, + mode="heat_transfer") + else: + # if no full connectivity check is performed, all nodes that are not connected to the + # rest of the network wrt. flow can be identified by a more performant sum_by_group_call + # check for branches that are not traversed (for temperature calculation, this means + # that they are "out of service") + branches_connected = get_lookup(net, "branch", "active_hydraulics") \ + & branches_connected_flow(branch_pit) + fn = branch_pit[:, FROM_NODE].astype(np.int32) + tn = branch_pit[:, TO_NODE].astype(np.int32) + fn_tn, flow = _sum_by_group( + get_net_option(net, "use_numba"), np.concatenate([fn, tn]), + np.concatenate([branches_connected, branches_connected]).astype(np.int32) + ) + nodes_connected = np.copy(get_lookup(net, "node", "active_hydraulics")) + # set nodes oos that are not connected to any branches with flow > 0 (0.1 is arbitrary + # here, any value between 0 and 1 should work, excluding 0 and 1) + nodes_connected[fn_tn] = nodes_connected[fn_tn] & (flow > 0.1) + mode = "hydraulics" if hydraulic else "heat_transfer" + net["_lookups"]["node_active_" + mode] = nodes_connected + net["_lookups"]["branch_active_" + mode] = branches_connected + + +def branches_connected_flow(branch_pit): + """ + Simple function to identify branches with flow based on the calculated velocity. + + :param branch_pit: The pandapipes internal table of the network (including hydraulics results) + :type branch_pit: np.array + :return: branches_connected_flow - lookup array if branch is connected wrt. flow + :rtype: np.array + """ + # TODO: is this formulation correct or could there be any caveats? + return ~np.isnan(branch_pit[:, VINIT]) \ + & ~np.isclose(branch_pit[:, VINIT], 0, rtol=1e-10, atol=1e-10) + + +def check_connectivity(net, branch_pit, node_pit, mode="hydraulics"): """ Perform a connectivity check which means that network nodes are identified that don't have any connection to an external grid component. Quick overview over the steps of this function: @@ -461,40 +540,30 @@ def check_connectivity(net, branch_pit, node_pit, check_heat): :type branch_pit: np.array :param node_pit: Internal array with node entries :type node_pit: np.array - :param check_heat: Flag which determines whether to also check for connectivity to heat \ - external grids - :type check_heat: bool - :return: (nodes_connected_hyd, branches_connected) - Lookups of np.arrays stating which of the + :return: (nodes_connected, branches_connected) - Lookups of np.arrays stating which of the internal nodes and branches are reachable from any of the hyd_slacks (np mask). :rtype: tuple(np.array) """ - active_branch_lookup = branch_pit[:, ACTIVE_BR].astype(bool) - active_node_lookup = node_pit[:, ACTIVE_ND].astype(bool) - from_nodes = branch_pit[:, FROM_NODE].astype(np.int32) - to_nodes = branch_pit[:, TO_NODE].astype(np.int32) - hyd_slacks = np.where((node_pit[:, NODE_TYPE] == P) & active_node_lookup)[0] - # hyd_slacks = np.where(((node_pit[:, NODE_TYPE] == P) | (node_pit[:, NODE_TYPE] == PC)) - # & active_node_lookup)[0] - - nodes_connected, branches_connected = perform_connectivity_search( - net, node_pit, hyd_slacks, from_nodes, to_nodes, active_node_lookup, active_branch_lookup, - mode="hydraulics") - if not check_heat: - return nodes_connected, branches_connected - - heat_slacks = np.where((node_pit[:, NODE_TYPE_T] == T) & nodes_connected)[0] - if len(heat_slacks) == len(hyd_slacks) and np.all(heat_slacks == hyd_slacks): - return nodes_connected, branches_connected - - nodes_connected, branches_connected = perform_connectivity_search( - net, node_pit, heat_slacks, from_nodes, to_nodes, nodes_connected, branches_connected, - mode="heat transfer") - return nodes_connected, branches_connected + if mode == "hydraulics": + active_branch_lookup = branch_pit[:, ACTIVE_BR].astype(np.bool_) + active_node_lookup = node_pit[:, ACTIVE_ND].astype(np.bool_) + slacks = np.where((node_pit[:, NODE_TYPE] == P) & active_node_lookup)[0] + else: + active_branch_lookup = branches_connected_flow(branch_pit) \ + & get_lookup(net, "branch", "active_hydraulics") + active_node_lookup = node_pit[:, ACTIVE_ND].astype(np.bool_)\ + & get_lookup(net, "node", "active_hydraulics") + slacks = np.where((node_pit[:, NODE_TYPE_T] == T) & active_node_lookup)[0] + + return perform_connectivity_search(net, node_pit, branch_pit, slacks, active_node_lookup, + active_branch_lookup, mode=mode) -def perform_connectivity_search(net, node_pit, slack_nodes, from_nodes, to_nodes, +def perform_connectivity_search(net, node_pit, branch_pit, slack_nodes, active_node_lookup, active_branch_lookup, mode="hydraulics"): len_nodes = len(node_pit) + from_nodes = branch_pit[:, FROM_NODE].astype(np.int32) + to_nodes = branch_pit[:, TO_NODE].astype(np.int32) nobranch = np.sum(active_branch_lookup) active_from_nodes = from_nodes[active_branch_lookup] active_to_nodes = to_nodes[active_branch_lookup] @@ -569,7 +638,7 @@ def get_table_index_list(net, pit_array, pit_indices, pit_type="node"): for tbl in tables] -def reduce_pit(net, node_pit, branch_pit, nodes_connected, branches_connected): +def reduce_pit(net, node_pit, branch_pit, mode="hydraulics"): """ Create an internal ("active") pit with all nodes and branches that are actually in_service. This is also done for different lookups (e.g. the from_to indices for this pit and the node index @@ -582,44 +651,46 @@ def reduce_pit(net, node_pit, branch_pit, nodes_connected, branches_connected): :type node_pit: np.array :param branch_pit: The internal structure branch array :type branch_pit: np.array - :param nodes_connected: A mask array stating which nodes are actually connected to the rest of\ - the net - :type nodes_connected: np.array - :param branches_connected: A mask array stating which branches are actually connected to the \ - rest of the net - :type branches_connected: np.array + :param mode: the mode of the calculation (either "hydraulics" or "heat_transfer") for storing /\ + retrieving correct lookups + :type mode: str, default "hydraulics" :return: No output """ active_pit = dict() els = dict() reduced_node_lookup = None + nodes_connected = get_lookup(net, "node", "active_" + mode) + branches_connected = get_lookup(net, "branch", "active_" + mode) if np.alltrue(nodes_connected): - net["_lookups"]["node_from_to_active"] = copy.deepcopy(get_lookup(net, "node", "from_to")) - net["_lookups"]["node_index_active"] = copy.deepcopy(get_lookup(net, "node", "index")) + net["_lookups"]["node_from_to_active_" + mode] = copy.deepcopy( + get_lookup(net, "node", "from_to")) + net["_lookups"]["node_index_active_" + mode] = copy.deepcopy( + get_lookup(net, "node", "index")) active_pit["node"] = np.copy(node_pit) else: active_pit["node"] = np.copy(node_pit[nodes_connected, :]) reduced_node_lookup = np.cumsum(nodes_connected) - 1 node_idx_lookup = get_lookup(net, "node", "index") - net["_lookups"]["node_index_active"] = { + net["_lookups"]["node_index_active_" + mode] = { tbl: reduced_node_lookup[idx_lookup[idx_lookup != -1]] for tbl, idx_lookup in node_idx_lookup.items()} els["node"] = nodes_connected if np.alltrue(branches_connected): - net["_lookups"]["branch_from_to_active"] = copy.deepcopy(get_lookup(net, "branch", - "from_to")) + net["_lookups"]["branch_from_to_active_" + mode] = copy.deepcopy( + get_lookup(net, "branch", "from_to")) active_pit["branch"] = np.copy(branch_pit) - net["_lookups"]["branch_index_active"] = copy.deepcopy(get_lookup(net, "branch", "index")) + net["_lookups"]["branch_index_active_" + mode] = copy.deepcopy( + get_lookup(net, "branch", "index")) else: active_pit["branch"] = np.copy(branch_pit[branches_connected, :]) branch_idx_lookup = get_lookup(net, "branch", "index") if len(branch_idx_lookup): reduced_branch_lookup = np.cumsum(branches_connected) - 1 - net["_lookups"]["branch_index_active"] = { + net["_lookups"]["branch_index_active_" + mode] = { tbl: reduced_branch_lookup[idx_lookup[idx_lookup != -1]] for tbl, idx_lookup in branch_idx_lookup.items()} else: - net["_lookups"]["branch_index_active"] = dict() + net["_lookups"]["branch_index_active_" + mode] = dict() els["branch"] = branches_connected if reduced_node_lookup is not None: active_pit["branch"][:, FROM_NODE] = reduced_node_lookup[ @@ -627,8 +698,6 @@ def reduce_pit(net, node_pit, branch_pit, nodes_connected, branches_connected): active_pit["branch"][:, TO_NODE] = reduced_node_lookup[ branch_pit[branches_connected, TO_NODE].astype(np.int32)] net["_active_pit"] = active_pit - net["_lookups"]["node_active"] = nodes_connected - net["_lookups"]["branch_active"] = branches_connected for el, connected_els in els.items(): ft_lookup = get_lookup(net, el, "from_to") @@ -639,4 +708,4 @@ def reduce_pit(net, node_pit, branch_pit, nodes_connected, branches_connected): for table, (_, _, len_new) in sorted(aux_lookup.items(), key=lambda x: x[1][0]): from_to_active_lookup[table] = (count, count + len_new) count += len_new - net["_lookups"]["%s_from_to_active" % el] = from_to_active_lookup + net["_lookups"]["%s_from_to_active_%s" % (el, mode)] = from_to_active_lookup diff --git a/pandapipes/pf/result_extraction.py b/pandapipes/pf/result_extraction.py index 7332f6c56..b600e9bd4 100644 --- a/pandapipes/pf/result_extraction.py +++ b/pandapipes/pf/result_extraction.py @@ -2,7 +2,7 @@ from pandapipes.constants import NORMAL_PRESSURE, NORMAL_TEMPERATURE from pandapipes.idx_branch import ELEMENT_IDX, FROM_NODE, TO_NODE, LOAD_VEC_NODES, VINIT, RE, \ - LAMBDA, TINIT, FROM_NODE_T, TO_NODE_T, PL, DESIRED_MV, ACTUAL_POS, QEXT, LOSS_COEFFICIENT as LC + LAMBDA, FROM_NODE_T, TO_NODE_T, PL, TOUTINIT, DESIRED_MV, ACTUAL_POS, QEXT, LOSS_COEFFICIENT as LC from pandapipes.idx_node import TABLE_IDX as TABLE_IDX_NODE, PINIT, PAMB, TINIT as TINIT_NODE from pandapipes.pf.internals_toolbox import _sum_by_group from pandapipes.pf.pipeflow_setup import get_table_number, get_lookup, get_net_option @@ -14,13 +14,15 @@ from pandapower.pf.no_numba import jit -def extract_all_results(net, nodes_connected, branches_connected): +def extract_all_results(net, calculation_mode): """ Extract results from branch pit and node pit and write them to the different tables of the net,\ as defined by the component models. :param net: pandapipes net for which to extract results into net.res_xy :type net: pandapipesNet + :param net: mode of the simulation (e.g. "hydraulics" or "heat" or "all") + :type net: str :return: No output """ @@ -50,8 +52,7 @@ def extract_all_results(net, nodes_connected, branches_connected): } branch_results.update(gas_branch_results) for comp in net['component_list']: - comp.extract_results(net, net["_options"], branch_results, nodes_connected, - branches_connected) + comp.extract_results(net, net["_options"], branch_results, calculation_mode) def get_basic_branch_results(net, branch_pit, node_pit): @@ -78,9 +79,15 @@ def get_branch_results_gas(net, branch_pit, node_pit, from_nodes, to_nodes, v_mp / (p_abs_from[mask] ** 2 - p_abs_to[mask] ** 2) fluid = get_fluid(net) - numerator = NORMAL_PRESSURE * branch_pit[:, TINIT] / NORMAL_TEMPERATURE - normfactor_from = numerator * fluid.get_property("compressibility", p_abs_from) / p_abs_from - normfactor_to = numerator * fluid.get_property("compressibility", p_abs_to) / p_abs_to + t_from = node_pit[from_nodes, TINIT_NODE] + t_to = branch_pit[:, TOUTINIT] + tm = (t_from + t_to) / 2 + numerator_from = NORMAL_PRESSURE * t_from / NORMAL_TEMPERATURE + numerator_to = NORMAL_PRESSURE * t_to / NORMAL_TEMPERATURE + numerator = NORMAL_PRESSURE * tm / NORMAL_TEMPERATURE + + normfactor_from = numerator_from * fluid.get_property("compressibility", p_abs_from) / p_abs_from + normfactor_to = numerator_to * fluid.get_property("compressibility", p_abs_to) / p_abs_to normfactor_mean = numerator * fluid.get_property("compressibility", p_abs_mean) / p_abs_mean v_gas_from = v_mps * normfactor_from @@ -102,7 +109,7 @@ def get_branch_results_gas_numba(net, branch_pit, node_pit, from_nodes, to_nodes comp_mean = fluid.get_property("compressibility", p_abs_mean) v_gas_from, v_gas_to, v_gas_mean, normfactor_from, normfactor_to, normfactor_mean = \ - get_gas_vel_numba(branch_pit, comp_from, comp_to, comp_mean, p_abs_from, p_abs_to, + get_gas_vel_numba(node_pit, branch_pit, comp_from, comp_to, comp_mean, p_abs_from, p_abs_to, p_abs_mean, v_mps) return v_gas_from, v_gas_to, v_gas_mean, p_abs_from, p_abs_to, p_abs_mean, normfactor_from, \ @@ -126,15 +133,19 @@ def get_pressures_numba(node_pit, from_nodes, to_nodes, v_mps, p_from, p_to): @jit(nopython=True) -def get_gas_vel_numba(branch_pit, comp_from, comp_to, comp_mean, p_abs_from, p_abs_to, p_abs_mean, - v_mps): +def get_gas_vel_numba(node_pit, branch_pit, comp_from, comp_to, comp_mean, p_abs_from, p_abs_to, p_abs_mean, v_mps): v_gas_from, v_gas_to, v_gas_mean, normfactor_from, normfactor_to, normfactor_mean = \ [np.empty_like(v_mps) for _ in range(6)] - + from_nodes = branch_pit[:, FROM_NODE].astype(np.int32) for i in range(len(v_mps)): - numerator = np.divide(NORMAL_PRESSURE * branch_pit[i, TINIT], NORMAL_TEMPERATURE) - normfactor_from[i] = np.divide(numerator * comp_from[i], p_abs_from[i]) - normfactor_to[i] = np.divide(numerator * comp_to[i], p_abs_to[i]) + t_from = node_pit[from_nodes[i], TINIT_NODE] + t_to = branch_pit[i, TOUTINIT] + tm = (t_from + t_to) / 2 + numerator_from = np.divide(NORMAL_PRESSURE * t_from, NORMAL_TEMPERATURE) + numerator_to = np.divide(NORMAL_PRESSURE * t_to, NORMAL_TEMPERATURE) + numerator = np.divide(NORMAL_PRESSURE * tm, NORMAL_TEMPERATURE) + normfactor_from[i] = np.divide(numerator_from * comp_from[i], p_abs_from[i]) + normfactor_to[i] = np.divide(numerator_to * comp_to[i], p_abs_to[i]) normfactor_mean[i] = np.divide(numerator * comp_mean[i], p_abs_mean[i]) v_gas_from[i] = v_mps[i] * normfactor_from[i] v_gas_to[i] = v_mps[i] * normfactor_to[i] @@ -143,8 +154,11 @@ def get_gas_vel_numba(branch_pit, comp_from, comp_to, comp_mean, p_abs_from, p_a return v_gas_from, v_gas_to, v_gas_mean, normfactor_from, normfactor_to, normfactor_mean -def extract_branch_results_with_internals(net, branch_results, table_name, res_nodes_from, - res_nodes_to, res_mean, node_name, branches_connected): +def extract_branch_results_with_internals(net, branch_results, table_name, + res_nodes_from_hydraulics, res_nodes_from_heat, + res_nodes_to_hydraulics, res_nodes_to_heat, + res_mean_hydraulics, res_mean_heat, node_name, + simulation_mode): # the result table to write results to res_table = net["res_" + table_name] @@ -157,101 +171,137 @@ def extract_branch_results_with_internals(net, branch_results, table_name, res_n # respective table), the placement of the indices mus be known to allocate the values correctly placement_table = np.argsort(net[table_name].index.values) idx_pit = branch_pit[f:t, ELEMENT_IDX] - comp_connected = branches_connected[f:t] node_pit = net["_pit"]["node"] # the id of the external node table inside the node_pit (mostly this is "junction": 0) ext_node_tbl_idx = get_table_number(get_lookup(net, "node", "table"), node_name) - if len(res_nodes_from) > 0: - # results that relate to the from_node --> in case of many internal nodes, only the single - # from_node that is the exterior node (e.g. junction vs. internal pipe_node) result has to - # be extracted from the node_pit - from_nodes = branch_results["from_nodes"][f:t] - from_nodes_external = node_pit[from_nodes, TABLE_IDX_NODE] == ext_node_tbl_idx - considered = from_nodes_external & comp_connected - external_active = comp_connected[from_nodes_external] - for res_name, entry in res_nodes_from: - res_table[res_name].values[external_active] = branch_results[entry][f:t][considered] - - if len(res_nodes_to) > 0: - # results that relate to the to_node --> in case of many internal nodes, only the single - # to_node that is the exterior node (e.g. junction vs. internal pipe_node) result has to - # be extracted from the node_pit - to_nodes = branch_results["to_nodes"][f:t] - to_nodes_external = node_pit[to_nodes, TABLE_IDX_NODE] == ext_node_tbl_idx - considered = to_nodes_external & comp_connected - external_active = comp_connected[to_nodes_external] - for res_name, entry in res_nodes_to: - res_table[res_name].values[external_active] = branch_results[entry][f:t][considered] - - if len(res_mean) > 0: - # results that relate to the whole branch and shall be averaged (by summing up all values - # and dividing by number of internal sections) - use_numba = get_net_option(net, "use_numba") - res = _sum_by_group(use_numba, idx_pit, np.ones_like(idx_pit), - comp_connected.astype(np.int32), - *[branch_results[rn[1]][f:t] for rn in res_mean]) - connected_ind = res[2] > 0.99 - num_internals = res[1][connected_ind] - # hint: idx_pit[placement_table] should result in the indices as ordered in the table - placement_table = placement_table[connected_ind] - - for i, (res_name, entry) in enumerate(res_mean): - res_table[res_name].values[placement_table] = res[i + 3][connected_ind] / num_internals - - -def extract_branch_results_without_internals(net, branch_results, required_results, table_name, - branches_connected): + for (result_mode, res_nodes_from, res_nodes_to, res_mean) in [ + ("hydraulics", res_nodes_from_hydraulics, res_nodes_to_hydraulics, res_mean_hydraulics), + ("heat", res_nodes_from_heat, res_nodes_to_heat, res_mean_heat) + ]: + if result_mode == "hydraulics" and simulation_mode == "heat": + continue + lookup_name = "hydraulics" + if result_mode == "heat" and simulation_mode in ["heat", "all"]: + lookup_name = "heat_transfer" + comp_connected = get_lookup(net, "branch", "active_" + lookup_name)[f:t] + for (res_ext, node_name) in ((res_nodes_from, "from_nodes"), (res_nodes_to, "to_nodes")): + if len(res_ext) == 0: + continue + # results that relate to the from_node --> in case of many internal nodes, only the + # single from_node that is the exterior node (e.g. junction vs. internal pipe_node) + # result has to be extracted from the node_pit + end_nodes = branch_results[node_name][f:t] + end_nodes_external = node_pit[end_nodes, TABLE_IDX_NODE] == ext_node_tbl_idx + considered = end_nodes_external & comp_connected + external_active = comp_connected[end_nodes_external] + for res_name, entry in res_ext: + res_table[res_name].values[external_active] = branch_results[entry][f:t][considered] + if len(res_mean) > 0: + # results that relate to the whole branch and shall be averaged (by summing up all + # values and dividing by number of internal sections) + use_numba = get_net_option(net, "use_numba") + res = _sum_by_group(use_numba, idx_pit, np.ones_like(idx_pit), + comp_connected.astype(np.int32), + *[branch_results[rn[1]][f:t] for rn in res_mean]) + connected_ind = res[2] > 0.99 + num_internals = res[1][connected_ind] + + # hint: idx_pit[placement_table] should result in the indices as ordered in the table + pt = placement_table[connected_ind] + + for i, (res_name, entry) in enumerate(res_mean_hydraulics): + res_table[res_name].values[pt] = res[i + 3][connected_ind] / num_internals + + +def extract_branch_results_without_internals(net, branch_results, required_results_hydraulic, + required_results_heat, table_name, simulation_mode): + """ + Extract the results from the branch result array derived from the pit to the result table of the + net (only for branch components without internal nodes). Here, we need to consider which results + exist for hydraulic calculation and for heat transfer calculation (wrt. connectivity). + + :param net: The pandapipes net that the internal structure belongs to + :type net: pandapipesNet + :param branch_results: Important branch results from the internal pit structure + :type branch_results: dict[np.ndarray] + :param required_results_hydraulic: The entries that should be extracted for the respective \ + component for hydraulic calculation + :type required_results_hydraulic: list[tuple] + :param required_results_heat: The entries that should be extracted for the respective \ + component for heat transfer calculation + :type required_results_heat: list[tuple] + :param table_name: The name of the table that the results should be written to + :type table_name: str + :param simulation_mode: simulation mode (e.g. "hydraulics", "heat", "all"); defines whether results from \ + hydraulic or temperature calculation are transferred + :type simulation_mode: str + :return: No output + :rtype: None + """ res_table = net["res_" + table_name] f, t = get_lookup(net, "branch", "from_to")[table_name] - comp_connected = branches_connected[f:t] - - for res_name, entry in required_results: - res_table[res_name].values[:][comp_connected] = branch_results[entry][f:t][comp_connected] - -def extract_results_active_pit(net, node_pit, branch_pit, nodes_connected, branches_connected): + # extract hydraulic results + if simulation_mode in ["hydraulics", "all"]: + # lookup for connected branch elements (hydraulic results) + comp_connected_hyd = get_lookup(net, "branch", "active_hydraulics")[f:t] + for res_name, entry in required_results_hydraulic: + res_table[res_name].values[:][comp_connected_hyd] = \ + branch_results[entry][f:t][comp_connected_hyd] + if simulation_mode == "hydraulics": + for res_name, entry in required_results_heat: + res_table[res_name].values[:][comp_connected_hyd] = \ + branch_results[entry][f:t][comp_connected_hyd] + + # extract heat transfer results + if simulation_mode in ["heat", "all"]: + # lookup for connected branch elements (heat transfer results) + comp_connected_ht = get_lookup(net, "branch", "active_heat_transfer")[f:t] + for res_name, entry in required_results_heat: + res_table[res_name].values[:][comp_connected_ht] = \ + branch_results[entry][f:t][comp_connected_ht] + + +def extract_results_active_pit(net, mode="hydraulics"): """ Extract the pipeflow results from the internal pit structure ("_active_pit") to the general pit structure. :param net: The pandapipes net that the internal structure belongs to :type net: pandapipesNet - :param node_pit: The internal structure node array - :type node_pit: np.array - :param branch_pit: The internal structure branch array - :type branch_pit: np.array - :param nodes_connected: A mask array stating which nodes are actually connected to the rest of\ - the net - :type nodes_connected: np.array - :param branches_connected: A mask array stating which branches are actually connected to the \ - rest of the net - :type branches_connected: np.array + :param mode: defines whether results from hydraulic or temperature calculation are transferred + :type mode: str, default "hydraulics" :return: No output """ - all_nodes_connected = np.alltrue(nodes_connected) - if not all_nodes_connected: - node_pit[~nodes_connected, PINIT] = np.NaN - node_pit[nodes_connected, :] = net["_active_pit"]["node"] - cols_br = np.array([i for i in range(branch_pit.shape[1]) - if i not in [FROM_NODE, TO_NODE, FROM_NODE_T, TO_NODE_T]]) - else: - net["_pit"]["node"] = np.copy(net["_active_pit"]["node"]) - cols_br = None - - if not np.alltrue(branches_connected): - branch_pit[~branches_connected, VINIT] = np.NaN - rows_active_br = np.where(branches_connected)[0] - if all_nodes_connected: - branch_pit[rows_active_br, :] = net["_active_pit"]["branch"][:, :] - else: - branch_pit[rows_active_br[:, np.newaxis], cols_br[np.newaxis, :]] = \ - net["_active_pit"]["branch"][:, cols_br] - else: - if all_nodes_connected: - net["_pit"]["branch"] = np.copy(net["_active_pit"]["branch"]) - else: - net["_pit"]["branch"][:, cols_br] = net["_active_pit"]["branch"][:, cols_br] + nodes_connected = get_lookup(net, "node", "active_" + mode) + branches_connected = get_lookup(net, "branch", "active_" + mode) + result_node_col = PINIT if mode == "hydraulics" else TINIT_NODE + not_affected_node_col = TINIT_NODE if mode == "hydraulics" else PINIT + copied_node_cols = np.array([i for i in range(net["_pit"]["node"].shape[1]) + if i not in [not_affected_node_col]]) + rows_nodes = np.arange(net["_pit"]["node"].shape[0])[nodes_connected] + + result_branch_col = VINIT if mode == "hydraulics" else TOUTINIT + not_affected_branch_col = TOUTINIT if mode == "hydraulics" else VINIT + copied_branch_cols = np.array([i for i in range(net["_pit"]["branch"].shape[1]) + if i not in [FROM_NODE, TO_NODE, FROM_NODE_T, TO_NODE_T, + not_affected_branch_col]]) + rows_branches = np.arange(net["_pit"]["branch"].shape[0])[branches_connected] + + net["_pit"]["node"][~nodes_connected, result_node_col] = np.NaN + net["_pit"]["node"][rows_nodes[:, np.newaxis], copied_node_cols[np.newaxis, :]] = \ + net["_active_pit"]["node"][:, copied_node_cols] + net["_pit"]["branch"][~branches_connected, result_branch_col] = np.NaN + net["_pit"]["branch"][rows_branches[:, np.newaxis], copied_branch_cols[np.newaxis, :]] = \ + net["_active_pit"]["branch"][:, copied_branch_cols] + + +def consider_heat(mode, results=None): + consider_ = mode in ["heat", "all"] + if results is None: + return consider_ + return consider_ and any(r[2] for r in results) diff --git a/pandapipes/pipeflow.py b/pandapipes/pipeflow.py index 7132d02e3..321a24b6b 100644 --- a/pandapipes/pipeflow.py +++ b/pandapipes/pipeflow.py @@ -4,18 +4,19 @@ import numpy as np from numpy import linalg -from pandapipes.component_models.abstract_models import BranchComponent -from pandapipes.idx_branch import ACTIVE as ACTIVE_BR, FROM_NODE, TO_NODE, FROM_NODE_T, \ - TO_NODE_T, VINIT, T_OUT, VINIT_T, T_OUT_OLD -from pandapipes.idx_node import PINIT, TINIT, TINIT_OLD, ACTIVE as ACTIVE_ND +from pandapower.auxiliary import ppException +from scipy.sparse.linalg import spsolve +from pandapipes.idx_branch import T_OUT_OLD +from pandapipes.idx_node import TINIT_OLD +from pandapipes.idx_branch import FROM_NODE, TO_NODE, FROM_NODE_T, TO_NODE_T, VINIT, TOUTINIT, VINIT_T +from pandapipes.idx_node import PINIT, TINIT from pandapipes.pf.build_system_matrix import build_system_matrix -from pandapipes.pf.derivative_calculation import calculate_derivatives_hydraulic +from pandapipes.pf.derivative_calculation import calculate_derivatives_hydraulic, calculate_derivatives_thermal from pandapipes.pf.pipeflow_setup import get_net_option, get_net_options, set_net_option, \ - init_options, create_internal_results, write_internal_results, get_lookup, create_lookups,\ - initialize_pit, check_connectivity, reduce_pit, set_user_pf_options, init_all_result_tables + init_options, create_internal_results, write_internal_results, get_lookup, create_lookups, \ + initialize_pit, reduce_pit, set_user_pf_options, init_all_result_tables, \ + identify_active_nodes_branches from pandapipes.pf.result_extraction import extract_all_results, extract_results_active_pit -from pandapower.auxiliary import ppException -from scipy.sparse.linalg import spsolve try: import pandaplan.core.pplog as logging @@ -91,38 +92,36 @@ def pipeflow(net, sol_vec=None, **kwargs): calculate_heat = calculation_mode in ["heat", "all"] # TODO: This is not necessary in every time step, but we need the result! The result of the - # connectivity check is currently not saved anywhere! - if get_net_option(net, "check_connectivity"): - nodes_connected, branches_connected = check_connectivity( - net, branch_pit, node_pit, check_heat=calculate_heat) - else: - nodes_connected = node_pit[:, ACTIVE_ND].astype(bool) - branches_connected = branch_pit[:, ACTIVE_BR].astype(bool) - - reduce_pit(net, node_pit, branch_pit, nodes_connected, branches_connected) + # connectivity check is currentlynot saved anywhere! + identify_active_nodes_branches(net, branch_pit, node_pit) if calculation_mode == "heat" and not net.user_pf_options["hyd_flag"]: - raise UserWarning("Converged flag not set. Make sure that hydraulic calculation results " - "are available.") + raise UserWarning("Converged flag not set. Make sure that hydraulic calculation " + "results are available.") elif calculation_mode == "heat" and net.user_pf_options["hyd_flag"]: - net["_active_pit"]["node"][:, PINIT] = sol_vec[:len(node_pit)] - net["_active_pit"]["branch"][:, VINIT] = sol_vec[len(node_pit):] + net["_pit"]["node"][:, PINIT] = sol_vec[:len(node_pit)] + net["_pit"]["branch"][:, VINIT] = sol_vec[len(node_pit):] if calculate_hydraulics: + reduce_pit(net, node_pit, branch_pit, mode="hydraulics") converged, _ = hydraulics(net) if not converged: raise PipeflowNotConverged("The hydraulic calculation did not converge to a solution.") + extract_results_active_pit(net, mode="hydraulics") if calculate_heat: + node_pit, branch_pit = net["_pit"]["node"], net["_pit"]["branch"] + identify_active_nodes_branches(net, branch_pit, node_pit, False) + reduce_pit(net, node_pit, branch_pit, mode="heat_transfer") converged, _ = heat_transfer(net) if not converged: raise PipeflowNotConverged("The heat transfer calculation did not converge to a " "solution.") + extract_results_active_pit(net, mode="heat_transfer") elif not calculate_hydraulics: raise UserWarning("No proper calculation mode chosen.") - extract_results_active_pit(net, node_pit, branch_pit, nodes_connected, branches_connected) - extract_all_results(net, nodes_connected, branches_connected) + extract_all_results(net, calculation_mode) # TODO: a really bad solution, should be passed in from outside! #if get_net_option(net, "transient"): @@ -205,13 +204,13 @@ def heat_transfer(net): set_net_option(net, "converged", False) niter = 0 + if get_net_option(net, 'transient'): + branch_pit = net["_active_pit"]["branch"] + node_pit = net["_active_pit"]["node"] + if get_net_option(net, "time_step") == 0: - branch_pit = net["_active_pit"]["branch"] - node_pit = net["_active_pit"]["node"] - if get_net_option(net, "time_step") == 0: - - node_pit[:, TINIT_OLD] = 293 - branch_pit[:, T_OUT_OLD] = 293 + node_pit[:, TINIT_OLD] = 293 + branch_pit[:, T_OUT_OLD] = 293 # This loop is left as soon as the solver converged @@ -230,11 +229,14 @@ def heat_transfer(net): error_t_out.append(linalg.norm(delta_t_out) / (len(delta_t_out))) finalize_iteration(net, niter, error_t, error_t_out, residual_norm, nonlinear_method, tol_t, - tol_t, tol_res, t_init_old, t_out_old, hydraulic_mode=True) + tol_t, tol_res, t_init_old, t_out_old, hydraulic_mode=False) + logger.debug("F: %s" % epsilon.round(4)) + logger.debug("T_init_: %s" % t_init.round(4)) + logger.debug("T_out_: %s" % t_out.round(4)) niter += 1 - - node_pit[:, TINIT_OLD] = node_pit[:, TINIT] - branch_pit[:, T_OUT_OLD] = branch_pit[:, T_OUT] + if get_net_option(net, 'transient'): + node_pit[:, TINIT_OLD] = node_pit[:, TINIT] + branch_pit[:, T_OUT_OLD] = branch_pit[:, TOUTINIT] write_internal_results(net, iterations_T=niter, error_T=error_t[niter - 1], residual_norm_T=residual_norm) @@ -260,7 +262,7 @@ def solve_hydraulics(net): branch_pit = net["_active_pit"]["branch"] node_pit = net["_active_pit"]["node"] - branch_lookups = get_lookup(net, "branch", "from_to_active") + branch_lookups = get_lookup(net, "branch", "from_to_active_hydraulics") for comp in net['component_list']: comp.adaption_before_derivatives_hydraulic( net, branch_pit, node_pit, branch_lookups, options) @@ -299,7 +301,7 @@ def solve_temperature(net): options = net["_options"] branch_pit = net["_active_pit"]["branch"] node_pit = net["_active_pit"]["node"] - branch_lookups = get_lookup(net, "branch", "from_to_active") + branch_lookups = get_lookup(net, "branch", "from_to_active_heat_transfer") # Negative velocity values are turned to positive ones (including exchange of from_node and # to_node for temperature calculation @@ -312,20 +314,22 @@ def solve_temperature(net): branch_pit[mask, TO_NODE_T] = branch_pit[mask, FROM_NODE] for comp in net['component_list']: - if issubclass(comp, BranchComponent): - comp.calculate_derivatives_thermal(net, branch_pit, node_pit, branch_lookups, options) + comp.adaption_before_derivatives_thermal( + net, branch_pit, node_pit, branch_lookups, options) + calculate_derivatives_thermal(net, branch_pit, node_pit, options) + for comp in net['component_list']: + comp.adaption_after_derivatives_thermal( + net, branch_pit, node_pit, branch_lookups, options) jacobian, epsilon = build_system_matrix(net, branch_pit, node_pit, True) t_init_old = node_pit[:, TINIT].copy() - t_out_old = branch_pit[:, T_OUT].copy() + t_out_old = branch_pit[:, TOUTINIT].copy() x = spsolve(jacobian, epsilon) node_pit[:, TINIT] += x[:len(node_pit)] * options["alpha"] - branch_pit[:, T_OUT] += x[len(node_pit):] * options["alpha"] - - + branch_pit[:, TOUTINIT] += x[len(node_pit):] * options["alpha"] - return branch_pit[:, T_OUT], t_out_old, node_pit[:, TINIT], t_init_old, epsilon + return branch_pit[:, TOUTINIT], t_out_old, node_pit[:, TINIT], t_init_old, epsilon def set_damping_factor(net, niter, error): @@ -359,7 +363,7 @@ def set_damping_factor(net, niter, error): def finalize_iteration(net, niter, error_1, error_2, residual_norm, nonlinear_method, tol_1, tol_2, tol_res, vals_1_old, vals_2_old, hydraulic_mode=True): - col1, col2 = (PINIT, VINIT) if hydraulic_mode else (TINIT, T_OUT) + col1, col2 = (PINIT, VINIT) if hydraulic_mode else (TINIT, TOUTINIT) # Control of damping factor if nonlinear_method == "automatic": diff --git a/pandapipes/plotting/generic_geodata.py b/pandapipes/plotting/generic_geodata.py index bed499b36..a158651d8 100644 --- a/pandapipes/plotting/generic_geodata.py +++ b/pandapipes/plotting/generic_geodata.py @@ -20,7 +20,7 @@ def build_igraph_from_ppipes(net, junctions=None): """ This function uses the igraph library to create an igraph graph for a given pandapipes network. - Pipes and valves are respected. + Any branch component is respected. Performance vs. networkx: https://graph-tool.skewed.de/performance :param net: The pandapipes network @@ -39,9 +39,9 @@ def build_igraph_from_ppipes(net, junctions=None): try: import igraph as ig except (DeprecationWarning, ImportError): - raise ImportError("Please install python-igraph with " - "`pip install python-igraph` or " - "`conda install python-igraph` " + raise ImportError("Please install igraph with " + "`pip install igraph` or " + "`conda install igraph` " "or from https://www.lfd.uci.edu/~gohlke/pythonlibs") g = ig.Graph(directed=True) junction_index = net.junction.index if junctions is None else np.array(junctions) @@ -50,19 +50,15 @@ def build_igraph_from_ppipes(net, junctions=None): g.vs["label"] = list(junction_index) pp_junction_mapping = dict(list(zip(junction_index, list(range(nr_junctions))))) - mask = _get_element_mask_from_nodes(net, "pipe", ["from_junction", "to_junction"], junctions) - for pipe in net.pipe[mask].itertuples(): - g.add_edge(pp_junction_mapping[pipe.from_junction], pp_junction_mapping[pipe.to_junction], - weight=pipe.length_km) - for comp in net['component_list']: - if not isinstance(comp, BranchComponent): + if not issubclass(comp, BranchComponent): continue fjc, tjc = comp.from_to_node_cols() mask = _get_element_mask_from_nodes(net, comp.table_name(), [fjc, tjc], junctions) for comp_data in net[comp.table_name()][mask].itertuples(): - g.add_edge(pp_junction_mapping[comp_data[fjc]], pp_junction_mapping[comp_data[tjc]], - weight=0.001) + weight = 0.001 if 'length_km' not in dir(comp_data) else getattr(comp_data, 'length_km') + g.add_edge(pp_junction_mapping[getattr(comp_data, fjc)], pp_junction_mapping[getattr(comp_data, tjc)], + weight=weight) meshed = _igraph_meshed(g) roots = [pp_junction_mapping[s] for s in net.ext_grid.junction.values if s in junction_index] diff --git a/pandapipes/properties/biomethane_pure/compressibility.txt b/pandapipes/properties/biomethane_pure/compressibility.txt new file mode 100644 index 000000000..194a3471a --- /dev/null +++ b/pandapipes/properties/biomethane_pure/compressibility.txt @@ -0,0 +1,3 @@ +# source: linear approximation based on CoolProp (http://www.coolprop.org/) +# slope in 1/bar, offset for linear property +-0.0019303630399938587 0.9958350401842455 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_pure/density.txt b/pandapipes/properties/biomethane_pure/density.txt new file mode 100644 index 000000000..c90eac64b --- /dev/null +++ b/pandapipes/properties/biomethane_pure/density.txt @@ -0,0 +1,58 @@ +# source: CoolProp (http://www.coolprop.org/) +# temperature in Kelvin, nominal density in kg/Nm^3 at 1.01325 bar +263.15 0.7883176797706959 +265.15 0.7823175132720274 +267.15 0.7764086858132603 +269.15 0.7705891091714784 +271.15 0.7648567589356711 +273.15 0.7592096720602627 +275.15 0.7536459445317518 +277.15 0.7481637291423288 +279.15 0.742761233364706 +281.15 0.7374367173227688 +283.15 0.7321884918529732 +285.15 0.7270149166517398 +287.15 0.721914398504361 +289.15 0.7168853895912243 +291.15 0.7119263858673918 +293.15 0.7070359255118169 +295.15 0.7022125874426869 +297.15 0.6974549899243704 +299.15 0.6927617891486424 +301.15 0.6881316779168388 +303.15 0.6835633841304272 +305.15 0.679055670907835 +307.15 0.6746073333963901 +309.15 0.6702171990259529 +311.15 0.6658841261093711 +313.15 0.6616070028247312 +315.15 0.6573847462379292 +317.15 0.6532163013636869 +319.15 0.6491006402632528 +321.15 0.6450367611771036 +323.15 0.6410236876910659 +325.15 0.6370604679343483 +327.15 0.6331461738080604 +329.15 0.62927990024286 +331.15 0.6254607644844474 +333.15 0.6216879054056833 +335.15 0.6179604828441738 +337.15 0.6142776769642169 +339.15 0.6106386876420702 +341.15 0.6070427338735377 +343.15 0.6034890532029326 +345.15 0.5999769011734114 +347.15 0.5965055507927562 +349.15 0.5930742920256563 +351.15 0.589682431296971 +353.15 0.5863292910154656 +355.15 0.5830142091135528 +357.15 0.5797365386029372 +359.15 0.5764956471455245 +361.15 0.5732909166389835 +363.15 0.5701217428163711 +365.15 0.5669875348592726 +367.15 0.5638877150239164 +369.15 0.5608217182797604 +371.15 0.557788991960064 +373.15 0.5547889954239786 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_pure/der_compressibility.txt b/pandapipes/properties/biomethane_pure/der_compressibility.txt new file mode 100644 index 000000000..7561489ee --- /dev/null +++ b/pandapipes/properties/biomethane_pure/der_compressibility.txt @@ -0,0 +1,3 @@ +# source: own calculation based on CoolProp (http://www.coolprop.org/) +# derivative (slope) of compressibility +-0.0019303630399938587 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_pure/gas_composition.txt b/pandapipes/properties/biomethane_pure/gas_composition.txt new file mode 100644 index 000000000..a6e56cccb --- /dev/null +++ b/pandapipes/properties/biomethane_pure/gas_composition.txt @@ -0,0 +1,10 @@ +source: Arbeitsblatt DVGW G 260(A) + +Gas composition (molar fraction): +methane: 96.15 % +nitrogen: 0.75 % +carbon dioxide: 2.9 % +oxygen: 0.2 % + +Wobbe-Index (normal conditions) : 13.9 KWh/m³ +HHV (normal conditions) : 10.6 KWh/m³ \ No newline at end of file diff --git a/pandapipes/properties/biomethane_pure/heat_capacity.txt b/pandapipes/properties/biomethane_pure/heat_capacity.txt new file mode 100644 index 000000000..e02164ac0 --- /dev/null +++ b/pandapipes/properties/biomethane_pure/heat_capacity.txt @@ -0,0 +1,58 @@ +#source CoolProp (http://www.coolprop.org/) +# temperature in Kelvin, isobaric heat capacity in J/(kg K) +263.15 2043.9248427852253 +265.15 2046.988073303865 +267.15 2050.126087163204 +269.15 2053.3384737054007 +271.15 2056.6247917272185 +273.15 2059.9845702851426 +275.15 2063.417309553297 +277.15 2066.922481727277 +279.15 2070.4995319674445 +281.15 2074.1478793756605 +283.15 2077.8669179998637 +285.15 2081.6560178612567 +287.15 2085.514525999244 +289.15 2089.4417675296154 +291.15 2093.4370467118033 +293.15 2097.499648021338 +295.15 2101.628837223956 +297.15 2105.8238624483056 +299.15 2110.083955253294 +301.15 2114.4083316884407 +303.15 2118.7961933423576 +305.15 2123.246728391504 +307.15 2127.7591126080515 +309.15 2132.332510378635 +311.15 2136.9660756917788 +313.15 2141.6589531087366 +315.15 2146.41027871373 +317.15 2151.219181042416 +319.15 2156.0847819875867 +321.15 2161.0061976812103 +323.15 2165.982539352107 +325.15 2171.0129141586276 +327.15 2176.0964259958378 +329.15 2181.232176276832 +331.15 2186.419264687867 +333.15 2191.6567899171305 +335.15 2196.9438503570186 +337.15 2202.2795447799003 +339.15 2207.662972987398 +341.15 2213.0932364332866 +343.15 2218.569438820182 +345.15 2224.0906866702367 +347.15 2229.656089870096 +349.15 2235.2647621904885 +351.15 2240.9158217807285 +353.15 2246.608391638581 +355.15 2252.3416000559114 +357.15 2258.11458104055 +359.15 2263.9264747148845 +361.15 2269.7764276916773 +363.15 2275.6635934276164 +365.15 2281.587132555168 +367.15 2287.546213193266 +369.15 2293.540011237413 +371.15 2299.567710629771 +373.15 2305.6285036098143 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_pure/higher_heating_value.txt b/pandapipes/properties/biomethane_pure/higher_heating_value.txt new file mode 100644 index 000000000..56c79ba77 --- /dev/null +++ b/pandapipes/properties/biomethane_pure/higher_heating_value.txt @@ -0,0 +1,3 @@ +# source: Arbeitsblatt DVGW G 260(A) +# higher heating value in kWh/kg (at normal conditions) +13.96188746019903 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_pure/lower_heating_value.txt b/pandapipes/properties/biomethane_pure/lower_heating_value.txt new file mode 100644 index 000000000..e7b41c8d4 --- /dev/null +++ b/pandapipes/properties/biomethane_pure/lower_heating_value.txt @@ -0,0 +1 @@ +# lower heating value in kWh/kg (at normal conditions) diff --git a/pandapipes/properties/biomethane_pure/molar_mass.txt b/pandapipes/properties/biomethane_pure/molar_mass.txt new file mode 100644 index 000000000..8aedf9214 --- /dev/null +++ b/pandapipes/properties/biomethane_pure/molar_mass.txt @@ -0,0 +1,2 @@ +# source: CoolProp (http://www.coolprop.org/), kg/kmol +16.9755351 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_pure/viscosity.txt b/pandapipes/properties/biomethane_pure/viscosity.txt new file mode 100644 index 000000000..ae4cb306d --- /dev/null +++ b/pandapipes/properties/biomethane_pure/viscosity.txt @@ -0,0 +1,58 @@ +# source: CoolProp (http://www.coolprop.org/) +# temperature in Kelvin, dynamic viscosity in kg/(m s) +263.15 1.018799917679172e-05 +265.15 1.0255447167391177e-05 +267.15 1.0322713803330764e-05 +269.15 1.0389800774187494e-05 +271.15 1.0456709739161057e-05 +273.15 1.0523442327979087e-05 +275.15 1.0590000141762678e-05 +277.15 1.0656384753854598e-05 +279.15 1.0722597710611642e-05 +281.15 1.0788640532164104e-05 +283.15 1.08545147131434e-05 +285.15 1.0920221723379986e-05 +287.15 1.0985763008573338e-05 +289.15 1.105113999093497e-05 +291.15 1.1116354069806426e-05 +293.15 1.1181406622253389e-05 +295.15 1.124629900363687e-05 +297.15 1.1311032548163775e-05 +299.15 1.1375608569415205e-05 +301.15 1.144002836085609e-05 +303.15 1.1504293196322224e-05 +305.15 1.1568404330518516e-05 +307.15 1.1632362999438391e-05 +309.15 1.1696170420830542e-05 +311.15 1.1759827794618619e-05 +313.15 1.1823336303312924e-05 +315.15 1.1886697112408354e-05 +317.15 1.194991137076894e-05 +319.15 1.201298021099999e-05 +321.15 1.2075904749808127e-05 +323.15 1.2138686088349675e-05 +325.15 1.2201325312568147e-05 +327.15 1.226382349352113e-05 +329.15 1.2326181687697131e-05 +331.15 1.2388400937322568e-05 +333.15 1.2450482270659557e-05 +335.15 1.2512426702294873e-05 +337.15 1.2574235233420227e-05 +339.15 1.2635908852104261e-05 +341.15 1.2697448533556995e-05 +343.15 1.2758855240386152e-05 +345.15 1.282012992284671e-05 +347.15 1.2881273519083055e-05 +349.15 1.2942286955364732e-05 +351.15 1.3003171146315279e-05 +353.15 1.3063926995135216e-05 +355.15 1.3124555393818743e-05 +357.15 1.3185057223364654e-05 +359.15 1.3245433353981949e-05 +361.15 1.3305684645289342e-05 +363.15 1.3365811946510463e-05 +365.15 1.3425816096663347e-05 +367.15 1.3485697924745226e-05 +369.15 1.3545458249912988e-05 +371.15 1.3605097881658395e-05 +373.15 1.3664617619979682e-05 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_treated/compressibility.txt b/pandapipes/properties/biomethane_treated/compressibility.txt new file mode 100644 index 000000000..7ebaa69ce --- /dev/null +++ b/pandapipes/properties/biomethane_treated/compressibility.txt @@ -0,0 +1,3 @@ +# source: linear approximation based on CoolProp (http://www.coolprop.org/) +# slope in 1/bar, offset for linear property +-0.0024789428559189412, 0.9962776221466679 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_treated/density.txt b/pandapipes/properties/biomethane_treated/density.txt new file mode 100644 index 000000000..940ab541b --- /dev/null +++ b/pandapipes/properties/biomethane_treated/density.txt @@ -0,0 +1,58 @@ +# source: CoolProp (http://www.coolprop.org/) +# temperature in Kelvin, nominal density in kg/Nm^3 at 1.01325 bar +263.15 0.86048646407235 +265.15 0.8539252359131624 +267.15 0.8474642302098054 +269.15 0.8411011428532086 +271.15 0.8348337407285736 +273.15 0.8286598589619569 +275.15 0.8225773982960998 +277.15 0.816584322588365 +279.15 0.8106786564240795 +281.15 0.8048584828390211 +283.15 0.7991219411451699 +285.15 0.7934672248542186 +287.15 0.7878925796936597 +289.15 0.7823963017106081 +291.15 0.7769767354587873 +293.15 0.7716322722643928 +295.15 0.7663613485668018 +297.15 0.7611624443303306 +299.15 0.7560340815234674 +301.15 0.7509748226622115 +303.15 0.7459832694143467 +305.15 0.7410580612616586 +307.15 0.7361978742172673 +309.15 0.7314014195954124 +311.15 0.7266674428311796 +313.15 0.7219947223477784 +315.15 0.7173820685226427 +317.15 0.712828322486563 +319.15 0.7083323552601722 +321.15 0.7038930663980693 +323.15 0.6995093845290987 +325.15 0.695180264243638 +327.15 0.6909046867186862 +329.15 0.6866816585237271 +331.15 0.6825102108281128 +333.15 0.6783893986382189 +335.15 0.6743183000630635 +337.15 0.670296015607147 +339.15 0.6663216674893319 +341.15 0.6623943989866364 +343.15 0.6585133738018817 +345.15 0.6546777754541744 +347.15 0.6508868066912565 +349.15 0.6471396889228147 +351.15 0.6434356616738607 +353.15 0.6397739820573669 +355.15 0.6361539242660609 +357.15 0.6325747790786994 +359.15 0.6290358533891036 +361.15 0.6255364697463401 +363.15 0.6220759659128245 +365.15 0.6186536944370283 +367.15 0.6152690222406079 +369.15 0.6119213302193801 +371.15 0.60861001285761 +373.15 0.6053344778550793 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_treated/der_compressibility.txt b/pandapipes/properties/biomethane_treated/der_compressibility.txt new file mode 100644 index 000000000..22482b305 --- /dev/null +++ b/pandapipes/properties/biomethane_treated/der_compressibility.txt @@ -0,0 +1,3 @@ +# source: own calculation based on CoolProp (http://www.coolprop.org/) +# derivative (slope) of compressibility +-0.0024789428559189412 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_treated/gas_composition.txt b/pandapipes/properties/biomethane_treated/gas_composition.txt new file mode 100644 index 000000000..c529c1d97 --- /dev/null +++ b/pandapipes/properties/biomethane_treated/gas_composition.txt @@ -0,0 +1,13 @@ +source: Arbeitsblatt DVGW G 260(A) + +Gas composition (molar fraction): +methane: 90.94% +nitrogen: 0.69 % +carbon dioxide: 2.68 % +oxygen: 0.19 % +propane: 5 % +butane: 0.5 % + + +Wobbe-Index (normal conditions) : 14.9 KWh/m³ +HHV (normal conditions) : 11.6 KWh/m³ \ No newline at end of file diff --git a/pandapipes/properties/biomethane_treated/heat_capacity.txt b/pandapipes/properties/biomethane_treated/heat_capacity.txt new file mode 100644 index 000000000..f9f78e48d --- /dev/null +++ b/pandapipes/properties/biomethane_treated/heat_capacity.txt @@ -0,0 +1,58 @@ +#source CoolProp (http://www.coolprop.org/) +# temperature in Kelvin, isobaric heat capacity in J/(kg K) +263.151976.8823234072695 +265.15 1980.6134982832095 +267.15 1984.416050463013 +269.15 1988.2894370033634 +271.15 1992.2330899146655 +273.15 1996.246416873169 +275.15 2000.328801982753 +277.15 2004.4796065798193 +279.15 2008.6981700751355 +281.15 2012.9838108269525 +283.15 2017.3358270400702 +285.15 2021.753497685928 +287.15 2026.236083439167 +289.15 2030.7828276264033 +291.15 2035.3929571833426 +293.15 2040.0656836165801 +295.15 2044.8002039668168 +297.15 2049.5957017703836 +299.15 2054.4513480163328 +301.15 2059.3663020964914 +303.15 2064.3397127461894 +305.15 2069.370718973518 +307.15 2074.458450975239 +309.15 2079.6020310376007 +311.15 2084.800574420541 +313.15 2090.053190223892 +315.15 2095.358982234797 +317.15 2100.7170497532743 +319.15 2106.126488398847 +321.15 2111.5863908912784 +323.15 2117.0958478222283 +325.15 2122.65394837675 +327.15 2128.2597810582947 +329.15 2133.9124343761173 +331.15 2139.610997511174 +333.15 2145.3545609576 +335.15 2151.142217139677 +337.15 2156.9730610042843 +339.15 2162.8461905888544 +341.15 2168.760707564975 +343.15 2174.7157177577647 +345.15 2180.7103316412727 +347.15 2186.7436648101425 +349.15 2192.814838427854 +351.15 2198.922979651878 +353.15 2205.0672220361303 +355.15 2211.246705911128 +357.15 2217.460578742257 +359.15 2223.707995466675 +361.15 2229.9881188092413 +363.15 2236.300119578022 +365.15 2242.643176939882 +367.15 2249.0164786766545 +369.15 2255.4192214224554 +371.15 2261.8506108826527 +373.15 2268.3098620350665 diff --git a/pandapipes/properties/biomethane_treated/higher_heating_value.txt b/pandapipes/properties/biomethane_treated/higher_heating_value.txt new file mode 100644 index 000000000..dc86eb4a5 --- /dev/null +++ b/pandapipes/properties/biomethane_treated/higher_heating_value.txt @@ -0,0 +1,3 @@ +# source: Arbeitsblatt DVGW G 260(A) +# higher heating value in kWh/kg (at normal conditions) +13.998505990782578 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_treated/lower_heating_value.txt b/pandapipes/properties/biomethane_treated/lower_heating_value.txt new file mode 100644 index 000000000..e7b41c8d4 --- /dev/null +++ b/pandapipes/properties/biomethane_treated/lower_heating_value.txt @@ -0,0 +1 @@ +# lower heating value in kWh/kg (at normal conditions) diff --git a/pandapipes/properties/biomethane_treated/molar_mass.txt b/pandapipes/properties/biomethane_treated/molar_mass.txt new file mode 100644 index 000000000..9322e972d --- /dev/null +++ b/pandapipes/properties/biomethane_treated/molar_mass.txt @@ -0,0 +1,2 @@ +# source: CoolProp (http://www.coolprop.org/) kg/kmol +18.518267691999997 \ No newline at end of file diff --git a/pandapipes/properties/biomethane_treated/viscosity.txt b/pandapipes/properties/biomethane_treated/viscosity.txt new file mode 100644 index 000000000..226d005ba --- /dev/null +++ b/pandapipes/properties/biomethane_treated/viscosity.txt @@ -0,0 +1,58 @@ +# source: CoolProp (http://www.coolprop.org/) +# temperature in Kelvin, dynamic viscosity in kg/(m s) +263.15 9.987598418270064e-06 +265.15 1.0054271376713275e-05 +267.15 1.01207712445252e-05 +269.15 1.0187099643189088e-05 +271.15 1.0253258161058564e-05 +273.15 1.0319248354546486e-05 +275.15 1.038507174925251e-05 +277.15 1.0450729841031813e-05 +279.15 1.0516224097009172e-05 +281.15 1.0581555956543026e-05 +283.15 1.064672683214113e-05 +285.15 1.0711738110332342e-05 +287.15 1.0776591152496127e-05 +289.15 1.0841287295653449e-05 +291.15 1.0905827853220495e-05 +293.15 1.097021411572817e-05 +295.15 1.1034447351508859e-05 +297.15 1.109852880735291e-05 +299.15 1.116245970913629e-05 +301.15 1.122624126242086e-05 +303.15 1.1289874653029489e-05 +305.15 1.1353361047596854e-05 +307.15 1.141670159409703e-05 +309.15 1.1479897422350304e-05 +311.15 1.1542949644508997e-05 +313.15 1.1605859355524109e-05 +315.15 1.166862763359458e-05 +317.15 1.1731255540595754e-05 +319.15 1.1793744122496459e-05 +321.15 1.185609440975119e-05 +323.15 1.1918307417708628e-05 +325.15 1.1980384146945096e-05 +327.15 1.2042325583645421e-05 +329.15 1.2104132699940739e-05 +331.15 1.2165806454240284e-05 +333.15 1.2227347791551614e-05 +335.15 1.2288757643789442e-05 +337.15 1.2350036930074347e-05 +339.15 1.2411186557021452e-05 +341.15 1.2472207419019115e-05 +343.15 1.2533100398498824e-05 +345.15 1.2593866366196224e-05 +347.15 1.2654506181403717e-05 +349.15 1.271502069221504e-05 +351.15 1.2775410735762185e-05 +353.15 1.2835677138445082e-05 +355.15 1.2895820716153996e-05 +357.15 1.2955842274485576e-05 +359.15 1.3015742608951777e-05 +361.15 1.3075522505183164e-05 +363.15 1.313518273912608e-05 +365.15 1.3194724077234009e-05 +367.15 1.3254147276653159e-05 +369.15 1.331345308540351e-05 +371.15 1.3372642242554015e-05 +373.15 1.3431715478393082e-05 \ No newline at end of file diff --git a/pandapipes/properties/fluids.py b/pandapipes/properties/fluids.py index db0d045ed..9721fa3cd 100644 --- a/pandapipes/properties/fluids.py +++ b/pandapipes/properties/fluids.py @@ -669,7 +669,7 @@ def linear_property(prop): os.path.join(pp_dir, "properties", fluid_name, prop + ".txt")) liquids = ["water"] - gases = ["air", "lgas", "hgas", "hydrogen", "methane"] + gases = ["air", "lgas", "hgas", "hydrogen", "methane", "biomethane_pure", "biomethane_treated"] if fluid_name == "natural_gas": logger.error("'natural_gas' is ambigious. Please choose 'hgas' or 'lgas' " diff --git a/pandapipes/std_types/std_type_class.py b/pandapipes/std_types/std_type_class.py index f1eab6b0e..d2fad3844 100644 --- a/pandapipes/std_types/std_type_class.py +++ b/pandapipes/std_types/std_type_class.py @@ -423,8 +423,9 @@ def from_path(cls, name, path): @classmethod def from_list(cls, name, x_values, y_values, degree): reg_par, x_values, y_values, degree = cls._from_list(x_values, y_values, degree) - reg_st = cls(name, reg_par) - cls.init_std_type(reg_st, x_values, y_values, degree) + pump_st = cls(name, reg_par) + cls.init_std_type(pump_st, x_values, y_values, degree) + return pump_st @classmethod def load_data(cls, path): diff --git a/pandapipes/test/api/old_versions/example_0.8.5_gas.json b/pandapipes/test/api/old_versions/example_0.8.5_gas.json new file mode 100644 index 000000000..3edb20eb2 --- /dev/null +++ b/pandapipes/test/api/old_versions/example_0.8.5_gas.json @@ -0,0 +1,412 @@ +{ + "_module": "pandapipes.pandapipes_net", + "_class": "pandapipesNet", + "_object": { + "fluid": { + "_module": "pandapipes.properties.fluids", + "_class": "Fluid", + "_object": "{\"name\": \"hgas\", \"fluid_type\": \"gas\", \"is_gas\": true, \"all_properties\": {\"density\": {\"_module\": \"pandapipes.properties.fluids\", \"_class\": \"FluidPropertyInterExtra\", \"_object\": \"{\\\"x\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"array\\\", \\\"_object\\\": [{\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 263.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 273.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 283.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 293.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 303.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 313.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 323.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 333.0}], \\\"dtype\\\": \\\"float64\\\"}, \\\"y\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"array\\\", \\\"_object\\\": [{\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 0.7614762591064257}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 0.733332277439119}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 0.7072104923835694}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 0.6828947600611692}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 0.660205611537355}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 0.6389854855679075}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 0.6190946329317856}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 0.6004074588524487}], \\\"dtype\\\": \\\"float64\\\"}, \\\"_fill_value_orig\\\": \\\"extrapolate\\\"}\"}, \"viscosity\": {\"_module\": \"pandapipes.properties.fluids\", \"_class\": \"FluidPropertyInterExtra\", \"_object\": \"{\\\"x\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"array\\\", \\\"_object\\\": [{\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 263.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 273.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 283.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 293.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 303.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 313.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 323.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 333.0}], \\\"dtype\\\": \\\"float64\\\"}, \\\"y\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"array\\\", \\\"_object\\\": [{\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 1.0047118361853041e-05}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 1.04021750220461e-05}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 1.0704866480048474e-05}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 1.1007402297863992e-05}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 1.1337005139349375e-05}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 1.170765177634217e-05}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 1.2010332619395079e-05}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 1.231274052527204e-05}], \\\"dtype\\\": \\\"float64\\\"}, \\\"_fill_value_orig\\\": \\\"extrapolate\\\"}\"}, \"heat_capacity\": {\"_module\": \"pandapipes.properties.fluids\", \"_class\": \"FluidPropertyInterExtra\", \"_object\": \"{\\\"x\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"array\\\", \\\"_object\\\": [{\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 263.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 273.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 283.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 293.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 303.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 313.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 323.0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 333.0}], \\\"dtype\\\": \\\"float64\\\"}, \\\"y\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"array\\\", \\\"_object\\\": [{\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 2111.7430409177705}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 2129.19525821288}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 2148.5756908384515}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 2169.8204812997346}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 2192.8111461983763}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 2217.455354914997}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 2243.67904088272}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 2271.295613279192}], \\\"dtype\\\": \\\"float64\\\"}, \\\"_fill_value_orig\\\": \\\"extrapolate\\\"}\"}, \"molar_mass\": {\"_module\": \"pandapipes.properties.fluids\", \"_class\": \"FluidPropertyConstant\", \"_object\": \"{\\\"value\\\": 16.604497, \\\"warn_dependent_variables\\\": false}\"}, \"compressibility\": {\"_module\": \"pandapipes.properties.fluids\", \"_class\": \"FluidPropertyLinear\", \"_object\": \"{\\\"slope\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": -0.0022}, \\\"offset\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"float64\\\", \\\"_object\\\": 1.0}}\"}, \"der_compressibility\": {\"_module\": \"pandapipes.properties.fluids\", \"_class\": \"FluidPropertyConstant\", \"_object\": \"{\\\"value\\\": -0.0022, \\\"warn_dependent_variables\\\": false}\"}, \"lhv\": {\"_module\": \"pandapipes.properties.fluids\", \"_class\": \"FluidPropertyConstant\", \"_object\": \"{\\\"value\\\": 13.20179, \\\"warn_dependent_variables\\\": false}\"}, \"hhv\": {\"_module\": \"pandapipes.properties.fluids\", \"_class\": \"FluidPropertyConstant\", \"_object\": \"{\\\"value\\\": 14.62197, \\\"warn_dependent_variables\\\": false}\"}}}" + }, + "converged": true, + "name": "net", + "version": "0.8.5", + "format_version": "0.8.0", + "component_list": [ + { + "_module": "pandapipes.component_models.junction_component", + "_class": "Junction", + "_object": "{}" + }, + { + "_module": "pandapipes.component_models.pipe_component", + "_class": "Pipe", + "_object": "{}" + }, + { + "_module": "pandapipes.component_models.ext_grid_component", + "_class": "ExtGrid", + "_object": "{}" + }, + { + "_module": "pandapipes.component_models.sink_component", + "_class": "Sink", + "_object": "{}" + }, + { + "_module": "pandapipes.component_models.source_component", + "_class": "Source", + "_object": "{}" + }, + { + "_module": "pandapipes.component_models.mass_storage_component", + "_class": "MassStorage", + "_object": "{}" + }, + { + "_module": "pandapipes.component_models.valve_component", + "_class": "Valve", + "_object": "{}" + }, + { + "_module": "pandapipes.component_models.flow_control_component", + "_class": "FlowControlComponent", + "_object": "{}" + }, + { + "_module": "pandapipes.component_models.pressure_control_component", + "_class": "PressureControlComponent", + "_object": "{}" + }, + { + "_module": "pandapipes.component_models.compressor_component", + "_class": "Compressor", + "_object": "{}" + } + ], + "junction": { + "_module": "pandas.core.frame", + "_class": "DataFrame", + "_object": "{\"columns\":[\"name\",\"pn_bar\",\"tfluid_k\",\"height_m\",\"in_service\",\"type\"],\"index\":[0,1,2,3,4,5,6,7,8,9,10,11,12],\"data\":[[\"Junction 0\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 1\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 2\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 3\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 4\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 5\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 6\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 7\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 8\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 9\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 10\",16.0,283.0,0.0,true,\"junction\"],[\"Junction 11\",0.7,283.0,0.0,true,\"junction\"],[\"Junction 12\",0.7,283.0,0.0,true,\"junction\"]]}", + "orient": "split", + "dtype": { + "name": "object", + "pn_bar": "float64", + "tfluid_k": "float64", + "height_m": "float64", + "in_service": "bool", + "type": "object" + } + }, + "junction_geodata": { + "_module": "pandas.core.frame", + "_class": "DataFrame", + "_object": "{\"columns\":[\"x\",\"y\"],\"index\":[],\"data\":[]}", + "orient": "split", + "dtype": { + "x": "float64", + "y": "float64" + } + }, + "pipe": { + "_module": "pandas.core.frame", + "_class": "DataFrame", + "_object": "{\"columns\":[\"name\",\"from_junction\",\"to_junction\",\"std_type\",\"length_km\",\"diameter_m\",\"k_mm\",\"loss_coefficient\",\"alpha_w_per_m2k\",\"text_k\",\"qext_w\",\"sections\",\"in_service\",\"type\"],\"index\":[0,1,2,3,4,5,6,7],\"data\":[[\"Pipe 0\",0,1,null,3.0,0.1,1.0,0.0,10.0,293.0,0.0,10,true,\"pipe\"],[\"Pipe 1\",2,3,null,6.0,0.075,0.1,0.0,3.0,293.0,0.0,10,true,\"pipe\"],[\"Pipe 2\",3,4,null,5.0,0.06,0.1,0.0,20.0,293.0,0.0,10,true,\"pipe\"],[\"Pipe 3\",4,5,null,0.1,0.07,0.1,0.0,2.0,293.0,0.0,10,true,\"pipe\"],[\"Pipe 4\",5,6,null,4.5,0.085,0.1,0.0,2.5,293.0,0.0,10,true,\"pipe\"],[\"Pipe 5\",8,7,null,4.0,0.03,0.1,0.0,1.0,293.0,0.0,10,true,\"pipe\"],[\"Pipe 6\",9,10,null,1.0,0.03,0.1,0.0,1.0,293.0,0.0,10,true,\"pipe\"],[\"Pipe 7\",11,12,null,1.5,0.09,0.1,0.0,3.0,293.0,0.0,10,true,\"pipe\"]]}", + "orient": "split", + "dtype": { + "name": "object", + "from_junction": "uint32", + "to_junction": "uint32", + "std_type": "object", + "length_km": "float64", + "diameter_m": "float64", + "k_mm": "float64", + "loss_coefficient": "float64", + "alpha_w_per_m2k": "float64", + "text_k": "float64", + "qext_w": "float64", + "sections": "uint32", + "in_service": "bool", + "type": "object" + } + }, + "pipe_geodata": { + "_module": "pandas.core.frame", + "_class": "DataFrame", + "_object": "{\"columns\":[\"coords\"],\"index\":[],\"data\":[]}", + "orient": "split", + "dtype": { + "coords": "object" + } + }, + "ext_grid": { + "_module": "pandas.core.frame", + "_class": "DataFrame", + "_object": "{\"columns\":[\"name\",\"junction\",\"p_bar\",\"t_k\",\"in_service\",\"type\"],\"index\":[0,1],\"data\":[[\"External Grid 0\",0,16.0,280.0,true,\"pt\"],[\"External Grid 1\",8,15.0,285.0,true,\"pt\"]]}", + "orient": "split", + "dtype": { + "name": "object", + "junction": "uint32", + "p_bar": "float64", + "t_k": "float64", + "in_service": "bool", + "type": "object" + } + }, + "controller": { + "_module": "pandas.core.frame", + "_class": "DataFrame", + "_object": "{\"columns\":[\"object\",\"in_service\",\"order\",\"level\",\"initial_run\",\"recycle\"],\"index\":[0,1],\"data\":[[{\"_module\":\"pandapower.control.controller.const_control\",\"_class\":\"ConstControl\",\"_object\":\"{\\\"index\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 0}, \\\"matching_params\\\": {\\\"element\\\": \\\"sink\\\", \\\"variable\\\": \\\"mdot_kg_per_s\\\", \\\"element_index\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"array\\\", \\\"_object\\\": [{\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 1}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 2}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 3}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 4}], \\\"dtype\\\": \\\"int64\\\"}}, \\\"data_source\\\": {\\\"_module\\\": \\\"pandapower.timeseries.data_sources.frame_data\\\", \\\"_class\\\": \\\"DFData\\\", \\\"_object\\\": \\\"{\\\\\\\"df\\\\\\\": {\\\\\\\"_module\\\\\\\": \\\\\\\"pandas.core.frame\\\\\\\", \\\\\\\"_class\\\\\\\": \\\\\\\"DataFrame\\\\\\\", \\\\\\\"_object\\\\\\\": \\\\\\\"{\\\\\\\\\\\\\\\"columns\\\\\\\\\\\\\\\":[\\\\\\\\\\\\\\\"0\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"1\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"2\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"3\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"4\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"5\\\\\\\\\\\\\\\"],\\\\\\\\\\\\\\\"index\\\\\\\\\\\\\\\":[0,1,2,3],\\\\\\\\\\\\\\\"data\\\\\\\\\\\\\\\":[[0.2,0.1,0.5,0.07,0.09,0.1],[0.3,0.2,0.6,0.08,0.1,0.2],[0.4,0.3,0.7,0.09,0.11,0.3],[0.5,0.4,0.8,0.1,0.12,0.4]]}\\\\\\\", \\\\\\\"orient\\\\\\\": \\\\\\\"split\\\\\\\", \\\\\\\"dtype\\\\\\\": {\\\\\\\"0\\\\\\\": \\\\\\\"float64\\\\\\\", \\\\\\\"1\\\\\\\": \\\\\\\"float64\\\\\\\", \\\\\\\"2\\\\\\\": \\\\\\\"float64\\\\\\\", \\\\\\\"3\\\\\\\": \\\\\\\"float64\\\\\\\", \\\\\\\"4\\\\\\\": \\\\\\\"float64\\\\\\\", \\\\\\\"5\\\\\\\": \\\\\\\"float64\\\\\\\"}}}\\\"}, \\\"element_index\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"array\\\", \\\"_object\\\": [{\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 0}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 1}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 2}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 3}, {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"int64\\\", \\\"_object\\\": 4}], \\\"dtype\\\": \\\"int64\\\"}, \\\"element\\\": \\\"sink\\\", \\\"values\\\": null, \\\"profile_name\\\": {\\\"_module\\\": \\\"numpy\\\", \\\"_class\\\": \\\"array\\\", \\\"_object\\\": [\\\"0\\\", \\\"1\\\", \\\"2\\\", \\\"3\\\", \\\"4\\\"], \\\"dtype\\\": \\\"=2.11.1", extras_require={"docs": ["numpydoc", "sphinx", "sphinx_rtd_theme", "sphinxcontrib.bibtex"], - "plotting": ["plotly", "python-igraph"], + "plotting": ["plotly", "igraph"], "test": ["pytest", "pytest-xdist", "nbmake"], "all": ["numpydoc", "sphinx", "sphinx_rtd_theme", "sphinxcontrib.bibtex", - "plotly", "python-igraph", "pytest", "pytest-xdist", "nbmake"]}, + "plotly", "igraph", "pytest", "pytest-xdist", "nbmake"]}, packages=find_packages(), include_package_data=True, classifiers=classifiers diff --git a/tutorials/creating_a_simple_network.ipynb b/tutorials/creating_a_simple_network.ipynb index b88bf1de9..982b41435 100644 --- a/tutorials/creating_a_simple_network.ipynb +++ b/tutorials/creating_a_simple_network.ipynb @@ -35,8 +35,8 @@ "We have to state the name of the fluid for the network. In pandapipes, some fluids are already\n", "pre-defined, e.g. hgas, lgas\n", "(high and low calorific natural gas), hydrogen,\n", - "water, and air, but you can\n", - "also create your own fluid if you prefer (tutorial in preparation).\n", + "water, biomethane_pure, biomethane_treated (see [here](https://pandapipes.readthedocs.io/en/latest/fluid_properties/fluids.html) for the composition) and air. It is\n", + "also possible to create a fluid if needed (tutorial in preparation).\n", "\n", "In this example, we will create a medium pressure gas network and choose lgas from the predefined fluids in pandapipes." ] @@ -371,11 +371,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "pp.pipeflow(net)" @@ -383,11 +379,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "The results are written to `res_...` tables. They were added to the `net`container. " ] @@ -395,11 +387,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "net # result tables have been added to the net " @@ -408,11 +396,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "net.res_junction # calculated pressure and temperature at junctions" @@ -421,11 +405,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "net.res_pipe # velocities, mass flows through pipes and other results\n", diff --git a/tutorials/minimal_example.ipynb b/tutorials/minimal_example.ipynb index a8d639ac7..8701fc6b2 100644 --- a/tutorials/minimal_example.ipynb +++ b/tutorials/minimal_example.ipynb @@ -17,7 +17,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -44,12 +44,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that the fluid used here is lgas. You can find 5 predefined fluids in pandapipes:\n", - " - lgas\n", - " - hgas\n", - " - hydrogen\n", - " - water\n", - " - air\n", + "Note that the fluid used here is ``lgas`` (low-calorific natural gas). You can find 7 predefined fluids in pandapipes:\n", + "- ``lgas`` (low-calorific natural gas)\n", + "- ``hgas`` (high-calorific natural gas)\n", + "- ``hydrogen``\n", + "- ``water``\n", + "- ``biomethane_pure``\n", + "- ``biomethane_treated`` (see [here](https://pandapipes.readthedocs.io/en/latest/fluid_properties/fluids.html) for the composition)\n", + "- ``air``\n", "\n", "And that the predefined valve element is an ideal valve. " ] @@ -65,57 +67,27 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": " name pn_bar tfluid_k height_m in_service type\n0 Junction 1 1.05 293.15 0.0 True junction\n1 Junction 2 1.05 293.15 0.0 True junction\n2 Junction 3 1.05 293.15 0.0 True junction", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
namepn_bartfluid_kheight_min_servicetype
0Junction 11.05293.150.0Truejunction
1Junction 21.05293.150.0Truejunction
2Junction 31.05293.150.0Truejunction
\n
" - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "net.junction" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": " name from_junction to_junction std_type length_km diameter_m k_mm \\\n0 Pipe 1 0 1 None 0.1 0.05 1.0 \n\n loss_coefficient alpha_w_per_m2k text_k qext_w sections in_service \\\n0 0.0 0.0 293.0 0.0 1 True \n\n type \n0 pipe ", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
namefrom_junctionto_junctionstd_typelength_kmdiameter_mk_mmloss_coefficientalpha_w_per_m2ktext_kqext_wsectionsin_servicetype
0Pipe 101None0.10.051.00.00.0293.00.01Truepipe
\n
" - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "net.pipe" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": " name junction p_bar t_k in_service type\n0 Grid Connection 0 1.1 293.15 True pt", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
namejunctionp_bart_kin_servicetype
0Grid Connection01.1293.15Truept
\n
" - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "net.ext_grid" ] @@ -131,26 +103,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "hp.pandapipes.pipeflow - INFO: niter 0\n", - "hp.pandapipes.pipeflow - INFO: niter 1\n", - "hp.pandapipes.pipeflow - INFO: niter 2\n", - "hp.pandapipes.pipeflow - INFO: niter 3\n", - "hp.pandapipes.pipeflow - INFO: ---------------------------------------------------------------------------------\n", - "hp.pandapipes.pipeflow - INFO: Calculation completed. Preparing results...\n", - "hp.pandapipes.pipeflow - INFO: Converged after 4 iterations.\n", - "hp.pandapipes.pipeflow - INFO: Norm of residual: 1.6351116571833302e-08\n", - "hp.pandapipes.pipeflow - INFO: tol_p: 0.0001\n", - "hp.pandapipes.pipeflow - INFO: tol_v: 0.0001\n" - ] - } - ], + "outputs": [], "source": [ "pp.pipeflow(net)" ] @@ -164,19 +119,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": " p_bar t_k\n0 1.100000 293.15\n1 0.913916 293.15\n2 0.913916 293.15", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
p_bart_k
01.100000293.15
10.913916293.15
20.913916293.15
\n
" - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "net.res_junction" ] @@ -190,19 +135,9 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": " v_from_m_per_s v_to_m_per_s v_mean_m_per_s p_from_bar p_to_bar \\\n0 15.766074 17.295535 16.483877 1.1 0.913916 \n\n t_from_k t_to_k mdot_from_kg_per_s mdot_to_kg_per_s vdot_norm_m3_per_s \\\n0 293.15 293.15 0.045 -0.045 0.06044 \n\n reynolds lambda normfactor_from normfactor_to \n0 96710.314701 0.049222 0.512189 0.561877 ", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
v_from_m_per_sv_to_m_per_sv_mean_m_per_sp_from_barp_to_bart_from_kt_to_kmdot_from_kg_per_smdot_to_kg_per_svdot_norm_m3_per_sreynoldslambdanormfactor_fromnormfactor_to
015.76607417.29553516.4838771.10.913916293.15293.150.045-0.0450.0604496710.3147010.0492220.5121890.561877
\n
" - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "net.res_pipe" ] @@ -218,7 +153,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -244,37 +179,11 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "hp.pandapipes.pipeflow_setup - INFO: Setting the following nodes out of service for hydraulics calculation in connectivity check:\n", - "In table junction: [2]\n", - "hp.pandapipes.pipeflow - INFO: niter 0\n", - "hp.pandapipes.pipeflow - INFO: niter 1\n", - "hp.pandapipes.pipeflow - INFO: ---------------------------------------------------------------------------------\n", - "hp.pandapipes.pipeflow - INFO: Calculation completed. Preparing results...\n", - "hp.pandapipes.pipeflow - INFO: Converged after 2 iterations.\n", - "hp.pandapipes.pipeflow - INFO: Norm of residual: 6.635561679383765e-07\n", - "hp.pandapipes.pipeflow - INFO: tol_p: 0.0001\n", - "hp.pandapipes.pipeflow - INFO: tol_v: 0.0001\n" - ] - }, - { - "data": { - "text/plain": " p_bar t_k\n0 1.1 293.15\n1 1.1 293.15\n2 NaN NaN", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
p_bart_k
01.1293.15
11.1293.15
2NaNNaN
\n
" - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "pp.pipeflow(net)\n", "net.res_junction" @@ -289,19 +198,9 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": " v_from_m_per_s v_to_m_per_s v_mean_m_per_s p_from_bar p_to_bar \\\n0 0.0 0.0 0.0 1.1 1.1 \n\n t_from_k t_to_k mdot_from_kg_per_s mdot_to_kg_per_s vdot_norm_m3_per_s \\\n0 293.15 293.15 0.0 -0.0 0.0 \n\n reynolds lambda normfactor_from normfactor_to \n0 0.0 0.04856 0.512189 0.512189 ", - "text/html": "
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
v_from_m_per_sv_to_m_per_sv_mean_m_per_sp_from_barp_to_bart_from_kt_to_kmdot_from_kg_per_smdot_to_kg_per_svdot_norm_m3_per_sreynoldslambdanormfactor_fromnormfactor_to
00.00.00.01.11.1293.15293.150.0-0.00.00.00.048560.5121890.512189
\n
" - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "net.res_pipe" ] @@ -328,4 +227,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} \ No newline at end of file +}