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 2026-03-26 09:43 +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 

12 

13 

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 ] 

110 

111 

112class BaselineMPCModel(CasadiModel): 

113 config: BaselineMPCModelConfig 

114 

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 ) 

144 

145 

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="Not defined", 

180 type="bool", 

181 description="Flag indicating whether flexibility should be provisioned", 

182 ), 

183 CasadiInput( 

184 name="P_el_base", 

185 value=0, 

186 unit="Not defined", 

187 type="None", 

188 description="Not defined", 

189 ), 

190 ] 

191 states: list[CasadiState] = [ 

192 CasadiState( 

193 name="T_zone", value=293.15, unit="K", description="Temperature of zone" 

194 ), 

195 CasadiState( 

196 name="T_slack", 

197 value=0, 

198 unit="K", 

199 description="Slack variable for zone temperature", 

200 ), 

201 ] 

202 parameters: list[CasadiParameter] = [ 

203 CasadiParameter( 

204 name="C", value=10000, unit="J/K", description="Thermal capacity of zone" 

205 ), 

206 CasadiParameter( 

207 name="U", value=5, unit="W/K", description="Thermal conductivity of zone" 

208 ), 

209 CasadiParameter( 

210 name="s_T", 

211 value=1, 

212 unit="-", 

213 description="Weight for zone temperature slack var in constraint function", 

214 ), 

215 CasadiParameter( 

216 name="r_pel", 

217 value=1, 

218 unit="-", 

219 description="Weight for P_el in objective function", 

220 ), 

221 CasadiParameter( 

222 name="prep_time", 

223 value=900, 

224 unit="s", 

225 description="Preparation time before switching objective", 

226 ), 

227 CasadiParameter( 

228 name="flex_event_duration", 

229 value=7200, 

230 unit="s", 

231 description="Duration of the flexibility event", 

232 ), 

233 CasadiParameter( 

234 name="market_time", 

235 value=900, 

236 unit="s", 

237 description="Market time associated with the objective switch", 

238 ), 

239 CasadiParameter( 

240 name="s_P", value=10, unit="Not defined", description="Not defined" 

241 ), 

242 ] 

243 outputs: list[CasadiOutput] = [ 

244 CasadiOutput( 

245 name="P_el", 

246 unit="W", 

247 description="Electrical power of heating rod (system input)", 

248 ) 

249 ] 

250 

251 

252class PosFlexModel(CasadiModel): 

253 config: PosFlexModelConfig 

254 

255 def setup_system(self): 

256 P_in_lower = ca.if_else( 

257 self.time < self.market_time.sym, self.P_in_full.sym, self.P_in.lb 

258 ) 

259 P_in_upper = ca.if_else( 

260 self.time < self.market_time.sym, self.P_in_full.sym, self.P_in.ub 

261 ) 

262 self.T_zone.ode = (self.P_in - self.U * (self.T_zone - self.T_amb)) / self.C 

263 self.P_el.alg = self.P_in 

264 self.constraints = [ 

265 (-inf, self.T_zone - self.T_slack, self.T_upper), 

266 (self.T_lower, self.T_zone + self.T_slack, inf), 

267 (0, self.T_slack, inf), 

268 (0, self.P_in, 200), 

269 (P_in_lower, self.P_in, P_in_upper), 

270 ] 

271 objective = sum([self.s_T * self.T_slack**2, self.r_pel * self.P_in]) 

272 obj_std = objective 

273 obj_flex = sum([self.s_T * self.T_slack**2, self.s_P * self.P_el]) 

274 return ca.if_else( 

275 self.time < self.prep_time.sym + self.market_time.sym, 

276 obj_std, 

277 ca.if_else( 

278 self.time 

279 < self.prep_time.sym 

280 + self.flex_event_duration.sym 

281 + self.market_time.sym, 

282 obj_flex, 

283 obj_std, 

284 ), 

285 ) 

286 

287 

288class NegFlexModelConfig(CasadiModelConfig): 

289 inputs: list[CasadiInput] = [ 

290 CasadiInput( 

291 name="P_in", 

292 value=100, 

293 unit="W", 

294 description="Electrical power of heating rod (equivalent to P_el)", 

295 ), 

296 CasadiInput( 

297 name="T_amb", value=290.15, unit="K", description="Ambient air temperature" 

298 ), 

299 CasadiInput( 

300 name="T_upper", 

301 value=294.15, 

302 unit="K", 

303 description="Upper boundary (soft) for T", 

304 ), 

305 CasadiInput( 

306 name="T_lower", 

307 value=290.15, 

308 unit="K", 

309 description="Lower boundary (soft) for T", 

310 ), 

311 CasadiInput( 

312 name="P_in_full", 

313 value=None, 

314 unit="Not defined", 

315 type="pd.Series", 

316 description="full control trajectory output of baseline mpc", 

317 ), 

318 CasadiInput( 

319 name="in_provision", 

320 value=False, 

321 unit="Not defined", 

322 type="bool", 

323 description="Flag indicating whether flexibility should be provisioned", 

324 ), 

325 CasadiInput( 

326 name="P_el_base", 

327 value=0, 

328 unit="Not defined", 

329 type="None", 

330 description="Not defined", 

331 ), 

332 ] 

333 states: list[CasadiState] = [ 

334 CasadiState( 

335 name="T_zone", value=293.15, unit="K", description="Temperature of zone" 

336 ), 

337 CasadiState( 

338 name="T_slack", 

339 value=0, 

340 unit="K", 

341 description="Slack variable for zone temperature", 

342 ), 

343 ] 

344 parameters: list[CasadiParameter] = [ 

345 CasadiParameter( 

346 name="C", value=10000, unit="J/K", description="Thermal capacity of zone" 

347 ), 

348 CasadiParameter( 

349 name="U", value=5, unit="W/K", description="Thermal conductivity of zone" 

350 ), 

351 CasadiParameter( 

352 name="s_T", 

353 value=1, 

354 unit="-", 

355 description="Weight for zone temperature slack var in constraint function", 

356 ), 

357 CasadiParameter( 

358 name="r_pel", 

359 value=1, 

360 unit="-", 

361 description="Weight for P_el in objective function", 

362 ), 

363 CasadiParameter( 

364 name="prep_time", 

365 value=900, 

366 unit="s", 

367 description="Preparation time before switching objective", 

368 ), 

369 CasadiParameter( 

370 name="flex_event_duration", 

371 value=7200, 

372 unit="s", 

373 description="Duration of the flexibility event", 

374 ), 

375 CasadiParameter( 

376 name="market_time", 

377 value=900, 

378 unit="s", 

379 description="Market time associated with the objective switch", 

380 ), 

381 CasadiParameter( 

382 name="s_P", value=10, unit="Not defined", description="Not defined" 

383 ), 

384 ] 

385 outputs: list[CasadiOutput] = [ 

386 CasadiOutput( 

387 name="P_el", 

388 unit="W", 

389 description="Electrical power of heating rod (system input)", 

390 ) 

391 ] 

392 

393 

394class NegFlexModel(CasadiModel): 

395 config: NegFlexModelConfig 

396 

397 def setup_system(self): 

398 P_in_lower = ca.if_else( 

399 self.time < self.market_time.sym, self.P_in_full.sym, self.P_in.lb 

400 ) 

401 P_in_upper = ca.if_else( 

402 self.time < self.market_time.sym, self.P_in_full.sym, self.P_in.ub 

403 ) 

404 self.T_zone.ode = (self.P_in - self.U * (self.T_zone - self.T_amb)) / self.C 

405 self.P_el.alg = self.P_in 

406 self.constraints = [ 

407 (-inf, self.T_zone - self.T_slack, self.T_upper), 

408 (self.T_lower, self.T_zone + self.T_slack, inf), 

409 (0, self.T_slack, inf), 

410 (0, self.P_in, 200), 

411 (P_in_lower, self.P_in, P_in_upper), 

412 ] 

413 objective = sum([self.s_T * self.T_slack**2, self.r_pel * self.P_in]) 

414 obj_std = objective 

415 obj_flex = sum([self.s_T * self.T_slack**2, -self.s_P * self.P_el]) 

416 return ca.if_else( 

417 self.time < self.prep_time.sym + self.market_time.sym, 

418 obj_std, 

419 ca.if_else( 

420 self.time 

421 < self.prep_time.sym 

422 + self.flex_event_duration.sym 

423 + self.market_time.sym, 

424 obj_flex, 

425 obj_std, 

426 ), 

427 )