diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 912098fc..aee05c42 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -33,6 +33,8 @@ Version 0.3.9 * Up to now the `rhs` argument in the `add_constraints` function was not supporting an expression as an input type. This is now added. +* Improve `run_gurobi` to optionally wait for an available token. + * Linopy now supports python 3.12. **Deprecations** diff --git a/linopy/solvers.py b/linopy/solvers.py index ee5a5352..0552799a 100644 --- a/linopy/solvers.py +++ b/linopy/solvers.py @@ -583,6 +583,25 @@ def get_solver_solution() -> Solution: return Result(status, solution, m) +def start_gurobi_env(wait=60): + """ + Try (forever!) to create an environment. Return the environment once started. Waiting time is in seconds. + """ + # see https://support.gurobi.com/hc/en-us/articles/360029879251-How-do-I-check-the-availability-of-floating-license-tokens + import time + + while True: + try: + # Attempt to construct a Gurobi environment + env = gurobipy.Env() + logging.debug("Gurobi: Token retrieved!") + return env + except gurobipy.GurobiError: + logging.debug("Gurobi: No tokens available...") + # Wait x seconds + time.sleep(wait) + + def run_gurobi( model, io_api=None, @@ -627,7 +646,10 @@ def run_gurobi( with contextlib.ExitStack() as stack: if env is None: - env = stack.enter_context(gurobipy.Env()) + if solver_options.get("WaitTime"): + env = stack.enter_context(start_gurobi_env(solver_options["WaitTime"])) + else: + env = stack.enter_context(gurobipy.Env()) if io_api is None or io_api in FILE_IO_APIS: problem_fn = model.to_file(problem_fn, io_api=io_api) @@ -643,7 +665,8 @@ def run_gurobi( if solver_options is not None: for key, value in solver_options.items(): - m.setParam(key, value) + if key != "WaitTime": + m.setParam(key, value) if log_fn is not None: m.setParam("logfile", log_fn)