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

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# ------------------------------------------------------------------------------ 

7 

8import warnings 

9 

10import numpy as np 

11 

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 

17 

18 

19# def heat_flux_z_direction(temp_matrix: np.ndarray, input_matrix: np.ndarray, nodes: list, ) 

20 

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. 

28 

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 

36 

37 def boundary(self, boundary: BoundaryCondition) -> np.ndarray: 

38 resistors: Resistor = boundary.neighbours 

39 

40 bc_temp = self.input_matrix[:, boundary.index] 

41 heat_flux_sum = np.zeros_like(bc_temp) 

42 

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 

48 

49 def preheat(self, distributor: MassFlowNode, collector: MassFlowNode): 

50 """ 

51 Returns the preheat in Kelvin. 

52 

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 

60 

61 def channel_heat_flux(self, distributor: MassFlowNode, collector: MassFlowNode): 

62 """ 

63 Returns the heat flux between distributor and collector. 

64 

65 Parameters 

66 ---------- 

67 distributor : MassFlowNode 

68 collector : MassFlowNode 

69 

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) 

80 

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. 

85 

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 

88 

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. 

98 

99 Returns 

100 ------- 

101 float | np.ndarray : 

102 The heat fluxes for every time step. 

103 """ 

104 if isinstance(resistors, Resistor): 

105 resistors = [resistors] 

106 

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 

125 

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. 

129 

130 Parameters 

131 ---------- 

132 ihc : list | InternalHeatSource 

133 The `InternalHeatSource` s to get the values from. 

134 

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 

146 

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. 

155 

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. 

158 

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 

167 

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 ] 

183 

184 result = 0 

185 for node, resistors in nodes_and_resistors: 

186 result += self.calculate_heat_flux(node, resistors) 

187 results.append(result) 

188 

189 if len(results) > 1: 

190 return tuple(results) 

191 return results[0]