31 const unsigned long ts,
35 double current_bs_charge_kWh,
36 const std::vector<float>& future_resid_demand_kW,
37 const std::vector<double>& future_pv_generation_kW,
38 const std::vector<double>& future_hp_shiftable_maxP,
39 const std::vector<double>& future_hp_shiftable_minP,
40 const std::vector<double>& future_hp_shiftable_maxE,
41 const std::vector<double>& future_hp_shiftable_minE,
42 const std::vector<
const std::vector<double>*>* future_ev_shiftable_maxE,
43 const std::vector<
const std::vector<double>*>* future_ev_shiftable_minE,
44 const std::vector<
const std::vector<double>*>* future_ev_maxP,
45 const bool optimize_PV_size,
46 const bool optimize_BS_size,
47 const std::list<std::vector<double>>* total_PV_generation_per_section_kW,
48 const std::list<double>* max_PV_power_per_section_kWp
51 MPSolver* model = MPSolver::CreateSolver(
"SCIP");
54 std::cout <<
"SCIP solver unavailable." << std::endl;
58 const double infinity = model->infinity();
62 const unsigned int Tp = T + 1;
63 const unsigned long n_pv_sections = optimize_PV_size ? total_PV_generation_per_section_kW->size() : 0;
64 std::vector<MPVariable*> p_resid_eq1(T);
65 std::vector<MPVariable*> p_pv_to_resid(T);
66 std::vector<MPVariable*> p_pv_eq2(T);
67 std::vector<MPVariable*> p_hp_kW(T);
68 std::vector<MPVariable*> e_hp_cum_kWh(T);
69 std::vector<std::vector<MPVariable*>> p_ev_kW(
n_cars);
70 std::vector<std::vector<MPVariable*>> e_ev_cum_kWh(
n_cars);
71 std::vector<MPVariable*> p_bs_in_kW(T);
72 std::vector<MPVariable*> p_bs_out_kW(T);
73 std::vector<MPVariable*> e_bs_kWh(Tp);
74 std::vector<MPVariable*> x_demand_kW(T);
75 std::vector<MPVariable*> x_feedin_kW(T);
76 MPVariable* dim_bs_E_kWh;
77 MPVariable* dim_bs_P_kW;
78 std::vector<MPVariable*> dim_pv_per_sec_kW(n_pv_sections);
80 if (optimize_PV_size) {
81 auto it = max_PV_power_per_section_kWp->cbegin();
82 auto it2 = total_PV_generation_per_section_kW->cbegin();
83 for (
unsigned long sectionIdx = 0; sectionIdx < n_pv_sections; sectionIdx++) {
85 if (it == max_PV_power_per_section_kWp->cend()) {
86 throw std::runtime_error(
"Error in the optimization unit: not enough values provided in argument 'max_PV_power_per_section_kWp' for method updateController().");
89 if ( (*it2).size() < T ) {
90 throw std::runtime_error(
"Error in the optimization unit: parameter 'max_PV_power_per_section_kWp' has a vector to small size for section with index " + to_string(sectionIdx) +
".");
93 double upper_limit_for_this_section_kWp = *it;
94 dim_pv_per_sec_kW[sectionIdx] = model->MakeNumVar(0.0, upper_limit_for_this_section_kWp,
"dim_pv_per_sec_kW_" + std::to_string(sectionIdx));
99 if (optimize_BS_size) {
100 max_e_bs_kWh = infinity;
101 max_p_bs_kW = infinity;
102 dim_bs_E_kWh = model->MakeNumVar(0.0, infinity,
"dim_bs_E_kWh");
103 dim_bs_P_kW = model->MakeNumVar(0.0, infinity,
"dim_bs_P_kW");
105 MPConstraint*
const c_bs_P = model->MakeRowConstraint(0.0, 0.0,
"Bound BS power to capacity.");
106 c_bs_P->SetCoefficient(dim_bs_P_kW, -1.0);
109 if (current_bs_charge_kWh > 0.0) {
110 std::cerr <<
"Warning: current_bs_charge_kWh > 0 --> Setting this value to 0.0" << std::endl;
111 current_bs_charge_kWh = 0.0;
115 for (
unsigned int t = 0; t < T; t++) {
116 const std::string tstr = to_string(t);
117 p_resid_eq1[t] = model->MakeNumVar(0.0, infinity,
"p_resid_eq1_" + tstr);
118 p_pv_to_resid[t]= model->MakeNumVar(0.0, infinity,
"p_pv_to_resid_" + tstr);
119 p_pv_eq2[t] = model->MakeNumVar(0.0, infinity,
"p_pv_eq2_" + tstr);
120 p_hp_kW[t] = model->MakeNumVar(future_hp_shiftable_minP[t], future_hp_shiftable_maxP[t],
"p_hp_kW_" + tstr);
122 e_hp_cum_kWh[t] = model->MakeNumVar(future_hp_shiftable_minE[t], future_hp_shiftable_maxE[t],
"e_hp_cum_kWh_"+ tstr);
123 p_bs_in_kW[t] = model->MakeNumVar(0.0, max_p_bs_kW,
"p_bs_in_kW_" + tstr);
124 p_bs_out_kW[t] = model->MakeNumVar(0.0, max_p_bs_kW,
"p_bs_out_kW_" + tstr);
125 x_demand_kW[t] = model->MakeNumVar(0.0, infinity,
"x_demand_kW_" + tstr);
126 x_feedin_kW[t] = model->MakeNumVar(0.0, infinity,
"x_feedin_kW_" + tstr);
128 if (optimize_BS_size) {
129 MPConstraint*
const c_bs_P_upper_limit = model->MakeRowConstraint(-infinity, 0.0,
"Bound for BS power " + tstr);
130 c_bs_P_upper_limit->SetCoefficient(p_bs_in_kW[t], 1.0);
131 c_bs_P_upper_limit->SetCoefficient(p_bs_out_kW[t], 1.0);
132 c_bs_P_upper_limit->SetCoefficient(dim_bs_P_kW, -1.0);
136 for (
unsigned int t = 0; t < Tp; t++) {
137 const std::string tstr = to_string(t);
138 e_bs_kWh[t] = model->MakeNumVar(0.0, max_e_bs_kWh,
"e_bs_kWh_" + tstr);
139 if (optimize_BS_size) {
140 MPConstraint*
const c_bs_E_upper_limit = model->MakeRowConstraint(-infinity, 0.0,
"Bound for BS capacity " + tstr);
141 c_bs_E_upper_limit->SetCoefficient(e_bs_kWh[t], 1.0);
142 c_bs_E_upper_limit->SetCoefficient(dim_bs_E_kWh, -1.0);
146 for (
unsigned long evIdx = 0; evIdx <
n_cars; evIdx++) {
147 p_ev_kW[evIdx].clear();
148 e_ev_cum_kWh[evIdx].clear();
149 for (
unsigned int t = 0; t < T; t++) {
150 const std::string tstr = to_string(t);
151 const std::string estr = to_string(evIdx);
153 p_ev_kW[evIdx].push_back(
154 model->MakeNumVar(0.0, future_ev_maxP->at(evIdx)->at(t),
"p_ev" + estr +
"_kW_" + tstr)
156 e_ev_cum_kWh[evIdx].push_back(
158 future_ev_shiftable_minE->at(evIdx)->at(t),
159 future_ev_shiftable_maxE->at(evIdx)->at(t),
160 "e_ev" + estr +
"_cum_kWh_" + tstr)
166 MPConstraint*
const c0 = model->MakeRowConstraint(current_bs_charge_kWh, current_bs_charge_kWh,
"Init BS state");
167 c0->SetCoefficient(e_bs_kWh[0], 1.0);
169 for (
unsigned int t = 0; t < T; t++) {
175 const std::string tstr = to_string(t);
176 MPConstraint*
const c = model->MakeRowConstraint(0.0, 0.0,
"BESS balance " + tstr);
177 c->SetCoefficient(e_bs_kWh[t + 1], -1.0);
186 for (
unsigned int t = 0; t < T; t++) {
187 const std::string tstr = to_string(t);
188 MPConstraint*
const c = model->MakeRowConstraint(-infinity, max_p_cs_kW,
"Max CS power " + tstr);
189 for (
unsigned long evIdx = 0; evIdx <
n_cars; evIdx++) {
190 c->SetCoefficient( p_ev_kW[evIdx][t], 1.0 );
194 for (
unsigned int t = 0; t < T; t++) {
195 const std::string tstr = to_string(t);
196 MPConstraint*
const c1 = model->MakeRowConstraint(future_resid_demand_kW[t], future_resid_demand_kW[t],
"Residential demand linkage " + tstr);
197 c1->SetCoefficient(p_resid_eq1[t], 1.0);
198 c1->SetCoefficient(p_pv_to_resid[t], 1.0);
199 if (!optimize_PV_size) {
200 MPConstraint*
const c2 = model->MakeRowConstraint(future_pv_generation_kW[t], future_pv_generation_kW[t],
"PV generation linkage " + tstr);
201 c2->SetCoefficient(p_pv_eq2[t], 1.0);
202 c2->SetCoefficient(p_pv_to_resid[t], 1.0);
204 MPConstraint*
const c2_PVopti = model->MakeRowConstraint(0.0, 0.0,
"PV generation linkage in case of PV size opti " + tstr);
205 c2_PVopti->SetCoefficient(p_pv_eq2[t], 1.0);
206 c2_PVopti->SetCoefficient(p_pv_to_resid[t], 1.0);
207 auto it = total_PV_generation_per_section_kW->cbegin();
208 for (
unsigned long sectionIdx = 0; sectionIdx < n_pv_sections; sectionIdx++) {
210 const std::vector<double>& time_series_for_this_section = *it++;
211 c2_PVopti->SetCoefficient(dim_pv_per_sec_kW[sectionIdx], -time_series_for_this_section[t]);
218 for (
unsigned int t = 0; t < T; t++) {
219 const std::string tstr = to_string(t);
220 double resid_minus_pv_kW = future_resid_demand_kW[t] - future_pv_generation_kW[t];
221 MPConstraint*
const c = model->MakeRowConstraint(-resid_minus_pv_kW, -resid_minus_pv_kW,
"CU Power Balance " + tstr);
222 c->SetCoefficient(p_bs_in_kW[t], 1.0);
223 c->SetCoefficient(p_bs_out_kW[t],-1.0);
224 c->SetCoefficient(p_hp_kW[t], 1.0);
225 c->SetCoefficient(x_feedin_kW[t], 1.0);
226 c->SetCoefficient(x_demand_kW[t],-1.0);
227 for (
unsigned long evIdx = 0; evIdx <
n_cars; evIdx++) {
228 c->SetCoefficient(p_ev_kW[evIdx][t], 1.0);
234 std::vector<MPVariable*> p_bs_in_kW_1(T);
235 std::vector<MPVariable*> p_bs_in_kW_2(T);
236 std::vector<MPVariable*> p_hp_kW_1(T);
237 std::vector<MPVariable*> p_hp_kW_2(T);
238 std::vector<MPVariable*> p_cs_kW_1(T);
239 std::vector<MPVariable*> p_cs_kW_2(T);
240 for (
unsigned int t = 0; t < T; t++) {
241 const std::string tstr = to_string(t);
242 p_bs_in_kW_1[t] = model->MakeNumVar(0.0, max_p_bs_kW,
"p_bs_kW_BalEq1_" + tstr);
243 p_bs_in_kW_2[t] = model->MakeNumVar(0.0, max_p_bs_kW,
"p_bs_kW_BalEq2_" + tstr);
244 p_hp_kW_1[t] = model->MakeNumVar(0.0, infinity,
"p_hp_kW_BalEq1_" + tstr);
245 p_hp_kW_2[t] = model->MakeNumVar(0.0, infinity,
"p_hp_kW_BalEq2_" + tstr);
246 p_cs_kW_1[t] = model->MakeNumVar(0.0, max_p_cs_kW,
"p_cs_kW_BalEq1_" + tstr);
247 p_cs_kW_2[t] = model->MakeNumVar(0.0, max_p_cs_kW,
"p_cs_kW_BalEq2_" + tstr);
249 for (
unsigned int t = 0; t < T; t++) {
250 const std::string tstr = to_string(t);
252 MPConstraint*
const c1 = model->MakeRowConstraint(0.0, 0.0,
"CU Power Balance EQ1 " + tstr);
253 c1->SetCoefficient(p_resid_eq1[t], 1.0);
254 c1->SetCoefficient(p_hp_kW_1[t], 1.0);
255 c1->SetCoefficient(p_cs_kW_1[t], 1.0);
256 c1->SetCoefficient(p_bs_out_kW[t], -1.0);
257 c1->SetCoefficient(x_demand_kW[t], -1.0);
258 c1->SetCoefficient(p_bs_in_kW_1[t], 1.0);
260 MPConstraint*
const c2 = model->MakeRowConstraint(0.0, 0.0,
"CU Power Balance EQ2 " + tstr);
261 c2->SetCoefficient(p_hp_kW_2[t], 1.0);
262 c2->SetCoefficient(p_cs_kW_2[t], 1.0);
263 c2->SetCoefficient(x_feedin_kW[t], 1.0);
264 c2->SetCoefficient(p_bs_in_kW_2[t],1.0);
265 c2->SetCoefficient(p_pv_eq2[t], -1.0);
267 MPConstraint*
const cl0 = model->MakeRowConstraint(0.0, 0.0,
"CU P Bal Linkage BS " + tstr);
268 cl0->SetCoefficient(p_bs_in_kW[t], -1.0);
269 cl0->SetCoefficient(p_bs_in_kW_1[t], 1.0);
270 cl0->SetCoefficient(p_bs_in_kW_2[t], 1.0);
271 MPConstraint*
const cl1 = model->MakeRowConstraint(0.0, 0.0,
"CU P Bal Linkage HP " + tstr);
272 cl1->SetCoefficient(p_hp_kW[t], -1.0);
273 cl1->SetCoefficient(p_hp_kW_1[t], 1.0);
274 cl1->SetCoefficient(p_hp_kW_2[t], 1.0);
275 MPConstraint*
const cl2 = model->MakeRowConstraint(0.0, 0.0,
"CU P Bal Linkage CS " + tstr);
276 cl2->SetCoefficient(p_cs_kW_1[t], 1.0);
277 cl2->SetCoefficient(p_cs_kW_2[t], 1.0);
278 for (
unsigned long evIdx = 0; evIdx <
n_cars; evIdx++) {
279 cl2->SetCoefficient(p_ev_kW[evIdx][t], -1.0);
285 std::vector<MPVariable*> p_hp_kW_1(T);
286 std::vector<MPVariable*> p_hp_kW_2(T);
287 std::vector<MPVariable*> p_cs_kW_1(T);
288 std::vector<MPVariable*> p_cs_kW_2(T);
289 for (
unsigned int t = 0; t < T; t++) {
290 const std::string tstr = to_string(t);
291 p_hp_kW_1[t] = model->MakeNumVar(0.0, infinity,
"p_hp_kW_BalEq1_" + tstr);
292 p_hp_kW_2[t] = model->MakeNumVar(0.0, infinity,
"p_hp_kW_BalEq2_" + tstr);
293 p_cs_kW_1[t] = model->MakeNumVar(0.0, max_p_cs_kW,
"p_cs_kW_BalEq1_" + tstr);
294 p_cs_kW_2[t] = model->MakeNumVar(0.0, max_p_cs_kW,
"p_cs_kW_BalEq2_" + tstr);
296 for (
unsigned int t = 0; t < T; t++) {
297 const std::string tstr = to_string(t);
299 MPConstraint*
const c1 = model->MakeRowConstraint(0.0, 0.0,
"CU Power Balance EQ1 " + tstr);
300 c1->SetCoefficient(p_resid_eq1[t], 1.0);
301 c1->SetCoefficient(p_hp_kW_1[t], 1.0);
302 c1->SetCoefficient(p_cs_kW_1[t], 1.0);
303 c1->SetCoefficient(p_bs_out_kW[t], -1.0);
304 c1->SetCoefficient(x_demand_kW[t], -1.0);
306 MPConstraint*
const c2 = model->MakeRowConstraint(0.0, 0.0,
"CU Power Balance EQ2 " + tstr);
307 c2->SetCoefficient(p_hp_kW_2[t], 1.0);
308 c2->SetCoefficient(p_cs_kW_2[t], 1.0);
309 c2->SetCoefficient(x_feedin_kW[t], 1.0);
310 c2->SetCoefficient(p_bs_in_kW[t], 1.0);
311 c2->SetCoefficient(p_pv_eq2[t], -1.0);
313 MPConstraint*
const cl1 = model->MakeRowConstraint(0.0, 0.0,
"CU P Bal Linkage 1 " + tstr);
314 cl1->SetCoefficient(p_hp_kW[t], -1.0);
315 cl1->SetCoefficient(p_hp_kW_1[t], 1.0);
316 cl1->SetCoefficient(p_hp_kW_2[t], 1.0);
317 MPConstraint*
const cl2 = model->MakeRowConstraint(0.0, 0.0,
"CU P Bal Linkage 2 " + tstr);
318 cl2->SetCoefficient(p_cs_kW_1[t], 1.0);
319 cl2->SetCoefficient(p_cs_kW_2[t], 1.0);
320 for (
unsigned long evIdx = 0; evIdx <
n_cars; evIdx++) {
321 cl2->SetCoefficient(p_ev_kW[evIdx][t], -1.0);
326 for (
unsigned int tm = 0; tm < T; tm++) {
327 const std::string tmstr = to_string(tm);
330 MPConstraint*
const c = model->MakeRowConstraint(0.0, 0.0,
"HP Balance " + tmstr);
332 for (
unsigned int t = 0; t <= tm; t++) {
336 c->SetCoefficient(e_hp_cum_kWh[tm], -1.0);
338 for (
unsigned long evIdx = 0; evIdx <
n_cars; evIdx++) {
339 for (
unsigned int tm = 0; tm < T; tm++) {
340 const std::string tmstr = to_string(tm);
341 MPConstraint*
const c = model->MakeRowConstraint(0.0, 0.0,
"EV Balance " + tmstr);
342 for (
unsigned int t = 0; t <= tm; t++) {
346 c->SetCoefficient(e_ev_cum_kWh[evIdx][tm], -1.0);
350 MPObjective*
const objective = model->MutableObjective();
352 for (
unsigned int t = 0; t < T; t++) {
356 objective->SetCoefficient(x_demand_kW[t], current_demand_tariff);
359 if (optimize_PV_size) {
360 for (
unsigned long sectionIdx = 0; sectionIdx < n_pv_sections; sectionIdx++) {
364 if (optimize_BS_size) {
368 MPVariable *
const max_demand_kW = model->MakeNumVar(0.0, infinity,
"max_demand_kW");
369 objective->SetCoefficient(max_demand_kW, 1.0);
370 for (
unsigned int t = 0; t < T; t++) {
371 MPConstraint*
const c = model->MakeRowConstraint(-infinity, 0.0);
372 c->SetCoefficient(x_demand_kW[t], 1.0);
373 c->SetCoefficient(max_demand_kW, -1.0);
376 for (
unsigned int t = 0; t < T; t++) {
380 objective->SetCoefficient(x_demand_kW[t], current_emissions);
384 objective->SetMinimization();
387 const MPSolver::ResultStatus result_status = model->Solve();
388 if (result_status != MPSolver::OPTIMAL) {
389 std::cerr <<
"Optimization not resulting in optimal value.\n";
390 std::cerr <<
"Solver status = " << result_status << std::endl;
395 for (
unsigned int t = 0; t < T; t++) {
396 bs_power[t] = p_bs_in_kW[t]->solution_value() - p_bs_out_kW[t]->solution_value();
397 hp_power[t] = p_hp_kW[t]->solution_value();
398 for (
unsigned long evIdx = 0; evIdx <
n_cars; evIdx++) {
399 ev_power[evIdx][t] = p_ev_kW[evIdx][t]->solution_value();
402 if (optimize_PV_size) {
404 for (
unsigned long sectionIdx = 0; sectionIdx < n_pv_sections; sectionIdx++) {
408 if (optimize_BS_size) {