diff --git a/src/core/definitions.jl b/src/core/definitions.jl index 142967f063..52af4c8103 100644 --- a/src/core/definitions.jl +++ b/src/core/definitions.jl @@ -61,6 +61,7 @@ const NO_SERVICE_NAME_PROVIDED = "" const CONTAINER_KEY_EMPTY_META = "" const UPPER_BOUND = "ub" const LOWER_BOUND = "lb" +const MAX_OPTIMIZE_TRIES = 2 # File Names definitions const PROBLEM_SERIALIZATION_FILENAME = "operation_problem.bin" diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 2953aac2ad..133a439595 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -671,17 +671,35 @@ function solve_impl!(container::OptimizationContainer, system::PSY.System) optimizer_stats = get_optimizer_stats(container) jump_model = get_jump_model(container) - _, - optimizer_stats.timed_solve_time, - optimizer_stats.solve_bytes_alloc, - optimizer_stats.sec_in_gc = @timed JuMP.optimize!(jump_model) - model_status = JuMP.primal_status(jump_model) - if model_status != MOI.FEASIBLE_POINT::MOI.ResultStatusCode - @error "Optimizer returned $model_status" - if get_calculate_conflict(get_settings(container)) - compute_conflict!(container) + + model_status = MOI.NO_SOLUTION::MOI.ResultStatusCode + conflict_status = MOI.COMPUTE_CONFLICT_NOT_CALLED + + try_count = 0 + while model_status != MOI.FEASIBLE_POINT::MOI.ResultStatusCode + _, + optimizer_stats.timed_solve_time, + optimizer_stats.solve_bytes_alloc, + optimizer_stats.sec_in_gc = @timed JuMP.optimize!(jump_model) + model_status = JuMP.primal_status(jump_model) + + if model_status != MOI.FEASIBLE_POINT::MOI.ResultStatusCode + if get_calculate_conflict(get_settings(container)) + @warn "Optimizer returned $model_status computing conflict" + conflict_status = compute_conflict!(container) + if conflict_status == MOI.CONFLICT_FOUND + return RunStatus.FAILED + end + else + @warn "Optimizer returned $model_status trying optimize! again" + end + + try_count += 1 + if try_count > MAX_OPTIMIZE_TRIES + @error "Optimizer returned $model_status after $MAX_OPTIMIZE_TRIES optimize! attempts" + return RunStatus.FAILED + end end - return RunStatus.FAILED end status = RunStatus.SUCCESSFUL @@ -699,13 +717,19 @@ end function compute_conflict!(container::OptimizationContainer) jump_model = get_jump_model(container) + settings = get_settings(container) JuMP.unset_silent(jump_model) jump_model.is_model_dirty = false conflict = container.infeasibility_conflict try JuMP.compute_conflict!(jump_model) - if MOI.get(jump_model, MOI.ConflictStatus()) != MOI.CONFLICT_FOUND - @error "No conflict could be found for the model. $(MOI.get(jump_model, MOI.ConflictStatus()))" + conflict_status = MOI.get(jump_model, MOI.ConflictStatus()) + if conflict_status != MOI.CONFLICT_FOUND + @error "No conflict could be found for the model. Status: $conflict_status" + if !get_optimizer_solve_log_print(settings) + JuMP.set_silent(jump_model) + end + return conflict_status end for (key, field_container) in get_constraints(container) @@ -718,6 +742,8 @@ function compute_conflict!(container::OptimizationContainer) end end @error "$(conflict)" + + return conflict_status catch e jump_model.is_model_dirty = true if isa(e, MethodError) @@ -727,7 +753,7 @@ function compute_conflict!(container::OptimizationContainer) end end - return + return MOI.NO_CONFLICT_EXISTS end function write_optimizer_stats!(container::OptimizationContainer) diff --git a/src/core/optimizer_stats.jl b/src/core/optimizer_stats.jl index 19475381c6..dfac5c3cce 100644 --- a/src/core/optimizer_stats.jl +++ b/src/core/optimizer_stats.jl @@ -10,6 +10,7 @@ mutable struct OptimizerStats has_duals::Bool # Candidate solution objective_bound::Union{Missing, Float64} + relative_gap::Union{Missing, Float64} # Use missing instead of nothing so that CSV writting doesn't fail dual_objective_value::Union{Missing, Float64} # Work counters @@ -37,6 +38,7 @@ function OptimizerStats() false, missing, missing, + missing, NaN, missing, missing, diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index a0cde57e3d..e5d61a2fea 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -473,7 +473,6 @@ function solve!( @info "\n$(RUN_OPERATION_MODEL_TIMER)\n" catch e @error "Decision Problem solve failed" exception = (e, catch_backtrace()) - # TODO: Run IIS here if the solve called failed set_run_status!(model, RunStatus.FAILED) end end diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index faa323ae6b..1ddd992f1b 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -88,6 +88,10 @@ function solve_impl!(model::OperationModel) settings = get_settings(model) model_name = get_name(model) ts = get_current_timestamp(model) + output_dir = get_output_dir(model) + infeasible_opt_path = joinpath(output_dir, "infeasible_$(model_name)_$(ts).json") + serialize_optimization_model(container, infeasible_opt_path) + @error("Infeasible Problem Serialized at $(infeasible_opt_path)") if !get_allow_fails(settings) error("Solving model $(model_name) failed at $(ts)") else diff --git a/src/utils/jump_utils.jl b/src/utils/jump_utils.jl index c3360c5da5..e610a91ae5 100644 --- a/src/utils/jump_utils.jl +++ b/src/utils/jump_utils.jl @@ -243,6 +243,7 @@ function _summary_to_dict!(optimizer_stats::OptimizerStats, jump_model::JuMP.Mod :objective_bound, # Union{Missing,Float64} :dual_objective_value, # Union{Missing,Float64} # Work counters + :relative_gap, # Union{Missing,Int} :barrier_iterations, # Union{Missing,Int} :simplex_iterations, # Union{Missing,Int} :node_count, # Union{Missing,Int}