@@ -154,10 +154,13 @@ def _setup_variables(self):
154154
155155 # penalty variable for not being able to charge with the required power
156156 self .variables ['p_demand_pen' ] = [[None for t in self .time_steps ] for i in range (len (self .batteries ))]
157+ # binary variable to allow one out of two alternative constraints
158+ self .variables ['z_p_demand' ] = [[None for t in self .time_steps ] for i in range (len (self .batteries ))]
157159 for i , bat in enumerate (self .batteries ):
158160 if bat .p_demand is not None :
159161 for t in self .time_steps :
160162 self .variables ['p_demand_pen' ][i ][t ] = pulp .LpVariable (f"p_demand_pen_{ i } _{ t } " , lowBound = 0 )
163+ self .variables ['z_p_demand' ][i ][t ] = pulp .LpVariable (f"z_p_demand_{ i } _{ t } " , cat = 'Binary' )
161164
162165 # penalty variable for staying above max SOC and below min SOC
163166 self .variables ['s_max_pen' ] = [[pulp .LpVariable (f"s_max_pen_{ i } _{ t } " , lowBound = 0 ) for t in self .time_steps ] for i in range (len (self .batteries ))]
@@ -269,7 +272,7 @@ def _setup_target_function(self):
269272 if self .batteries [i ].s_goal [t ] > 0 :
270273 # negative target function contribution in a maximizing optimization
271274 objective += - self .prc_e_goal_pen * self .variables ['s_goal_pen' ][i ][t ]
272- # unmet charging demand due to battery reaching maximum SOC
275+ # unmet charging demand due to battery reaching maximum SOC with incentive to do charging early
273276 if bat .p_demand is not None :
274277 for t in self .time_steps :
275278 objective += - self .prc_p_goal_pen \
@@ -444,10 +447,15 @@ def _add_battery_constraints(self):
444447 if bat .p_demand [t ] > 0 :
445448 # clip required charge to max charging power if needed
446449 # and leave some air to breathe for the optimizer
447- p_demand = bat .p_demand [t ]
448- if p_demand >= bat .c_max * self .time_series .dt [t ] / 3600. :
449- p_demand = bat .c_max * self .time_series .dt [t ] / 3600. * 0.999
450- self .problem += (self .variables ['c' ][i ][t ] + self .variables ['p_demand_pen' ][i ][t ] >= p_demand )
450+ p_demand = min (bat .c_max * self .time_series .dt [t ] / 3600. , bat .p_demand [t ])
451+ # two alternative constraints, only one is active:
452+ # constraint option 1: charge energy tries to reach min charge energy parameter
453+ self .problem += (self .variables ['c' ][i ][t ] + self .variables ['p_demand_pen' ][i ][t ]
454+ + self .M * self .variables ['z_p_demand' ][i ][t ] >= p_demand )
455+ # constraint option 2: charge energy tries to reach energy to fill the battery to s_max
456+ self .problem += (self .variables ['c' ][i ][t ] + self .variables ['p_demand_pen' ][i ][t ]
457+ + self .M * (1 - self .variables ['z_p_demand' ][i ][t ])
458+ - (self .batteries [i ].s_max - self .variables ['s' ][i ][t ]) >= 0. )
451459 elif bat .c_min > 0 :
452460 # in time steps without given charging demand, apply normal lower bound:
453461 # Lower bound: either 0 or at least c_min
0 commit comments