From 962d9ef7f455d217f53b4511b34c8d906e089851 Mon Sep 17 00:00:00 2001 From: Jerry Potts Date: Thu, 31 Oct 2024 10:22:29 -0600 Subject: [PATCH] add some relevant model checks to test_utils from PSI --- test/runtests.jl | 1 + test/test_utils/model_checks.jl | 103 ++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 test/test_utils/model_checks.jl diff --git a/test/runtests.jl b/test/runtests.jl index d353f64..aae9f18 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -15,6 +15,7 @@ const PSINV = PowerSystemsInvestments const PSY = PowerSystems include("test_utils/test_data.jl") +include("test_utils/model_checks.jl") import Aqua Aqua.test_unbound_args(PowerSystemsInvestments) diff --git a/test/test_utils/model_checks.jl b/test/test_utils/model_checks.jl new file mode 100644 index 0000000..31aa9c7 --- /dev/null +++ b/test/test_utils/model_checks.jl @@ -0,0 +1,103 @@ +const GAEVF = JuMP.GenericAffExpr{Float64, VariableRef} +const GQEVF = JuMP.GenericQuadExpr{Float64, VariableRef} + +function moi_tests( + model::InvestmentModel, + vars::Int, + interval::Int, + lessthan::Int, + greaterthan::Int, + equalto::Int, + binary::Bool, +) + JuMPmodel = PSIN.get_jump_model(model) + @test JuMP.num_variables(JuMPmodel) == vars + @test JuMP.num_constraints(JuMPmodel, GAEVF, MOI.Interval{Float64}) == interval + @test JuMP.num_constraints(JuMPmodel, GAEVF, MOI.LessThan{Float64}) == lessthan + @test JuMP.num_constraints(JuMPmodel, GAEVF, MOI.GreaterThan{Float64}) == greaterthan + @test JuMP.num_constraints(JuMPmodel, GAEVF, MOI.EqualTo{Float64}) == equalto + @test ((JuMP.VariableRef, MOI.ZeroOne) in JuMP.list_of_constraint_types(JuMPmodel)) == + binary + + return +end + +function psin_constraint_test( + model::InvestmentModel, + constraint_keys::Vector{<:PSIN.ConstraintKey}, +) + constraints = PSIN.get_constraints(model) + for con in constraint_keys + if get(constraints, con, nothing) !== nothing + @test true + else + @error con + @test false + end + end + return +end + +function psin_checksolve_test(model::InvestmentModel, status, expected_result, tol = 0.0) + res = solve!(model) + model = PSIN.get_jump_model(model) + @test termination_status(model) in status + obj_value = JuMP.objective_value(model) + @test isapprox(obj_value, expected_result, atol = tol) +end + +function check_variable_unbounded( + model::InvestmentModel, + ::Type{T}, + ::Type{U}, +) where {T <: PSIN.VariableType, U <: PSIP.Technology} + return check_variable_unbounded(model::InvestmentModel, PSIN.VariableKey(T, U)) +end + +function check_variable_unbounded(model::InvestmentModel, var_key::PSIN.VariableKey) + psi_cont = PSIN.get_optimization_container(model) + variable = PSIN.get_variable(psi_cont, var_key) + for var in variable + if JuMP.has_lower_bound(var) || JuMP.has_upper_bound(var) + return false + end + end + return true +end + +function check_variable_bounded( + model::InvestmentModel, + ::Type{T}, + ::Type{U}, +) where {T <: PSIN.VariableType, U <: PSIP.Technology} + return check_variable_bounded(model, PSIN.VariableKey(T, U)) +end + +function check_variable_bounded(model::InvestmentModel, var_key::PSIN.VariableKey) + psi_cont = PSIN.get_optimization_container(model) + variable = PSIN.get_variable(psi_cont, var_key) + for var in variable + if !JuMP.has_lower_bound(var) || !JuMP.has_upper_bound(var) + return false + end + end + return true +end + +function check_flow_variable_values( + model::InvestmentModel, + ::Type{T}, + ::Type{U}, + device_name::String, + limit::Float64, +) where {T <: PSIN.VariableType, U <: PSIP.Technology} + psi_cont = PSIN.get_optimization_container(model) + variable = PSIN.get_variable(psi_cont, T(), U) + for var in variable[device_name, :] + if !(PSIN.jump_value(var) <= (limit + 1e-2)) + @error "$device_name out of bounds $(PSIN.jump_value(var))" + return false + end + end + return true +end \ No newline at end of file