diff --git a/src/optimizer/optimizer.py b/src/optimizer/optimizer.py index fa7eeb17c..4ac1b98ff 100644 --- a/src/optimizer/optimizer.py +++ b/src/optimizer/optimizer.py @@ -141,7 +141,10 @@ def _setup_variables(self): self.variables['s'] = {} for i, bat in enumerate(self.batteries): self.variables['s'][i] = [ - pulp.LpVariable(f"s_{i}_{t}", lowBound=0, upBound=bat.s_capacity) + pulp.LpVariable( + f"s_{i}_{t}", + lowBound=bat.s_min if bat.s_min <= bat.s_initial <= bat.s_max else 0, + upBound=bat.s_max if bat.s_min <= bat.s_initial <= bat.s_max else bat.s_capacity) for t in self.time_steps ] @@ -323,7 +326,10 @@ def _setup_target_function(self): objective += self.variables['c'][i][t] * self.min_import_price * 5e-5 * (self.T - t) * bat.c_priority objective += self.variables['d'][i][t] * self.min_import_price * 5e-5 * (self.T - t) * bat.c_priority - self.problem += objective + # scale the solver-facing objective so CBC's absolute tolerances + # (integrality 1e-6, cutoff increment 1e-5) can separate near-ties; + # reported values are recomputed from variables and stay unscaled + self.problem += objective * 1e4 def _add_energy_balance_constraints(self): """ @@ -430,6 +436,8 @@ def _add_battery_constraints(self): # greater than the maximum SOC or lesser than min SOC, maximum discharging is forced until the max. # SOC is reached or max. charing will be forced until min SOC is reached. for i, bat in enumerate(self.batteries): + if bat.s_min <= bat.s_initial <= bat.s_max: + continue # SOC kept in range by hard variable bounds for t in range(0, self.T): self.problem += (self.variables['s_max_pen'][i][t] >= self.variables['s'][i][t] - bat.s_max) self.problem += (self.variables['s_min_pen'][i][t] >= bat.s_min - self.variables['s'][i][t]) diff --git a/test_cases/013-grid-export-limit-hit.json b/test_cases/013-grid-export-limit-hit.json index 53863f505..4a3d34bcf 100644 --- a/test_cases/013-grid-export-limit-hit.json +++ b/test_cases/013-grid-export-limit-hit.json @@ -199,7 +199,7 @@ }, "expected_response": { "status": "Optimal", - "objective_value": 17.5372629588039, + "objective_value": 17.531374666979104, "limit_violations": { "grid_import_limit_exceeded": false, "grid_export_limit_hit": true diff --git a/test_cases/019-unexpected-charge-spikes.json b/test_cases/019-unexpected-charge-spikes.json index b61ffda0a..5d00cc867 100644 --- a/test_cases/019-unexpected-charge-spikes.json +++ b/test_cases/019-unexpected-charge-spikes.json @@ -274,7 +274,7 @@ }, "expected_response": { "status": "Optimal", - "objective_value": 1.2481766551776774, + "objective_value": 1.2393735754976773, "limit_violations": { "grid_import_limit_exceeded": false, "grid_export_limit_hit": false