Skip to content

Commit

Permalink
Merge pull request #599 from dlohmeier/feature/heat_consumer
Browse files Browse the repository at this point in the history
Simple heat consumer implementation
  • Loading branch information
SimonRubenDrauz committed Apr 9, 2024
2 parents 2104e36 + a347b82 commit e18dfa6
Show file tree
Hide file tree
Showing 6 changed files with 566 additions and 24 deletions.
6 changes: 3 additions & 3 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ exclude_lines =
pragma: no cover

omit =
pandapipes/test/*
pandapipes/plotting/geo.py
pandapipes/converter/stanet/data_cleaning.py
src/pandapipes/test/*
src/pandapipes/plotting/geo.py
src/pandapipes/converter/stanet/data_cleaning.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from pandapipes.component_models.abstract_models.branch_wo_internals_models import \
BranchWOInternalsComponent
from pandapipes.idx_branch import LENGTH, K
from pandapipes.idx_branch import LENGTH, K, TEXT, ALPHA

try:
import pandaplan.core.pplog as logging
Expand Down Expand Up @@ -58,6 +58,8 @@ def create_pit_branch_entries(cls, net, branch_pit):
super().create_pit_branch_entries(net, branch_pit)
branch_wzerolength_pit[:, LENGTH] = 0
branch_wzerolength_pit[:, K] = 1000
branch_wzerolength_pit[:, TEXT] = 293.15
branch_wzerolength_pit[:, ALPHA] = 0
return branch_wzerolength_pit

@classmethod
Expand Down
229 changes: 229 additions & 0 deletions src/pandapipes/component_models/heat_consumer_component.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
# Copyright (c) 2020-2023 by Fraunhofer Institute for Energy Economics
# and Energy System Technology (IEE), Kassel. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

import numpy as np
from numpy import dtype

from pandapipes.component_models import get_fluid, \
BranchWZeroLengthComponent, get_component_array, standard_branch_wo_internals_result_lookup
from pandapipes.component_models.junction_component import Junction
from pandapipes.idx_branch import (D, AREA, VINIT, ALPHA, QEXT, RHO, TEXT, JAC_DERIV_DP1,
JAC_DERIV_DV, JAC_DERIV_DP, LOAD_VEC_BRANCHES)
from pandapipes.pf.result_extraction import extract_branch_results_without_internals


class HeatConsumer(BranchWZeroLengthComponent):
"""
"""
# columns for internal array
MASS = 0
QEXT = 1
DELTAT = 2
TRETURN = 3
MODE = 4

internal_cols = 5

# numbering of given parameters (for mdot, qext, deltat, treturn)
MF = 0
QE = 1
DT = 2
TR = 3

# heat consumer modes (sum of combinations of given parameters)
MF_QE = 1
MF_DT = 2
MF_TR = 4
QE_DT = 3
QE_TR = 5

@classmethod
def table_name(cls):
return "heat_consumer"

@classmethod
def get_connected_node_type(cls):
return Junction

@classmethod
def from_to_node_cols(cls):
return "from_junction", "to_junction"

@classmethod
def active_identifier(cls):
return "in_service"

@classmethod
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:
:type branch_pit:
:return: No Output.
"""
hs_pit = super().create_pit_branch_entries(net, branch_pit)
hs_pit[:, D] = net[cls.table_name()].diameter_m.values
hs_pit[:, AREA] = hs_pit[:, D] ** 2 * np.pi / 4
hs_pit[:, VINIT] = (net[cls.table_name()].controlled_mdot_kg_per_s.values /
(hs_pit[:, AREA] * hs_pit[:, RHO]))
hs_pit[:, QEXT] = net[cls.table_name()].qext_w.values
return hs_pit

@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()]
consumer_array = np.zeros(shape=(len(tbl), cls.internal_cols), dtype=np.float64)
consumer_array[:, cls.MASS] = tbl.controlled_mdot_kg_per_s.values
consumer_array[:, cls.QEXT] = tbl.qext_w.values
consumer_array[:, cls.DELTAT] = tbl.deltat_k.values
consumer_array[:, cls.TRETURN] = tbl.treturn_k.values
mf = ~np.isnan(consumer_array[:, cls.MASS])
qe = ~np.isnan(consumer_array[:, cls.QEXT])
dt = ~np.isnan(consumer_array[:, cls.DELTAT])
tr = ~np.isnan(consumer_array[:, cls.TRETURN])
consumer_array[:, cls.MODE] = np.sum([mf, qe, dt, tr], axis=0)
component_pits[cls.table_name()] = consumer_array

@classmethod
def adaption_after_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options):
"""
Perform adaptions to the branch pit after the derivatives have been calculated globally.
:param net: The pandapipes network containing all relevant info
:type net: pandapipesNet
:param branch_pit: The branch internal array
:type branch_pit: np.ndarray
:param node_pit: The node internal array
:type node_pit: np.ndarray
:param idx_lookups: Lookup for the relevant indices in the pit
:type idx_lookups: dict
:param options: Options for the pipeflow
:type options: dict
:return: No Output.
:rtype: None
"""
# 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())
# TODO: this is more precise, but slower:
# np.isin(fc_array[:, cls.MODE], [cls.MF_QE, cls.MF_DT, cls.MF_TR])
mdot_controlled = ~np.isnan(fc_array[:, cls.MASS])
fc_branch_pit[mdot_controlled, JAC_DERIV_DP] = 0
fc_branch_pit[mdot_controlled, JAC_DERIV_DP1] = 0
fc_branch_pit[mdot_controlled, JAC_DERIV_DV] = 1
fc_branch_pit[mdot_controlled, LOAD_VEC_BRANCHES] = 0

# @classmethod
# def adaption_before_derivatives_thermal(cls, net, branch_pit, node_pit, idx_lookups, options):
# f, t = idx_lookups[cls.table_name()]
# hs_pit = branch_pit[f:t, :]
# mask_t_return = ~np.isnan(hs_pit[:, TRETURN])
# hs_pit[mask_t_return, TINIT_OUT] = (hs_pit[mask_t_return, TINIT_OUT]
# - hs_pit[mask_t_return, DELTAT])
#
#
# @classmethod
# def adaption_after_derivatives_thermal(cls, net, branch_pit, node_pit, idx_lookups, options):
# """
#
# :param net:
# :type net:
# :param branch_component_pit:
# :type branch_component_pit:
# :param node_pit:
# :type node_pit:
# :return:
# :rtype:
# """
# # -(rho * area * cp * v_init * (-t_init_i + t_init_i1 - tl)
# # - alpha * (t_amb - t_m) * length + qext)
#
# f, t = idx_lookups[cls.table_name()]
# hs_pit = branch_pit[f:t, :]
# from_nodes = hs_pit[:, FROM_NODE_T].astype(np.int32)
#
# mask_qext = ~np.isnan(hs_pit[:, QEXT])
# mask_deltat = ~np.isnan(hs_pit[:, DELTAT])
# mask_t_return = ~np.isnan(hs_pit[:, TRETURN])
# mask_mass = ~np.isnan(hs_pit[:, MASS])
# hs_pit[mask_t_return | mask_deltat, JAC_DERIV_DT1] = 0

@classmethod
def get_component_input(cls):
"""
Get component input.
:return:
:rtype:
"""
return [("name", dtype(object)),
("from_junction", "u4"),
("to_junction", "u4"),
("qext_w", "f8"),
("controlled_mdot_kg_per_s", "f8"),
("deltat_k", "f8"),
("treturn_k", "f8"),
("diameter_m", "f8"),
("in_service", "bool"),
("type", dtype(object))]

@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
if False, returns columns as tuples also specifying the dtypes
:rtype: (list, bool)
"""
if get_fluid(net).is_gas:
output = ["v_from_m_per_s", "v_to_m_per_s", "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", "reynolds", "lambda", "normfactor_from",
"normfactor_to"]
else:
output = ["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", "reynolds",
"lambda"]
return output, True

@classmethod
def extract_results(cls, net, options, branch_results, mode):
"""
:param net:
:type net:
:param options:
:type options:
:param branch_results:
:type branch_results:
:param mode:
:type mode:
:return:
:rtype:
"""
required_results_hyd, required_results_ht = standard_branch_wo_internals_result_lookup(net)

extract_branch_results_without_internals(net, branch_results, required_results_hyd,
required_results_ht, cls.table_name(), mode)
6 changes: 1 addition & 5 deletions src/pandapipes/component_models/heat_exchanger_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,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 ALPHA, TEXT, QEXT, D, AREA, LOSS_COEFFICIENT as LC, TOUTINIT
from pandapipes.idx_branch import QEXT, D, AREA, LOSS_COEFFICIENT as LC
from pandapipes.pf.pipeflow_setup import get_fluid
from pandapipes.pf.result_extraction import extract_branch_results_without_internals

Expand Down Expand Up @@ -55,10 +55,7 @@ def create_pit_branch_entries(cls, net, branch_pit):
heat_exchanger_pit[:, D] = net[cls.table_name()].diameter_m.values
heat_exchanger_pit[:, AREA] = heat_exchanger_pit[:, D] ** 2 * np.pi / 4
heat_exchanger_pit[:, LC] = net[cls.table_name()].loss_coefficient.values
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[:, TOUTINIT] = 307

@classmethod
def extract_results(cls, net, options, branch_results, mode):
Expand All @@ -81,7 +78,6 @@ def extract_results(cls, net, options, branch_results, mode):
extract_branch_results_without_internals(net, branch_results, required_results_hyd,
required_results_ht, cls.table_name(), mode)


@classmethod
def get_component_input(cls):
"""
Expand Down

0 comments on commit e18dfa6

Please sign in to comment.