Coverage for pyrc \ core \ components \ input.py: 84%

32 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 

8from __future__ import annotations 

9 

10from abc import abstractmethod 

11 

12from pyrc.core.settings import Settings, initial_settings 

13 

14 

15class Input: 

16 """ 

17 Each Input can be called as function to get its value during solving depending on the time step/ temperature 

18 or last input value. 

19 

20 Attributes 

21 ---------- 

22 self.static : bool, optional 

23 If True, a static value is assumed and no time-dependent calculations were done. 

24 NOTE: You may take a look on the ConstantInput class for such cases to remain performant. 

25 This also serves as a switch to first just use static values during network solving until a stationary 

26 state is reached and then activate the dynamic calculation. 

27 

28 

29 """ 

30 

31 def __init__(self, settings: Settings = initial_settings): 

32 """ 

33 Super class for all inputs. 

34 

35 Mainly used for calculation boundary conditions both time-independent and time-dependent. 

36 

37 The simplest way of using this class would be to just return one static value, no matter which solving time, 

38 temperature or input_vector is given. Because the __call__method is run every solver iteration it should be 

39 as performant as possible. Therefor, for constant Inputs it's recommended to use the ConstantInput class. 

40 

41 """ 

42 self.settings = settings 

43 

44 @property 

45 def static(self): 

46 return self.settings.calculate_static 

47 

48 @property 

49 @abstractmethod 

50 def index(self) -> int: 

51 """ 

52 Returns the index of self in the input vector/matrix. 

53 

54 Returns 

55 ------- 

56 int : 

57 The index of self in the input vector/matrix. 

58 """ 

59 pass 

60 

61 @property 

62 @abstractmethod 

63 def initial_value(self): 

64 pass 

65 

66 @initial_value.setter 

67 @abstractmethod 

68 def initial_value(self, value): 

69 pass 

70 

71 @abstractmethod 

72 def calculate_static(self, tau, temp_vector, _input_vector, *args, **kwargs): 

73 """ 

74 Calculate static values. 

75 

76 Each function in the dict must have the possibility to get along with *args and **kwargs. 

77 

78 Parameters 

79 ---------- 

80 tau 

81 temp_vector 

82 _input_vector 

83 kwargs 

84 

85 Returns 

86 ------- 

87 

88 """ 

89 pass 

90 

91 def calculate_dynamic(self, tau, temp_vector, _input_vector, *args, **kwargs): 

92 """ 

93 Should be overwritten for all time-dependent inputs. 

94 

95 Is used, when self.static = False to calculate time-dependent inputs. 

96 

97 Each function in the dict must have the possibility to get along with *args and **kwargs. 

98 

99 Parameters 

100 ---------- 

101 tau : float 

102 The current time of the solving process. 

103 temp_vector : np.ndarray 

104 The temperature vector of the last solution during iteration. 

105 In the first iteration it is the initial one. 

106 _input_vector : 

107 The input vector used for the last solution during iteration. 

108 In the first iteration it is the initial one. 

109 kwargs : dict, optional 

110 Further values that can be used for just some calculations. 

111 

112 Returns 

113 ------- 

114 float | int | np.number : 

115 A new input value for the input vector 

116 """ 

117 return self.calculate_static(tau, temp_vector, _input_vector) 

118 

119 def get_kwargs_functions(self) -> dict: 

120 """ 

121 Used to calculate keyword arguments for calculate_static/dynamic that only need to be calculated once for all objects. 

122 

123 The main reason for this method is speed up during calculation/iteration/solving, because some/most of the 

124 boundary conditions only need to be calculated once per time step. So these BCs should be calculated in here 

125 and passed to each Input object so that they can use the value for their calculation. 

126 

127 Each function in the dict must have the possibility to get along with *args and **kwargs. 

128 

129 Returns 

130 ------- 

131 dict : 

132 The names of the values that must be passed to calculate_static/dynamic and the function to calculate 

133 this values. 

134 If for example the exterior temperature is needed for calculate_dynamic, the dict looks like this: 

135 {"exterior_temperature": lambda tau: my_fancy_algorithm_to_calculate/get_the_exterior_temperature(tau)} 

136 To use it, this dict must be passed to calculate_dynamic like this: 

137 my_obj.calculate_dynamic(tau, temp_vector, _input_vector, **the_get_kwargs_dict) 

138 """ 

139 return {} 

140 

141 def __call__(self, tau, temp_vector, _input_vector, *args, **kwargs): 

142 if self.static: 

143 return self.calculate_static(tau, temp_vector, _input_vector, *args, **kwargs) 

144 return self.calculate_dynamic(tau, temp_vector, _input_vector, *args, **kwargs)