Skip to content

Commit 50ac6a5

Browse files
committed
Merge remote-tracking branch 'origin/pv' into pv
2 parents fb465a0 + 2913358 commit 50ac6a5

30 files changed

+3267
-1978
lines changed

src/pandaprosumer/controller/converter.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,17 @@ def control_step(self, prosumer):
5050
deltaT = t_supply_c - t_required_in_c
5151

5252
q_received_kw = self._get_input('q_received_kw')
53-
#print(q_received_kw)
54-
if abs(deltaT) < 1e-6:
55-
mdot_received_kg_per_s = 0.0
53+
54+
if abs(deltaT) < 1e-10:
55+
raise ValueError(
56+
f"Invalid temperature configuration: supply temperature ({t_supply_c} °C) "
57+
f"is lower than return temperature ({t_required_in_c} °C). "
58+
)
59+
5660
else:
5761
t_mean_K = CELSIUS_TO_K + 0.5 * (t_supply_c + t_required_in_c)
5862
cp = self.fluid.get_heat_capacity(t_mean_K)
5963
mdot_received_kg_per_s = q_received_kw * 1e3/ (cp * deltaT)
60-
#print(mdot_received_kg_per_s)
6164

6265
result = np.array([])
6366

src/pandaprosumer/controller/data_model/ice_chp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@ class IceChpControllerData:
2727
element_index: List[int]
2828
period_index: int = None
2929
element_name: str = 'ice_chp'
30-
input_columns: List[str] = field(default_factory=lambda: ['cycle', 't_intake_k'])
30+
input_columns: List[str] = field(default_factory=lambda: ['cycle', 't_intake_k', 'p_requested_kw'])
3131
result_columns: List[str] = field(default_factory=lambda: ['load', 'p_in_kw', 'p_el_out_kw', 'p_th_out_kw', 'p_rad_out_kw', 'ice_chp_efficiency', 'mdot_fuel_in_kg_per_s', 'acc_m_fuel_in_kg', 'acc_co2_equiv_kg', 'acc_co2_inst_kg', 'acc_nox_mg', 'acc_time_ice_chp_oper_s'])

src/pandaprosumer/controller/models/booster_heat_pump.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def _q_received_kw(self):
5858
def _p_received_kw(self):
5959
return self._get_input("p_received_kw")
6060

61+
6162
def q_to_receive_kw(self, prosumer):
6263
"""
6364
Calculates the heat to receive in kW.
@@ -114,6 +115,7 @@ def control_step(self, prosumer):
114115
t_sink_k = self._t_sink_k
115116
bhp_type = self._get_element_param(prosumer, "bhp_type")
116117
mode = self._mode
118+
q_max_kw = self._get_element_param(prosumer, "q_max_kw")
117119

118120
t_source_k = t_source_k - 273.0 # in celsius
119121
t_amb_k = t_amb_k - 273.0 # in celsius
@@ -128,7 +130,8 @@ def control_step(self, prosumer):
128130
else:
129131
t_sink_floor_heating_k = t_sink_k - 273.0
130132
t_sink_radiator_heating_k = t_sink_k - 273.0
131-
q_max_kw = 5.8 + 0.21 * t_source_k
133+
if pd.isna(q_max_kw):
134+
q_max_kw = 5.8 + 0.21 * t_source_k
132135
elif bhp_type == "water-water1":
133136
t_min_source_k = -10.0
134137
t_max_source_k = 25.0
@@ -139,7 +142,8 @@ def control_step(self, prosumer):
139142
else:
140143
t_sink_floor_heating_k = t_sink_k - 273.0
141144
t_sink_radiator_heating_k = t_sink_k - 273.0
142-
q_max_kw = 5.8 + 0.21 * t_source_k
145+
if pd.isna(q_max_kw):
146+
q_max_kw = 5.8 + 0.21 * t_source_k
143147
elif bhp_type == "water-water2":
144148
t_min_source_k = 10.0
145149
t_max_source_k = 80.0
@@ -150,7 +154,8 @@ def control_step(self, prosumer):
150154
else:
151155
t_sink_floor_heating_k = t_sink_k - 273.0
152156
t_sink_radiator_heating_k = t_sink_k - 273.0
153-
q_max_kw = 25.308 + 0.963 * t_source_k
157+
if pd.isna(q_max_kw):
158+
q_max_kw = 25.308 + 0.963 * t_source_k
154159
elif bhp_type == "water-water3":
155160
t_min_source_k = 10.0
156161
t_max_source_k = 80.0
@@ -161,7 +166,8 @@ def control_step(self, prosumer):
161166
else:
162167
t_sink_floor_heating_k = t_sink_k - 273.0
163168
t_sink_radiator_heating_k = t_sink_k - 273.0
164-
q_max_kw = 29.005 + 1.035 * t_source_k
169+
if pd.isna(q_max_kw):
170+
q_max_kw = 29.005 + 1.035 * t_source_k
165171

166172
else:
167173
raise ValueError(f"Unknown heat pump type: {bhp_type}")
@@ -214,6 +220,7 @@ def control_step(self, prosumer):
214220
logging.warning(f"Heat pump is not operating due to the heat source "
215221
f"temperature being out of range: {float(t_source_k)} celsius")
216222
else:
223+
217224
q_remain_kw, q_floor_kw, q_radiator_kw, cop_floor, cop_radiator = (
218225
self.first_mode_calc(q_kw, demand_kw, p_el_kw, q_max_kw,
219226
t_sink_floor_heating_k, t_sink_radiator_heating_k, t_source_k, cop_coeff))
@@ -329,6 +336,17 @@ def control_step(self, prosumer):
329336
pd.Series(q_radiator_kw)
330337
])
331338

339+
self.last_result = {
340+
"cop_floor": cop_floor,
341+
"cop_radiator": cop_radiator,
342+
"pel_floor_kw": pel_floor_kw,
343+
"pel_radiator_kw": pel_radiator_kw,
344+
"q_remain_kw": q_remain_kw,
345+
"q_floor_kw": q_floor_kw,
346+
"q_radiator_kw": q_radiator_kw
347+
}
348+
349+
332350
self.finalize(prosumer, result.T)
333351

334352
self.applied = True

src/pandaprosumer/controller/models/dry_cooler.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,32 @@ def _calculate_dry_cooler(self, prosumer, mdot_fluid_kg_per_s, t_in_required_c,
246246
mdot_air_kg_per_s, t_air_in_c, t_air_out_c,
247247
mdot_fluid_kg_per_s, t_fluid_in_c, t_fluid_out_c)
248248

249+
def _save_state(self):
250+
"""Backup states before Run"""
251+
self._backup_state = {
252+
"t_previous_out_c": self.t_previous_out_c,
253+
"t_previous_in_c": self.t_previous_in_c,
254+
"mdot_previous_in_kg_per_s": self.mdot_previous_in_kg_per_s,
255+
}
256+
257+
def _restore_state(self):
258+
"""Restore states before Rerun"""
259+
if hasattr(self, "_backup_state"):
260+
self.t_previous_out_c = self._backup_state["t_previous_out_c"]
261+
self.t_previous_in_c = self._backup_state["t_previous_in_c"]
262+
self.mdot_previous_in_kg_per_s = self._backup_state["mdot_previous_in_kg_per_s"]
263+
249264
def control_step(self, prosumer):
250265
"""
251266
Executes the control step for the controller.
252267
253268
:param prosumer: The prosumer object
254269
"""
270+
if not prosumer.rerun:
271+
self._save_state()
272+
else:
273+
self._restore_state()
274+
255275
if not (self.in_service and getattr(prosumer, self.obj.element_name).iloc[self.obj.element_index[0]].in_service):
256276
self.applied = True
257277
return
@@ -300,6 +320,19 @@ def control_step(self, prosumer):
300320
mdot_air_kg_per_s, t_air_in_c, t_air_out_c,
301321
mdot_fluid_kg_per_s, t_fluid_in_c, t_fluid_out_c]])
302322

323+
self.last_result = {
324+
"q_exchanged_kw": q_exchanged_kw,
325+
"p_fans_kw": p_fans_kw,
326+
"n_rpm": n_rpm,
327+
"mdot_air_m3_per_h": mdot_air_m3_per_h,
328+
"mdot_air_kg_per_s": mdot_air_kg_per_s,
329+
"t_air_in_c": t_air_in_c,
330+
"t_air_out_c": t_air_out_c,
331+
"mdot_fluid_kg_per_s": mdot_fluid_kg_per_s,
332+
"t_fluid_in_c": t_fluid_in_c,
333+
"t_fluid_out_c": t_fluid_out_c,
334+
}
335+
303336
assert round(t_fluid_out_c, 4) <= round(t_fluid_in_c, 4), f"Dry Cooler {self.name} t_fluid_out_c > t_fluid_in_c ({t_fluid_out_c} > {t_fluid_in_c}) for timestep {self.time} in prosumer {prosumer.name}"
304337

305338
# ToDo: Add a condition to check whether the mass flows are equal

src/pandaprosumer/controller/models/electric_boiler.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ def control_step(self, prosumer):
139139

140140
result = np.array([[q_kw, mdot_delivered_kg_per_s, t_in_c, t_out_c, p_kw]])
141141

142+
self.last_result = {
143+
"q_kw": q_kw,
144+
"mdot_delivered_kg_per_s": mdot_delivered_kg_per_s,
145+
"t_in_c": t_in_c,
146+
"t_out_c": t_out_c,
147+
"p_kw": p_kw,
148+
}
149+
142150
self.finalize(prosumer, result, result_fluid_mix)
143151

144152
self.applied = True

src/pandaprosumer/controller/models/gas_boiler.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ def control_step(self, prosumer):
121121

122122
result = np.array([[q_kw, mdot_delivered_kg_per_s, t_in_c, t_out_c, mdot_gas_kg_per_s]])
123123

124+
self.last_result = {
125+
"q_kw": q_kw,
126+
"mdot_delivered_kg_per_s": mdot_delivered_kg_per_s,
127+
"t_in_c": t_in_c,
128+
"t_out_c": t_out_c,
129+
"mdot_gas_kg_per_s": mdot_gas_kg_per_s,
130+
}
131+
124132
self.finalize(prosumer, result, result_fluid_mix)
125133

126134
self.applied = True

src/pandaprosumer/controller/models/heat_demand.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,32 @@ def _t_m_to_receive_init(self, prosumer):
161161
assert t_feed_demand_c >= t_return_demand_c
162162
return t_feed_demand_c, t_return_demand_c, mdot_demand_kg_per_s
163163

164+
def _save_state(self):
165+
"""Backup states before Run"""
166+
self._backup_state = {
167+
"t_previous_out_c": self.t_previous_out_c,
168+
"t_previous_in_c": self.t_previous_in_c,
169+
"mdot_previous_in_kg_per_s": self.mdot_previous_in_kg_per_s,
170+
}
171+
172+
def _restore_state(self):
173+
"""Restore states before Rerun"""
174+
if hasattr(self, "_backup_state"):
175+
self.t_previous_out_c = self._backup_state["t_previous_out_c"]
176+
self.t_previous_in_c = self._backup_state["t_previous_in_c"]
177+
self.mdot_previous_in_kg_per_s = self._backup_state["mdot_previous_in_kg_per_s"]
178+
164179
def control_step(self, prosumer):
165180
"""
166181
Executes the control step for the controller.
167182
168183
:param prosumer: The prosumer object
169184
"""
185+
if not prosumer.rerun:
186+
self._save_state()
187+
else:
188+
self._restore_state()
189+
170190
if not (self.in_service and getattr(prosumer, self.obj.element_name).iloc[self.obj.element_index[0]].in_service):
171191
self.applied = True
172192
return
@@ -184,6 +204,14 @@ def control_step(self, prosumer):
184204
q_received_kw = self._get_input('q_received_kw')
185205
q_uncovered_kw = self._q_demand_kw - q_received_kw
186206
result = np.array([[q_received_kw, q_uncovered_kw, 0, 0, 0]])
207+
self.last_result = {
208+
"q_received_kw": q_received_kw,
209+
"q_uncovered_kw": q_uncovered_kw,
210+
"mdot_received_kg_per_s": 0,
211+
"t_in_c": 0,
212+
"t_out_c": 0
213+
}
214+
187215
self.finalize(prosumer, result)
188216
self.applied = True
189217
return
@@ -211,6 +239,13 @@ def control_step(self, prosumer):
211239
# FixMe: Consider the temperature level in the output
212240
q_uncovered_kw = q_demand_kw - q_received_kw
213241
result = np.array([[q_received_kw, q_uncovered_kw, mdot_received_kg_per_s, self._t_in_c, t_out_c]])
242+
self.last_result = {
243+
"q_received_kw": q_received_kw,
244+
"q_uncovered_kw": q_uncovered_kw,
245+
"mdot_received_kg_per_s": mdot_received_kg_per_s,
246+
"t_in_c": self._t_in_c,
247+
"t_out_c": t_out_c
248+
}
214249
if np.isnan(result).any():
215250
self.input_mass_flow_with_temp = {FluidMixMapping.TEMPERATURE_KEY: np.nan,
216251
FluidMixMapping.MASS_FLOW_KEY: np.nan}

src/pandaprosumer/controller/models/heat_exchanger.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,32 @@ def calculate_heat_exchanger_reverse(self, prosumer, t_1_in_c, t_1_out_c, mdot_1
253253

254254
return mdot_1_kg_per_s, t_1_in_c, t_1_out_c, mdot_2_kg_per_s, t_2_in_c, t_2_out_c
255255

256+
def _save_state(self):
257+
"""Backup states before Run"""
258+
self._backup_state = {
259+
"t_previous_1_out_c": self.t_previous_1_out_c,
260+
"t_previous_1_in_c": self.t_previous_1_in_c,
261+
"mdot_previous_1_kg_per_s": self.mdot_previous_1_kg_per_s,
262+
}
263+
264+
def _restore_state(self):
265+
"""Restore states before Rerun"""
266+
if hasattr(self, "_backup_state"):
267+
self.t_previous_1_out_c = self._backup_state["t_previous_1_out_c"]
268+
self.t_previous_1_in_c = self._backup_state["t_previous_1_in_c"]
269+
self.mdot_previous_1_kg_per_s = self._backup_state["mdot_previous_1_kg_per_s"]
270+
256271
def control_step(self, prosumer):
257272
"""
258273
Executes the control step for the controller.
259274
260275
:param prosumer: The prosumer object
261276
"""
277+
if not prosumer.rerun:
278+
self._save_state()
279+
else:
280+
self._restore_state()
281+
262282
if not (self.in_service and getattr(prosumer, self.obj.element_name).iloc[
263283
self.obj.element_index[0]].in_service): # FixMe: use gettattr element
264284
self.applied = True
@@ -396,6 +416,16 @@ def control_step(self, prosumer):
396416
[[q_exchanged_kw, mdot_1_kg_per_s, t_1_in_c, t_1_out_c, mdot_2_kg_per_s, t_2_in_c, t_2_out_c]]
397417
)
398418

419+
self.last_result = {
420+
"q_exchanged_kw": q_exchanged_kw,
421+
"mdot_1_kg_per_s": mdot_1_kg_per_s,
422+
"t_1_in_c": t_1_in_c,
423+
"t_1_out_c": t_1_out_c,
424+
"mdot_2_kg_per_s": mdot_2_kg_per_s,
425+
"t_2_in_c": t_2_in_c,
426+
"t_2_out_c": t_2_out_c,
427+
}
428+
399429
result_fluid_mix = []
400430
for mdot_kg_per_s in result_mdot_tab_kg_per_s:
401431
result_fluid_mix.append({FluidMixMapping.TEMPERATURE_KEY: t_2_out_c,

src/pandaprosumer/controller/models/heat_pump.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,30 @@ def _calculate_heat_pump_reverse(self, prosumer, mdot_evap_kg_per_s, t_evap_in_c
229229
mdot_cond_kg_per_s, t_cond_in_c, t_cond_out_c,
230230
mdot_evap_kg_per_s, t_evap_in_c, t_evap_out_c)
231231

232+
def _save_state(self):
233+
self._backup_state = {
234+
"t_previous_evap_out_c": self.t_previous_evap_out_c,
235+
"t_previous_evap_in_c": self.t_previous_evap_in_c,
236+
"mdot_previous_evap_kg_per_s": self.mdot_previous_evap_kg_per_s,
237+
}
238+
239+
def _restore_state(self):
240+
if hasattr(self, "_backup_state"):
241+
self.t_previous_evap_out_c = self._backup_state["t_previous_evap_out_c"]
242+
self.t_previous_evap_in_c = self._backup_state["t_previous_evap_in_c"]
243+
self.mdot_previous_evap_kg_per_s = self._backup_state["mdot_previous_evap_kg_per_s"]
244+
232245
def control_step(self, prosumer):
233246
"""
234247
Executes the control step for the controller.
235248
236249
:param prosumer: The prosumer object
237250
"""
251+
if not prosumer.rerun:
252+
self._save_state()
253+
else:
254+
self._restore_state()
255+
238256
if not (self.in_service and getattr(prosumer, self.obj.element_name).iloc[self.obj.element_index[0]].in_service):
239257
self.applied = True
240258
return
@@ -328,6 +346,19 @@ def control_step(self, prosumer):
328346
mdot_cond_kg_per_s, t_cond_in_c, t_cond_out_c,
329347
mdot_evap_kg_per_s, t_evap_in_c, t_evap_out_c]])
330348

349+
self.last_result = {
350+
"q_cond_kw": q_cond_kw,
351+
"p_comp_kw": p_comp_kw,
352+
"q_evap_kw": q_evap_kw,
353+
"cop_hp": cop_hp,
354+
"mdot_cond_kg_per_s": mdot_cond_kg_per_s,
355+
"t_cond_in_c": t_cond_in_c,
356+
"t_cond_out_c": t_cond_out_c,
357+
"mdot_evap_kg_per_s": mdot_evap_kg_per_s,
358+
"t_evap_in_c": t_evap_in_c,
359+
"t_evap_out_c": t_evap_out_c,
360+
}
361+
331362
assert cop_hp >= 0, f"Heat Pump {self.name} COP is negative ({cop_hp}) for timestep {self.time} in prosumer {prosumer.name}"
332363
assert mdot_evap_kg_per_s >= 0, f"Heat Pump {self.name} mdot_evap_kg_per_s is negative ({mdot_evap_kg_per_s}) for timestep {self.time} in prosumer {prosumer.name}"
333364
assert mdot_cond_kg_per_s >= 0, f"Heat Pump {self.name} mdot_cond_kg_per_s is negative ({mdot_cond_kg_per_s}) for timestep {self.time} in prosumer {prosumer.name}"

0 commit comments

Comments
 (0)