Coverage for pyrc \ postprocessing \ calculations.py: 0%
67 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-13 16:59 +0200
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-13 16:59 +0200
1# -------------------------------------------------------------------------------
2# Copyright (C) 2026 Joel Kimmich, Tim Jourdan
3# ------------------------------------------------------------------------------
4# License
5# This file is part of PyRC, distributed under GPL-3.0-or-later.
6# ------------------------------------------------------------------------------
8import warnings
10import numpy as np
12from pyrc.core.components.resistor import Resistor
13from pyrc.core.components.capacitor import Capacitor
14from pyrc.core.inputs import BoundaryCondition, InternalHeatSource
15from pyrc.core.nodes import MassFlowNode
16from pyrc.core.components.input import Input
19# def heat_flux_z_direction(temp_matrix: np.ndarray, input_matrix: np.ndarray, nodes: list, )
21class SimpleHeatFlux:
22 def __init__(self,
23 time_filtered_temp_matrix: np.ndarray,
24 time_filtered_input_matrix: np.ndarray,
25 ):
26 """
27 Do not filter the columns! Otherwise, the algorithms won't work anymore.
29 Parameters
30 ----------
31 time_filtered_temp_matrix
32 time_filtered_input_matrix
33 """
34 self.temp_matrix = time_filtered_temp_matrix
35 self.input_matrix = time_filtered_input_matrix
37 def boundary(self, boundary: BoundaryCondition) -> np.ndarray:
38 resistors: Resistor = boundary.neighbours
40 bc_temp = self.input_matrix[:, boundary.index]
41 heat_flux_sum = np.zeros_like(bc_temp)
43 for resistor in resistors:
44 other_node_index = resistor.get_connected_node(boundary).index
45 node_temp = self.temp_matrix[:, other_node_index]
46 heat_flux_sum += 1 / resistor.resistance * (bc_temp - node_temp)
47 return heat_flux_sum
49 def preheat(self, distributor: MassFlowNode, collector: MassFlowNode):
50 """
51 Returns the preheat in Kelvin.
53 Returns
54 -------
55 np.ndarray
56 """
57 temp_dist: np.ndarray = self.temp_matrix[:, distributor.index]
58 temp_col: np.ndarray = self.temp_matrix[:, collector.index]
59 return temp_col - temp_dist
61 def channel_heat_flux(self, distributor: MassFlowNode, collector: MassFlowNode):
62 """
63 Returns the heat flux between distributor and collector.
65 Parameters
66 ----------
67 distributor : MassFlowNode
68 collector : MassFlowNode
70 Returns
71 -------
72 np.ndarray :
73 The heat flux between distributor and collector.
74 """
75 temp_dist = self.temp_matrix[:, distributor.index]
76 temp_col = self.temp_matrix[:, collector.index]
77 mass_flow = distributor.mass_flow
78 spec_capacity = distributor.material.heat_capacity
79 return mass_flow * spec_capacity * (temp_col - temp_dist)
81 def calculate_heat_flux(self, node, resistors: list | Resistor, raise_error_instead_of_warning=False) -> (
82 np.ndarray | float):
83 """
84 Returns the heat flux going into the node by the passed resistors.
86 Attention: It uses the equivalent resistance for both serial and parallel resistors. To prevent double
87 calculation do only pass one Resistor to a Node
89 Parameters
90 ----------
91 node : NoteTemplate
92 The Node of which the heat flux is being calculated.
93 resistors : list | Resistor
94 The resistors used to calculate the heat flow. They should be connected to node.
95 raise_error_instead_of_warning : bool, optional
96 If True, an error is raised instead of a warning when a heat flux is calculated to a Node that was
97 already considered.
99 Returns
100 -------
101 float | np.ndarray :
102 The heat fluxes for every time step.
103 """
104 if isinstance(resistors, Resistor):
105 resistors = [resistors]
107 result = 0
108 node_temp = self.temp_matrix[:, node.index]
109 seen_other_nodes = set()
110 for resistor in resistors:
111 other_node = resistor.get_connected_node(node)
112 if other_node in seen_other_nodes:
113 if raise_error_instead_of_warning:
114 raise ValueError("The heat flux to this Node was already calculated.\n"
115 "You might consider using TemperatureNode.resistors_in_direction_filtered (with "
116 "filtered!).")
117 warnings.warn("The heat flux to this Node was already calculated; the heat flux is probably wrong!")
118 if isinstance(other_node, Input):
119 result += 1 / resistor.equivalent_resistance * (
120 self.input_matrix[:, other_node.index] - node_temp)
121 else:
122 result += 1 / resistor.equivalent_resistance * (
123 self.temp_matrix[:, other_node.index] - node_temp)
124 return result
126 def internal_heat_source(self, ihc: InternalHeatSource | list) -> np.ndarray:
127 """
128 Returns the values for the internal heat sources out of the input matrix.
130 Parameters
131 ----------
132 ihc : list | InternalHeatSource
133 The `InternalHeatSource` s to get the values from.
135 Returns
136 -------
137 np.ndarray :
138 The values.
139 Vector if one IHS is passed, matrix otherwise (time steps x IHS).
140 """
141 if not isinstance(ihc, list):
142 ihc = [ihc]
143 ihc_index = [i.index for i in ihc]
144 ihc_values = self.input_matrix[:, ihc_index]
145 return ihc_values
147 def heat_flux_directions(
148 self,
149 nodes: list[Capacitor],
150 directions: list | np.ndarray = np.array([0, 0, -1]),
151 except_resistor_types=None
152 ) -> tuple | np.ndarray:
153 """
154 Returns the heat flux through the layer in the desired direction of all nodes in the given list.
156 E.g. if the direction is (0,0,1) the heat flux in positive z direction is calculated. The heat flux is
157 positive if going in the same direction as the desired one.
159 Parameters
160 ----------
161 nodes : list[Capacitor]
162 The Nodes of which the heat flux is being calculated.
163 directions : list | np.ndarray, optional
164 The direction(s) in which the heat flux is calculated.
165 Can be a list then each direction is calculated and returned.
166 except_resistor_types
168 Returns
169 -------
170 np.ndarray | tuple :
171 The result of one direction as np.ndarray or the result of all directions as tuple.
172 """
173 if except_resistor_types is None:
174 except_resistor_types = []
175 if isinstance(directions, np.ndarray):
176 directions = [directions]
177 results = []
178 for direction in directions:
179 nodes_and_resistors = [
180 (node, node.resistors_in_direction_filtered(direction, except_resistor_types=except_resistor_types))
181 for node in nodes if node is not None
182 ]
184 result = 0
185 for node, resistors in nodes_and_resistors:
186 result += self.calculate_heat_flux(node, resistors)
187 results.append(result)
189 if len(results) > 1:
190 return tuple(results)
191 return results[0]