Skip to content

Commit 4c036d3

Browse files
authored
Merge pull request #131 from bknueven/issue3
adding function for set_instance retries
2 parents 289b2f2 + 3bd3671 commit 4c036d3

File tree

5 files changed

+47
-34
lines changed

5 files changed

+47
-34
lines changed

doc/src/scenario_creator.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ assumed to be equally likely.
5353
EF Supplement List
5454
------------------
5555

56-
The function ``attach_root_node`` takes an optional argument ``nonant_ef_supple_list`` (that is passed through to the ``ScenarioNode`` constructor). This is a list similar to the nonanticipate Var list. These variables will not be given
56+
The function ``attach_root_node`` takes an optional argument ``nonant_ef_suppl_list`` (that is passed through to the ``ScenarioNode`` constructor). This is a list similar to the nonanticipate Var list. These variables will not be given
5757
multipliers by algorithms such as PH, but will be given non-anticipativity
5858
constraints when an EF is formed, either to solve the EF or when bundles are
5959
formed. For some problems, with the appropriate solver, adding redundant nonanticipativity constraints

examples/afew.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ def do_one(dirname, progname, np, argstring):
4343
"3 --bundles-per-rank=0 --max-iterations=50 "
4444
"--default-rho=1 --with-display-convergence-detail "
4545
"--solver-name={} --no-fwph --use-norm-rho-updater".format(solver_name))
46+
do_one("farmer", "farmer_lshapedhub.py", 2,
47+
"3 --bundles-per-rank=0 --max-iterations=50 "
48+
"--solver-name={} --rel-gap=0.0 "
49+
"--no-fwph --max-solver-threads=1".format(solver_name))
4650
do_one("sizes",
4751
"sizes_cylinders.py",
4852
4,

mpisppy/opt/lshaped.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from pyomo.core.plugins.transform.discrete_vars import RelaxIntegerVars
1313
from mpisppy.utils.sputils import find_active_objective
1414
from mpisppy.utils.lshaped_cuts import LShapedCutGenerator
15+
from mpisppy.spopt import set_instance_retry
1516
from pyomo.core import (
1617
Objective, SOSConstraint, Constraint, Var
1718
)
@@ -456,7 +457,7 @@ def create_subproblem(self, scenario_name):
456457
opt.options[k] = v
457458

458459
if sputils.is_persistent(opt):
459-
opt.set_instance(instance)
460+
set_instance_retry(instance, opt, scenario_name)
460461
res = opt.solve(tee=False)
461462
else:
462463
res = opt.solve(instance, tee=False)
@@ -578,7 +579,7 @@ def lshaped_algorithm(self, converger=None):
578579

579580
is_persistent = sputils.is_persistent(opt)
580581
if is_persistent:
581-
opt.set_instance(m)
582+
set_instance_retry(m, opt, "root")
582583

583584
t = time.time()
584585
res, t1, t2 = None, None, None

mpisppy/spopt.py

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -767,36 +767,7 @@ def _create_solvers(self):
767767
if dtiming:
768768
set_instance_start_time = time.time()
769769

770-
# this loop is required to address the sitution where license
771-
# token servers become temporarily over-subscribed / non-responsive
772-
# when large numbers of ranks are in use.
773-
774-
# these parameters should eventually be promoted to a non-PH
775-
# general class / location. even better, the entire retry
776-
# logic can be encapsulated in a sputils.py function.
777-
MAX_ACQUIRE_LICENSE_RETRY_ATTEMPTS = 5
778-
LICENSE_RETRY_SLEEP_TIME = 2 # in seconds
779-
780-
num_retry_attempts = 0
781-
while True:
782-
try:
783-
s._solver_plugin.set_instance(s)
784-
if num_retry_attempts > 0:
785-
print("Acquired solver license (call to set_instance() for scenario=%s) after %d retry attempts" % (sname, num_retry_attempts))
786-
break
787-
# pyomo presently has no general way to trap a license acquisition
788-
# error - so we're stuck with trapping on "any" exception. not ideal.
789-
except:
790-
if num_retry_attempts == 0:
791-
print("Failed to acquire solver license (call to set_instance() for scenario=%s) after first attempt" % (sname))
792-
else:
793-
print("Failed to acquire solver license (call to set_instance() for scenario=%s) after %d retry attempts" % (sname, num_retry_attempts))
794-
if num_retry_attempts == MAX_ACQUIRE_LICENSE_RETRY_ATTEMPTS:
795-
raise RuntimeError("Failed to acquire solver license - call to set_instance() for scenario=%s failed after %d retry attempts" % (sname, num_retry_attempts))
796-
else:
797-
print("Sleeping for %d seconds before re-attempting" % LICENSE_RETRY_SLEEP_TIME)
798-
time.sleep(LICENSE_RETRY_SLEEP_TIME)
799-
num_retry_attempts += 1
770+
set_instance_retry(s, s._solver_plugin, sname)
800771

801772
if dtiming:
802773
set_instance_time = time.time() - set_instance_start_time
@@ -816,3 +787,38 @@ def _create_solvers(self):
816787
for scen_name in s.scen_list:
817788
scen = self.local_scenarios[scen_name]
818789
scen._solver_plugin = s._solver_plugin
790+
791+
792+
# these parameters should eventually be promoted to a non-PH
793+
# general class / location. even better, the entire retry
794+
# logic can be encapsulated in a sputils.py function.
795+
MAX_ACQUIRE_LICENSE_RETRY_ATTEMPTS = 5
796+
LICENSE_RETRY_SLEEP_TIME = 2 # in seconds
797+
798+
def set_instance_retry(subproblem, solver_plugin, subproblem_name):
799+
800+
sname = subproblem_name
801+
# this loop is required to address the sitution where license
802+
# token servers become temporarily over-subscribed / non-responsive
803+
# when large numbers of ranks are in use.
804+
805+
num_retry_attempts = 0
806+
while True:
807+
try:
808+
solver_plugin.set_instance(subproblem)
809+
if num_retry_attempts > 0:
810+
print("Acquired solver license (call to set_instance() for scenario=%s) after %d retry attempts" % (sname, num_retry_attempts))
811+
break
812+
# pyomo presently has no general way to trap a license acquisition
813+
# error - so we're stuck with trapping on "any" exception. not ideal.
814+
except:
815+
if num_retry_attempts == 0:
816+
print("Failed to acquire solver license (call to set_instance() for scenario=%s) after first attempt" % (sname))
817+
else:
818+
print("Failed to acquire solver license (call to set_instance() for scenario=%s) after %d retry attempts" % (sname, num_retry_attempts))
819+
if num_retry_attempts == MAX_ACQUIRE_LICENSE_RETRY_ATTEMPTS:
820+
raise RuntimeError("Failed to acquire solver license - call to set_instance() for scenario=%s failed after %d retry attempts" % (sname, num_retry_attempts))
821+
else:
822+
print("Sleeping for %d seconds before re-attempting" % LICENSE_RETRY_SLEEP_TIME)
823+
time.sleep(LICENSE_RETRY_SLEEP_TIME)
824+
num_retry_attempts += 1

mpisppy/utils/lshaped_cuts.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver
66
import pyomo.contrib.benders.benders_cuts as bc
77

8+
from mpisppy.spopt import set_instance_retry
9+
810
try:
911
from mpi4py import MPI
1012

@@ -77,7 +79,7 @@ def add_subproblem(self, subproblem_fn, subproblem_fn_kwargs, root_eta, subprobl
7779
subproblem_solver = pe.SolverFactory(subproblem_solver)
7880
self.subproblem_solvers.append(subproblem_solver)
7981
if isinstance(subproblem_solver, PersistentSolver):
80-
subproblem_solver.set_instance(subproblem)
82+
set_instance_retry(subproblem, subproblem_solver, subproblem_fn_kwargs['scenario_name'])
8183
if subproblem_solver_options:
8284
for k,v in subproblem_solver_options.items():
8385
subproblem_solver.options[k] = v

0 commit comments

Comments
 (0)