From 7eb0cbe205b3774c70e509c7cf3787f8198cca5b Mon Sep 17 00:00:00 2001 From: Stephen Cini Date: Thu, 2 Jul 2026 13:07:42 -0600 Subject: [PATCH 01/10] Add time limit warning to global solver --- pyomo/devel/initialization/global_init.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyomo/devel/initialization/global_init.py b/pyomo/devel/initialization/global_init.py index 83b8afba98e..8a90b373f94 100644 --- a/pyomo/devel/initialization/global_init.py +++ b/pyomo/devel/initialization/global_init.py @@ -31,6 +31,12 @@ def _initialize_with_global_solver( 'interfaces, so the global solvers are limited to ScipDirect, ' 'ScipPersistent, and GurobiDirectMINLP.' ) + # Check if time limit is provided for global solver + if global_solver.config.time_limit is None: + logger.warning('No time limit set for global optimizer. ' + 'For a large model, this may take a long time. ' + 'Consider setting a time limit using global_solver.config.time_limit.') + res = global_solver.solve( nlp, load_solutions=True, From 0f97cb0274e1e723c630225d68bcad24bb872da7 Mon Sep 17 00:00:00 2001 From: Stephen Cini Date: Wed, 8 Jul 2026 08:41:30 -0600 Subject: [PATCH 02/10] Ran black --- pyomo/devel/initialization/global_init.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pyomo/devel/initialization/global_init.py b/pyomo/devel/initialization/global_init.py index 8a90b373f94..10b33a9a0cb 100644 --- a/pyomo/devel/initialization/global_init.py +++ b/pyomo/devel/initialization/global_init.py @@ -33,9 +33,11 @@ def _initialize_with_global_solver( ) # Check if time limit is provided for global solver if global_solver.config.time_limit is None: - logger.warning('No time limit set for global optimizer. ' - 'For a large model, this may take a long time. ' - 'Consider setting a time limit using global_solver.config.time_limit.') + logger.warning( + 'No time limit set for global optimizer. ' + 'For a large model, this may take a long time. ' + 'Consider setting a time limit using global_solver.config.time_limit.' + ) res = global_solver.solve( nlp, From 352c828c54b09972577b42bdc5bf93707cc33280 Mon Sep 17 00:00:00 2001 From: Stephen Cini Date: Wed, 8 Jul 2026 09:29:06 -0600 Subject: [PATCH 03/10] Adjusted order to solve unbounded nlp at end of method --- pyomo/devel/initialization/global_init.py | 10 ----- pyomo/devel/initialization/initialize.py | 41 +++++++++++++++++++- pyomo/devel/initialization/lp_approx_init.py | 15 +------ 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/pyomo/devel/initialization/global_init.py b/pyomo/devel/initialization/global_init.py index 10b33a9a0cb..3f3ecb9fee0 100644 --- a/pyomo/devel/initialization/global_init.py +++ b/pyomo/devel/initialization/global_init.py @@ -48,15 +48,5 @@ def _initialize_with_global_solver( logger.info( f'solved NLP with {global_solver.name}: {res.solution_status}, {res.termination_condition}' ) - res = nlp_solver.solve( - nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False - ) - logger.info( - f'solved NLP with {nlp_solver.name}: {res.solution_status}, {res.termination_condition}' - ) - if res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: - res.solution_loader.load_vars() - else: - logger.warning('initialization was not successful via global optimization') return res diff --git a/pyomo/devel/initialization/initialize.py b/pyomo/devel/initialization/initialize.py index 7b1117cf5b9..fd481644b30 100644 --- a/pyomo/devel/initialization/initialize.py +++ b/pyomo/devel/initialization/initialize.py @@ -155,8 +155,22 @@ def initialize_with_piecewise_linear_approximation( ) finally: _cleanup(orig_var_data) + # Try final nlp solve - return res + # solve the original problem from the initialized solution + nlp_res = nlp_solver.solve( + nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False + ) + logger.info( + f'solved NLP: {nlp_res.solution_status}, {nlp_res.termination_condition}' + ) + + if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: + nlp_res.solution_loader.load_vars() + else: + logger.warning('initialization was not successful via LP approximation') + + return nlp_res def initialize_with_LP_approximation( @@ -239,7 +253,20 @@ def initialize_with_LP_approximation( finally: _cleanup(orig_var_data) - return res + # solve the original problem from the initialized solution + nlp_res = nlp_solver.solve( + nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False + ) + logger.info( + f'solved NLP: {nlp_res.solution_status}, {nlp_res.termination_condition}' + ) + + if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: + nlp_res.solution_loader.load_vars() + else: + logger.warning('initialization was not successful via LP approximation') + + return nlp_res def initialize_with_global_opt( @@ -293,4 +320,14 @@ def initialize_with_global_opt( finally: _cleanup(orig_var_data) + res = nlp_solver.solve( + nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False + ) + logger.info( + f'solved NLP with {nlp_solver.name}: {res.solution_status}, {res.termination_condition}' + ) + if res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: + res.solution_loader.load_vars() + else: + logger.warning('initialization was not successful via global optimization') return res diff --git a/pyomo/devel/initialization/lp_approx_init.py b/pyomo/devel/initialization/lp_approx_init.py index c8f7c2ff4fc..d20c92c0203 100644 --- a/pyomo/devel/initialization/lp_approx_init.py +++ b/pyomo/devel/initialization/lp_approx_init.py @@ -218,17 +218,4 @@ def _initialize_with_LP_approximation( ) logger.info(f'solved LP: {lp_res.solution_status}, {lp_res.termination_condition}') - # try solving the NLP - nlp_res = nlp_solver.solve( - orig_nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False - ) - logger.info( - f'solved NLP: {nlp_res.solution_status}, {nlp_res.termination_condition}' - ) - - if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: - nlp_res.solution_loader.load_vars() - else: - logger.warning('initialization was not successful via LP approximation') - - return nlp_res + return lp_res From 8c0a358441100f400f07e935fd0d2cfbd73969ce Mon Sep 17 00:00:00 2001 From: Stephen Cini Date: Wed, 8 Jul 2026 10:30:53 -0600 Subject: [PATCH 04/10] Made naming consistent, commented out pwl while debugging tests --- pyomo/devel/initialization/initialize.py | 40 +++++++++++++----------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/pyomo/devel/initialization/initialize.py b/pyomo/devel/initialization/initialize.py index fd481644b30..1371ab077af 100644 --- a/pyomo/devel/initialization/initialize.py +++ b/pyomo/devel/initialization/initialize.py @@ -155,22 +155,25 @@ def initialize_with_piecewise_linear_approximation( ) finally: _cleanup(orig_var_data) - # Try final nlp solve - # solve the original problem from the initialized solution - nlp_res = nlp_solver.solve( - nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False - ) - logger.info( - f'solved NLP: {nlp_res.solution_status}, {nlp_res.termination_condition}' - ) + # Commented out while I fix testing + # # Try final nlp solve - if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: - nlp_res.solution_loader.load_vars() - else: - logger.warning('initialization was not successful via LP approximation') + # # solve the original problem from the initialized solution + # nlp_res = nlp_solver.solve( + # nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False + # ) + # logger.info( + # f'solved NLP: {nlp_res.solution_status}, {nlp_res.termination_condition}' + # ) - return nlp_res + # if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: + # nlp_res.solution_loader.load_vars() + # else: + # logger.warning('initialization was not successful via LP approximation') + + # return nlp_res + return res def initialize_with_LP_approximation( @@ -320,14 +323,15 @@ def initialize_with_global_opt( finally: _cleanup(orig_var_data) - res = nlp_solver.solve( + nlp_res = nlp_solver.solve( nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False ) logger.info( - f'solved NLP with {nlp_solver.name}: {res.solution_status}, {res.termination_condition}' + f'solved NLP with {nlp_solver.name}: {nlp_res.solution_status}, {nlp_res.termination_condition}' ) - if res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: - res.solution_loader.load_vars() + if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: + nlp_res.solution_loader.load_vars() else: logger.warning('initialization was not successful via global optimization') - return res + + return nlp_res From b6947a0c66446d83687d53649a97ea68b2f89e09 Mon Sep 17 00:00:00 2001 From: Stephen Cini Date: Wed, 8 Jul 2026 10:52:51 -0600 Subject: [PATCH 05/10] Fixed test, ran black --- pyomo/devel/initialization/initialize.py | 29 +++++++++---------- .../tests/test_initialization.py | 5 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/pyomo/devel/initialization/initialize.py b/pyomo/devel/initialization/initialize.py index 1371ab077af..b227d7819d4 100644 --- a/pyomo/devel/initialization/initialize.py +++ b/pyomo/devel/initialization/initialize.py @@ -156,21 +156,20 @@ def initialize_with_piecewise_linear_approximation( finally: _cleanup(orig_var_data) - # Commented out while I fix testing - # # Try final nlp solve - - # # solve the original problem from the initialized solution - # nlp_res = nlp_solver.solve( - # nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False - # ) - # logger.info( - # f'solved NLP: {nlp_res.solution_status}, {nlp_res.termination_condition}' - # ) - - # if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: - # nlp_res.solution_loader.load_vars() - # else: - # logger.warning('initialization was not successful via LP approximation') + # Try final nlp solve + + # solve the original problem from the initialized solution + nlp_res = nlp_solver.solve( + nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False + ) + logger.info( + f'solved NLP: {nlp_res.solution_status}, {nlp_res.termination_condition}' + ) + + if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: + nlp_res.solution_loader.load_vars() + else: + logger.warning('initialization was not successful via LP approximation') # return nlp_res return res diff --git a/pyomo/devel/initialization/tests/test_initialization.py b/pyomo/devel/initialization/tests/test_initialization.py index 67a260d9904..b9851888f39 100644 --- a/pyomo/devel/initialization/tests/test_initialization.py +++ b/pyomo/devel/initialization/tests/test_initialization.py @@ -196,6 +196,8 @@ def test_pwl_init(self): 25: ([-9.91992877683681], 1e-6, 1e-6), 26: ([-9.920038488200985], 1e-6, 1e-6), 27: ([-9.920096055464825], 1e-6, 1e-6), + # For new second solve, repeat last value. + 28: ([-9.920096055464825], 1e-6, 1e-6), }, ) mip_solver = SolverFactory('highs') @@ -230,5 +232,4 @@ def test_pwl_ineq(self): import logging logging.basicConfig(level=logging.INFO) - t = TestInit() - t.test_pwl_init() + t = TestInit() \ No newline at end of file From 3cb15856b34415431aa58b59326ca88ec0447b16 Mon Sep 17 00:00:00 2001 From: Stephen Cini Date: Wed, 8 Jul 2026 10:55:10 -0600 Subject: [PATCH 06/10] Forgot comment, ran black --- pyomo/devel/initialization/initialize.py | 4 +--- pyomo/devel/initialization/tests/test_initialization.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pyomo/devel/initialization/initialize.py b/pyomo/devel/initialization/initialize.py index b227d7819d4..815cd94669e 100644 --- a/pyomo/devel/initialization/initialize.py +++ b/pyomo/devel/initialization/initialize.py @@ -157,7 +157,6 @@ def initialize_with_piecewise_linear_approximation( _cleanup(orig_var_data) # Try final nlp solve - # solve the original problem from the initialized solution nlp_res = nlp_solver.solve( nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False @@ -171,8 +170,7 @@ def initialize_with_piecewise_linear_approximation( else: logger.warning('initialization was not successful via LP approximation') - # return nlp_res - return res + return nlp_res def initialize_with_LP_approximation( diff --git a/pyomo/devel/initialization/tests/test_initialization.py b/pyomo/devel/initialization/tests/test_initialization.py index b9851888f39..042bb890828 100644 --- a/pyomo/devel/initialization/tests/test_initialization.py +++ b/pyomo/devel/initialization/tests/test_initialization.py @@ -232,4 +232,4 @@ def test_pwl_ineq(self): import logging logging.basicConfig(level=logging.INFO) - t = TestInit() \ No newline at end of file + t = TestInit() From 6aa9ce0e9a80d0eaf40a1f31dc7102bc5092a898 Mon Sep 17 00:00:00 2001 From: Stephen Cini Date: Thu, 9 Jul 2026 13:17:05 -0600 Subject: [PATCH 07/10] define helper fcn to retry solve, removed from finally block --- pyomo/devel/initialization/initialize.py | 55 +++++++++--------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/pyomo/devel/initialization/initialize.py b/pyomo/devel/initialization/initialize.py index 815cd94669e..6d449fa8e54 100644 --- a/pyomo/devel/initialization/initialize.py +++ b/pyomo/devel/initialization/initialize.py @@ -76,6 +76,21 @@ def _try_nlp_solve(nlp: BlockData, nlp_solver: SolverBase): logger.info('NLP solved without any initialization') return res +def _retry_nlp_solve(nlp: BlockData, nlp_solver: SolverBase): + # retry to solve the original nlp after using an initialization method + nlp_res = nlp_solver.solve( + nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False + ) + logger.info( + f'solved NLP with {nlp_solver.name}: {nlp_res.solution_status}, {nlp_res.termination_condition}' + ) + if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: + nlp_res.solution_loader.load_vars() + else: + logger.warning('initialization did not find feasible solution') + + return nlp_res + def initialize_with_piecewise_linear_approximation( nlp: BlockData, @@ -156,19 +171,7 @@ def initialize_with_piecewise_linear_approximation( finally: _cleanup(orig_var_data) - # Try final nlp solve - # solve the original problem from the initialized solution - nlp_res = nlp_solver.solve( - nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False - ) - logger.info( - f'solved NLP: {nlp_res.solution_status}, {nlp_res.termination_condition}' - ) - - if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: - nlp_res.solution_loader.load_vars() - else: - logger.warning('initialization was not successful via LP approximation') + nlp_res = _retry_nlp_solve(nlp, nlp_solver) return nlp_res @@ -253,18 +256,7 @@ def initialize_with_LP_approximation( finally: _cleanup(orig_var_data) - # solve the original problem from the initialized solution - nlp_res = nlp_solver.solve( - nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False - ) - logger.info( - f'solved NLP: {nlp_res.solution_status}, {nlp_res.termination_condition}' - ) - - if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: - nlp_res.solution_loader.load_vars() - else: - logger.warning('initialization was not successful via LP approximation') + nlp_res = _retry_nlp_solve(nlp, nlp_solver) return nlp_res @@ -320,15 +312,8 @@ def initialize_with_global_opt( finally: _cleanup(orig_var_data) - nlp_res = nlp_solver.solve( - nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False - ) - logger.info( - f'solved NLP with {nlp_solver.name}: {nlp_res.solution_status}, {nlp_res.termination_condition}' - ) - if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: - nlp_res.solution_loader.load_vars() - else: - logger.warning('initialization was not successful via global optimization') + nlp_res = _retry_nlp_solve(nlp, nlp_solver) return nlp_res + + From 3753f4b81923c46b3537d7897d0eee8030e26f07 Mon Sep 17 00:00:00 2001 From: Stephen Cini Date: Thu, 9 Jul 2026 13:18:44 -0600 Subject: [PATCH 08/10] Ran black --- pyomo/devel/initialization/initialize.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyomo/devel/initialization/initialize.py b/pyomo/devel/initialization/initialize.py index 6d449fa8e54..2fd4f5c145c 100644 --- a/pyomo/devel/initialization/initialize.py +++ b/pyomo/devel/initialization/initialize.py @@ -76,6 +76,7 @@ def _try_nlp_solve(nlp: BlockData, nlp_solver: SolverBase): logger.info('NLP solved without any initialization') return res + def _retry_nlp_solve(nlp: BlockData, nlp_solver: SolverBase): # retry to solve the original nlp after using an initialization method nlp_res = nlp_solver.solve( @@ -315,5 +316,3 @@ def initialize_with_global_opt( nlp_res = _retry_nlp_solve(nlp, nlp_solver) return nlp_res - - From 9dd6c48616a06b182de26e9e32c8e674828987b9 Mon Sep 17 00:00:00 2001 From: Stephen Cini Date: Thu, 9 Jul 2026 13:28:23 -0600 Subject: [PATCH 09/10] Moved string, Ran black --- pyomo/devel/initialization/initialize.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyomo/devel/initialization/initialize.py b/pyomo/devel/initialization/initialize.py index 2fd4f5c145c..58f8f9c0a97 100644 --- a/pyomo/devel/initialization/initialize.py +++ b/pyomo/devel/initialization/initialize.py @@ -82,9 +82,8 @@ def _retry_nlp_solve(nlp: BlockData, nlp_solver: SolverBase): nlp_res = nlp_solver.solve( nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False ) - logger.info( - f'solved NLP with {nlp_solver.name}: {nlp_res.solution_status}, {nlp_res.termination_condition}' - ) + logger.info(f'resolved NLP with {nlp_solver.name}: {nlp_res.solution_status}, \ + {nlp_res.termination_condition}') if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: nlp_res.solution_loader.load_vars() else: From 51ccb0361a94ab558b0ab28b3e3d6d39d30c7df0 Mon Sep 17 00:00:00 2001 From: Stephen Cini Date: Fri, 10 Jul 2026 08:42:56 -0600 Subject: [PATCH 10/10] All load_solutions=False with loading criteria, fixed typo. --- pyomo/devel/initialization/global_init.py | 4 +++- pyomo/devel/initialization/initialize.py | 2 +- pyomo/devel/initialization/lp_approx_init.py | 4 +++- pyomo/devel/initialization/pwl_init.py | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pyomo/devel/initialization/global_init.py b/pyomo/devel/initialization/global_init.py index 3f3ecb9fee0..25101b7d8d7 100644 --- a/pyomo/devel/initialization/global_init.py +++ b/pyomo/devel/initialization/global_init.py @@ -41,12 +41,14 @@ def _initialize_with_global_solver( res = global_solver.solve( nlp, - load_solutions=True, + load_solutions=False, raise_exception_on_nonoptimal_result=False, solver_options=opts, ) logger.info( f'solved NLP with {global_solver.name}: {res.solution_status}, {res.termination_condition}' ) + if res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: + res.solution_loader.load_vars() return res diff --git a/pyomo/devel/initialization/initialize.py b/pyomo/devel/initialization/initialize.py index 58f8f9c0a97..7dffe072a5e 100644 --- a/pyomo/devel/initialization/initialize.py +++ b/pyomo/devel/initialization/initialize.py @@ -82,7 +82,7 @@ def _retry_nlp_solve(nlp: BlockData, nlp_solver: SolverBase): nlp_res = nlp_solver.solve( nlp, load_solutions=False, raise_exception_on_nonoptimal_result=False ) - logger.info(f'resolved NLP with {nlp_solver.name}: {nlp_res.solution_status}, \ + logger.info(f're-solved NLP with {nlp_solver.name}: {nlp_res.solution_status}, \ {nlp_res.termination_condition}') if nlp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: nlp_res.solution_loader.load_vars() diff --git a/pyomo/devel/initialization/lp_approx_init.py b/pyomo/devel/initialization/lp_approx_init.py index d20c92c0203..4a334754687 100644 --- a/pyomo/devel/initialization/lp_approx_init.py +++ b/pyomo/devel/initialization/lp_approx_init.py @@ -214,8 +214,10 @@ def _initialize_with_LP_approximation( # solve the LP lp_res = lp_solver.solve( - lp, load_solutions=True, raise_exception_on_nonoptimal_result=False + lp, load_solutions=False, raise_exception_on_nonoptimal_result=False ) logger.info(f'solved LP: {lp_res.solution_status}, {lp_res.termination_condition}') + if lp_res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: + lp_res.solution_loader.load_vars() return lp_res diff --git a/pyomo/devel/initialization/pwl_init.py b/pyomo/devel/initialization/pwl_init.py index 94f2a19d5b5..a8c98afb8db 100644 --- a/pyomo/devel/initialization/pwl_init.py +++ b/pyomo/devel/initialization/pwl_init.py @@ -326,9 +326,11 @@ def _initialize_with_piecewise_linear_approximation( # solve the MILP res = mip_solver.solve( - _pwl, load_solutions=True, raise_exception_on_nonoptimal_result=False + _pwl, load_solutions=False, raise_exception_on_nonoptimal_result=False ) logger.info(f'solved MILP: {res.solution_status}, {res.termination_condition}') + if res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}: + res.solution_loader.load_vars() # load the variable values back into orig_vars for ov, nv in zip(orig_vars, new_vars):