Skip to content

Commit

Permalink
iter through solvers
Browse files Browse the repository at this point in the history
  • Loading branch information
ahalev committed Apr 14, 2024
1 parent 19a2def commit f16ffef
Showing 1 changed file with 54 additions and 7 deletions.
61 changes: 54 additions & 7 deletions src/pymgrid/algos/mpc/mpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@

logger = logging.getLogger(__name__)


if mosek is not None:
SOLVER_ERRS = mosek.Error, cp.error.SolverError
else:
SOLVER_ERRS = cp.error.SolverError


"""
Attributes:
--------------
Expand Down Expand Up @@ -101,6 +108,7 @@ def __init__(self, microgrid, solver=None):
self.problem = self._create_problem(*parameters)
self._passed_solver = solver
self._solver = self._get_solver()
self._all_solvers = self._solvers(solver)

@property
def has_genset(self):
Expand Down Expand Up @@ -373,6 +381,31 @@ def _create_problem(self, eta, battery_capacity, fuel_cost, cost_battery_cycle,

return cp.Problem(objective, constraints)

def _solvers(self, solver=None):
solvers = []

if solver is not None:
solvers.append(solver)

if 'MOSEK' in cp.installed_solvers():
solvers.append(cp.MOSEK)

if 'GLPK_MI' in cp.installed_solvers():
solvers.append(cp.GLPK_MI)

if self.problem.is_mixed_integer():
if not solvers:
raise RuntimeError(
"If microgrid has a genset, the cvxpy problem becomes mixed integer. Either MOSEK or "
"CVXOPT must be installed.\n"
"You can install both by calling pip install -e .'[genset_mpc]' in the root folder of "
"pymgrid. Note that MOSEK requires a license; see https://www.mosek.com/ for details.\n"
"Academic and trial licenses are available.")
else:
solvers.append(cp.CLARABEL)

return solvers

def _get_solver(self, failure=False):
if not failure:
logger.info("Using default solver." if self._passed_solver is None else f"Using {self._passed_solver} solver.")
Expand Down Expand Up @@ -793,20 +826,34 @@ def _set_and_solve(self,
else:
errs = cp.error.SolverError

try:
self.problem.solve(warm_start=True, solver=self._solver)
except errs:
self._solver = self._get_solver(failure=True)
self.problem.solve(warm_start=True, solver=self._solver)
# try:
# self.problem.solve(warm_start=True, solver=self._solver)
# except errs:
# self._solver = self._get_solver(failure=True)
# self.problem.solve(warm_start=True, solver=self._solver)
#
# if self.problem.status == 'infeasible':
# warn("Infeasible problem")

if self.problem.status == 'infeasible':
warn("Infeasible problem")
for solver in self.solvers():
self.problem.solve(warm_start=True, solver=solver)
break

if self.is_modular:
return self._extract_modular_control(load_vector, verbose)
else:
return self._extract_control_dict(return_steps, pv_vector, load_vector)

def solvers(self):
for solver in self._all_solvers:
try:
yield solver
except SOLVER_ERRS as e:
if solver == self._all_solvers[-1]:
raise cp.error.SolverError(f'Unable to solve problem with solvers: {self._all_solvers}') from e
else:
raise StopIteration # this should never hit, should break out first or hit above exception

def _extract_control_dict(self, return_steps, pv_vector, load_vector):
if return_steps == 0:
if self.has_genset:
Expand Down

0 comments on commit f16ffef

Please sign in to comment.