Coverage for examples/SimpleBuilding/flex_output_data/created_flex_files/flex_agents.py: 100%
52 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-10-20 14:09 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2025-10-20 14:09 +0000
1import casadi as ca
2import pandas as pd
3from agentlib_mpc.models.casadi_model import (
4 CasadiModel,
5 CasadiInput,
6 CasadiState,
7 CasadiParameter,
8 CasadiOutput,
9 CasadiModelConfig,
10)
11from math import inf
14class BaselineMPCModelConfig(CasadiModelConfig):
15 inputs: list[CasadiInput] = [
16 CasadiInput(
17 name="P_in",
18 value=100,
19 unit="W",
20 description="Electrical power of heating rod (equivalent to P_el)",
21 ),
22 CasadiInput(
23 name="T_amb", value=290.15, unit="K", description="Ambient air temperature"
24 ),
25 CasadiInput(
26 name="T_upper",
27 value=294.15,
28 unit="K",
29 description="Upper boundary (soft) for T",
30 ),
31 CasadiInput(
32 name="T_lower",
33 value=290.15,
34 unit="K",
35 description="Lower boundary (soft) for T",
36 ),
37 CasadiInput(
38 name="_P_external",
39 value=0,
40 unit="W",
41 type="pd.Series",
42 description="External power profile to be provided",
43 ),
44 CasadiInput(
45 name="in_provision",
46 value=False,
47 unit="-",
48 type="bool",
49 description="Flag signaling if the flexibility is in provision",
50 ),
51 CasadiInput(
52 name="rel_start",
53 value=0,
54 unit="s",
55 type="int",
56 description="relative start time of the flexibility event",
57 ),
58 CasadiInput(
59 name="rel_end",
60 value=0,
61 unit="s",
62 type="int",
63 description="relative end time of the flexibility event",
64 ),
65 ]
66 states: list[CasadiState] = [
67 CasadiState(
68 name="T_zone", value=293.15, unit="K", description="Temperature of zone"
69 ),
70 CasadiState(
71 name="T_slack",
72 value=0,
73 unit="K",
74 description="Slack variable for zone temperature",
75 ),
76 ]
77 parameters: list[CasadiParameter] = [
78 CasadiParameter(
79 name="C", value=10000, unit="J/K", description="Thermal capacity of zone"
80 ),
81 CasadiParameter(
82 name="U", value=5, unit="W/K", description="Thermal conductivity of zone"
83 ),
84 CasadiParameter(
85 name="s_T",
86 value=1,
87 unit="-",
88 description="Weight for zone temperature slack var in constraint function",
89 ),
90 CasadiParameter(
91 name="r_pel",
92 value=1,
93 unit="-",
94 description="Weight for P_el in objective function",
95 ),
96 CasadiParameter(
97 name="profile_deviation_weight",
98 value=0,
99 unit="-",
100 description="Weight of soft constraint for deviation from accepted flexible profile",
101 ),
102 ]
103 outputs: list[CasadiOutput] = [
104 CasadiOutput(
105 name="P_el",
106 unit="W",
107 description="Electrical power of heating rod (system input)",
108 )
109 ]
112class BaselineMPCModel(CasadiModel):
113 config: BaselineMPCModelConfig
115 def setup_system(self):
116 self.T_zone.ode = (self.P_in - self.U * (self.T_zone - self.T_amb)) / self.C
117 self.P_el.alg = self.P_in
118 self.constraints = [
119 (-inf, self.T_zone - self.T_slack, self.T_upper),
120 (self.T_lower, self.T_zone + self.T_slack, inf),
121 (0, self.T_slack, inf),
122 (0, self.P_in, 200),
123 ]
124 objective = sum([self.s_T * self.T_slack**2, self.r_pel * self.P_in])
125 obj_std = objective
126 return ca.if_else(
127 self.in_provision.sym,
128 ca.if_else(
129 self.time < self.rel_start.sym,
130 obj_std,
131 ca.if_else(
132 self.time >= self.rel_end.sym,
133 obj_std,
134 sum(
135 [
136 self.profile_deviation_weight
137 * (self.P_el - self._P_external) ** 2
138 ]
139 ),
140 ),
141 ),
142 obj_std,
143 )
146class PosFlexModelConfig(CasadiModelConfig):
147 inputs: list[CasadiInput] = [
148 CasadiInput(
149 name="P_in",
150 value=100,
151 unit="W",
152 description="Electrical power of heating rod (equivalent to P_el)",
153 ),
154 CasadiInput(
155 name="T_amb", value=290.15, unit="K", description="Ambient air temperature"
156 ),
157 CasadiInput(
158 name="T_upper",
159 value=294.15,
160 unit="K",
161 description="Upper boundary (soft) for T",
162 ),
163 CasadiInput(
164 name="T_lower",
165 value=290.15,
166 unit="K",
167 description="Lower boundary (soft) for T",
168 ),
169 CasadiInput(
170 name="P_in_full",
171 value=None,
172 unit="Not defined",
173 type="pd.Series",
174 description="full control trajectory output of baseline mpc",
175 ),
176 CasadiInput(
177 name="in_provision",
178 value=False,
179 unit="-",
180 type="bool",
181 description="provision flag",
182 ),
183 ]
184 states: list[CasadiState] = [
185 CasadiState(
186 name="T_zone", value=293.15, unit="K", description="Temperature of zone"
187 ),
188 CasadiState(
189 name="T_slack",
190 value=0,
191 unit="K",
192 description="Slack variable for zone temperature",
193 ),
194 ]
195 parameters: list[CasadiParameter] = [
196 CasadiParameter(
197 name="C", value=10000, unit="J/K", description="Thermal capacity of zone"
198 ),
199 CasadiParameter(
200 name="U", value=5, unit="W/K", description="Thermal conductivity of zone"
201 ),
202 CasadiParameter(
203 name="s_T",
204 value=1,
205 unit="-",
206 description="Weight for zone temperature slack var in constraint function",
207 ),
208 CasadiParameter(
209 name="r_pel",
210 value=1,
211 unit="-",
212 description="Weight for P_el in objective function",
213 ),
214 CasadiParameter(
215 name="prep_time", value=0, unit="s", description="time to switch objective"
216 ),
217 CasadiParameter(
218 name="flex_event_duration",
219 value=0,
220 unit="s",
221 description="time to switch objective",
222 ),
223 CasadiParameter(
224 name="market_time",
225 value=0,
226 unit="s",
227 description="time to switch objective",
228 ),
229 CasadiParameter(
230 name="s_P",
231 value=10,
232 unit="-",
233 description="Weight for P in objective function",
234 ),
235 ]
236 outputs: list[CasadiOutput] = [
237 CasadiOutput(
238 name="P_el",
239 unit="W",
240 description="Electrical power of heating rod (system input)",
241 )
242 ]
245class PosFlexModel(CasadiModel):
246 config: PosFlexModelConfig
248 def setup_system(self):
249 P_in_lower = ca.if_else(
250 self.time < self.market_time.sym, self.P_in_full.sym, self.P_in.lb
251 )
252 P_in_upper = ca.if_else(
253 self.time < self.market_time.sym, self.P_in_full.sym, self.P_in.ub
254 )
255 self.T_zone.ode = (self.P_in - self.U * (self.T_zone - self.T_amb)) / self.C
256 self.P_el.alg = self.P_in
257 self.constraints = [
258 (-inf, self.T_zone - self.T_slack, self.T_upper),
259 (self.T_lower, self.T_zone + self.T_slack, inf),
260 (0, self.T_slack, inf),
261 (0, self.P_in, 200),
262 (P_in_lower, self.P_in, P_in_upper),
263 ]
264 objective = sum([self.s_T * self.T_slack**2, self.r_pel * self.P_in])
265 obj_std = objective
266 obj_flex = sum([self.s_T * self.T_slack**2, self.s_P * self.P_el])
267 return ca.if_else(
268 self.time < self.prep_time.sym + self.market_time.sym,
269 obj_std,
270 ca.if_else(
271 self.time
272 < self.prep_time.sym
273 + self.flex_event_duration.sym
274 + self.market_time.sym,
275 obj_flex,
276 obj_std,
277 ),
278 )
281class NegFlexModelConfig(CasadiModelConfig):
282 inputs: list[CasadiInput] = [
283 CasadiInput(
284 name="P_in",
285 value=100,
286 unit="W",
287 description="Electrical power of heating rod (equivalent to P_el)",
288 ),
289 CasadiInput(
290 name="T_amb", value=290.15, unit="K", description="Ambient air temperature"
291 ),
292 CasadiInput(
293 name="T_upper",
294 value=294.15,
295 unit="K",
296 description="Upper boundary (soft) for T",
297 ),
298 CasadiInput(
299 name="T_lower",
300 value=290.15,
301 unit="K",
302 description="Lower boundary (soft) for T",
303 ),
304 CasadiInput(
305 name="P_in_full",
306 value=None,
307 unit="Not defined",
308 type="pd.Series",
309 description="full control trajectory output of baseline mpc",
310 ),
311 CasadiInput(
312 name="in_provision",
313 value=False,
314 unit="-",
315 type="bool",
316 description="provision flag",
317 ),
318 ]
319 states: list[CasadiState] = [
320 CasadiState(
321 name="T_zone", value=293.15, unit="K", description="Temperature of zone"
322 ),
323 CasadiState(
324 name="T_slack",
325 value=0,
326 unit="K",
327 description="Slack variable for zone temperature",
328 ),
329 ]
330 parameters: list[CasadiParameter] = [
331 CasadiParameter(
332 name="C", value=10000, unit="J/K", description="Thermal capacity of zone"
333 ),
334 CasadiParameter(
335 name="U", value=5, unit="W/K", description="Thermal conductivity of zone"
336 ),
337 CasadiParameter(
338 name="s_T",
339 value=1,
340 unit="-",
341 description="Weight for zone temperature slack var in constraint function",
342 ),
343 CasadiParameter(
344 name="r_pel",
345 value=1,
346 unit="-",
347 description="Weight for P_el in objective function",
348 ),
349 CasadiParameter(
350 name="prep_time", value=0, unit="s", description="time to switch objective"
351 ),
352 CasadiParameter(
353 name="flex_event_duration",
354 value=0,
355 unit="s",
356 description="time to switch objective",
357 ),
358 CasadiParameter(
359 name="market_time",
360 value=0,
361 unit="s",
362 description="time to switch objective",
363 ),
364 CasadiParameter(
365 name="s_P",
366 value=10,
367 unit="-",
368 description="Weight for P in objective function",
369 ),
370 ]
371 outputs: list[CasadiOutput] = [
372 CasadiOutput(
373 name="P_el",
374 unit="W",
375 description="Electrical power of heating rod (system input)",
376 )
377 ]
380class NegFlexModel(CasadiModel):
381 config: NegFlexModelConfig
383 def setup_system(self):
384 P_in_lower = ca.if_else(
385 self.time < self.market_time.sym, self.P_in_full.sym, self.P_in.lb
386 )
387 P_in_upper = ca.if_else(
388 self.time < self.market_time.sym, self.P_in_full.sym, self.P_in.ub
389 )
390 self.T_zone.ode = (self.P_in - self.U * (self.T_zone - self.T_amb)) / self.C
391 self.P_el.alg = self.P_in
392 self.constraints = [
393 (-inf, self.T_zone - self.T_slack, self.T_upper),
394 (self.T_lower, self.T_zone + self.T_slack, inf),
395 (0, self.T_slack, inf),
396 (0, self.P_in, 200),
397 (P_in_lower, self.P_in, P_in_upper),
398 ]
399 objective = sum([self.s_T * self.T_slack**2, self.r_pel * self.P_in])
400 obj_std = objective
401 obj_flex = sum([self.s_T * self.T_slack**2, -self.s_P * self.P_el])
402 return ca.if_else(
403 self.time < self.prep_time.sym + self.market_time.sym,
404 obj_std,
405 ca.if_else(
406 self.time
407 < self.prep_time.sym
408 + self.flex_event_duration.sym
409 + self.market_time.sym,
410 obj_flex,
411 obj_std,
412 ),
413 )