diff --git a/src/PowerFlows.jl b/src/PowerFlows.jl index 5128900..eac152c 100644 --- a/src/PowerFlows.jl +++ b/src/PowerFlows.jl @@ -1,7 +1,7 @@ module PowerFlows export solve_powerflow -export solve_ac_powerflow! +export solve_powerflow! export PowerFlowData export DCPowerFlow export NLSolveACPowerFlow diff --git a/src/newton_ac_powerflow.jl b/src/newton_ac_powerflow.jl index 231e900..5a5f44b 100644 --- a/src/newton_ac_powerflow.jl +++ b/src/newton_ac_powerflow.jl @@ -30,32 +30,34 @@ solve_ac_powerflow!(sys) solve_ac_powerflow!(sys, method=:newton) ``` """ -function solve_ac_powerflow!( +function solve_powerflow!( pf::ACPowerFlow{<:ACPowerFlowSolverType}, system::PSY.System; - kwargs..., + kwargs... ) #Save per-unit flag settings_unit_cache = deepcopy(system.units_settings.unit_system) #Work in System per unit PSY.set_units_base_system!(system, "SYSTEM_BASE") - check_reactive_power_limits = get(kwargs, :check_reactive_power_limits, false) + data = PowerFlowData( pf, system; check_connectivity = get(kwargs, :check_connectivity, true), ) - max_iterations = DEFAULT_MAX_REDISTRIBUTION_ITERATIONS - converged, x = _solve_powerflow!(pf, data, check_reactive_power_limits; kwargs...) + + converged, x = _ac_powereflow(data, pf, system; kwargs...) + if converged - write_powerflow_solution!(system, x, max_iterations) + write_powerflow_solution!(system, x, get(kwargs, :maxIter, DEFAULT_NR_MAX_ITER)) @info("PowerFlow solve converged, the results have been stored in the system") - #Restore original per unit base - PSY.set_units_base_system!(system, settings_unit_cache) - return converged + else + @error("The powerflow solver returned convergence = $(converged)") end - @error("The powerflow solver returned convergence = $(converged)") + + #Restore original per unit base PSY.set_units_base_system!(system, settings_unit_cache) + return converged end @@ -74,33 +76,57 @@ res = solve_powerflow(sys, method=:newton) function solve_powerflow( pf::ACPowerFlow{<:ACPowerFlowSolverType}, system::PSY.System; - kwargs..., + kwargs... ) #Save per-unit flag settings_unit_cache = deepcopy(system.units_settings.unit_system) #Work in System per unit PSY.set_units_base_system!(system, "SYSTEM_BASE") + data = PowerFlowData( pf, system; check_connectivity = get(kwargs, :check_connectivity, true), ) + # @error(typeof(data)) - converged, x = _solve_powerflow!(pf, data, pf.check_reactive_power_limits; kwargs...) - + converged, x = _ac_powereflow(data, pf, system; kwargs...) + if converged @info("PowerFlow solve converged, the results are exported in DataFrames") df_results = write_results(pf, system, data, x) - #Restore original per unit base - PSY.set_units_base_system!(system, settings_unit_cache) - return df_results + else + df_results = missing + @error("The powerflow solver returned convergence = $(converged)") end - @error("The powerflow solver returned convergence = $(converged)") + + #Restore original per unit base PSY.set_units_base_system!(system, settings_unit_cache) - return converged + + return df_results end -function _check_q_limit_bounds!(data::ACPowerFlowData, zero::Vector{Float64}) + +function _ac_powereflow( + data::PowerFlowData, + pf::ACPowerFlow{<:ACPowerFlowSolverType}, + system::PSY.System; + kwargs... + ) + check_reactive_power_limits = get(kwargs, :check_reactive_power_limits, false) + + for _ in 1:MAX_REACTIVE_POWER_ITERATIONS + converged, x = _newton_powerflow(pf, data; kwargs...) + if !converged || !check_reactive_power_limits || _check_q_limit_bounds!(data, x) + return converged, x + end + end + + @error("could not enforce reactive power limits after $MAX_REACTIVE_POWER_ITERATIONS") + return converged, x +end + +function _check_q_limit_bounds!(data::PowerFlowData, zero::Vector{Float64}) bus_names = data.power_network_matrix.axes[1] within_limits = true for (ix, b) in enumerate(data.bus_type) @@ -133,20 +159,16 @@ function _solve_powerflow!( check_reactive_power_limits; nlsolve_kwargs..., ) - if check_reactive_power_limits - for _ in 1:MAX_REACTIVE_POWER_ITERATIONS - converged, x = _newton_powerflow(pf, data; nlsolve_kwargs...) - if converged - if _check_q_limit_bounds!(data, x) - return converged, x - end - else - return converged, x - end + + for _ in 1:MAX_REACTIVE_POWER_ITERATIONS + converged, x = _newton_powerflow(pf, data; nlsolve_kwargs...) + if !converged || !check_reactive_power_limits || _check_q_limit_bounds!(data, x) + return converged, x end - else - return _newton_powerflow(pf, data; nlsolve_kwargs...) end + # todo: throw error? set converged to false? + @error("could not enforce reactive power limits after $MAX_REACTIVE_POWER_ITERATIONS") + return converged, x end function _newton_powerflow( @@ -389,11 +411,11 @@ end function _newton_powerflow( pf::ACPowerFlow{KLUACPowerFlow}, data::ACPowerFlowData; - nlsolve_kwargs..., + kwargs..., ) # Fetch maxIter and tol from kwargs, or use defaults if not provided - maxIter = get(nlsolve_kwargs, :maxIter, DEFAULT_NR_MAX_ITER) - tol = get(nlsolve_kwargs, :tol, DEFAULT_NR_TOL) + maxIter = get(kwargs, :maxIter, DEFAULT_NR_MAX_ITER) + tol = get(kwargs, :tol, DEFAULT_NR_TOL) i = 0 Ybus = data.power_network_matrix.data @@ -568,11 +590,11 @@ end function _newton_powerflow( pf::ACPowerFlow{LUACPowerFlow}, data::ACPowerFlowData; - nlsolve_kwargs..., + kwargs..., ) # Fetch maxIter and tol from kwargs, or use defaults if not provided - maxIter = get(nlsolve_kwargs, :maxIter, DEFAULT_NR_MAX_ITER) - tol = get(nlsolve_kwargs, :tol, DEFAULT_NR_TOL) + maxIter = get(kwargs, :maxIter, DEFAULT_NR_MAX_ITER) + tol = get(kwargs, :tol, DEFAULT_NR_TOL) i = 0 Ybus = data.power_network_matrix.data diff --git a/test/test_newton_ac_powerflow.jl b/test/test_newton_ac_powerflow.jl index 4564a29..dbc4912 100644 --- a/test/test_newton_ac_powerflow.jl +++ b/test/test_newton_ac_powerflow.jl @@ -41,7 +41,7 @@ #Compare results between finite diff methods and Jacobian method converged1, x1 = PowerFlows._solve_powerflow!(pf, data, false) @test LinearAlgebra.norm(result_14 - x1, Inf) <= 1e-6 - @test solve_ac_powerflow!(pf, sys; method = :newton) + @test solve_powerflow!(pf, sys; method = :newton) # Test enforcing the reactive power Limits set_reactive_power!(get_component(PowerLoad, sys, "Bus4"), 0.0) @@ -63,7 +63,7 @@ end branch = first(PSY.get_components(Line, sys)) dyn_branch = DynamicBranch(branch) add_component!(sys, dyn_branch) - @test dyn_pf = solve_ac_powerflow!(pf, sys) + @test dyn_pf = solve_powerflow!(pf, sys) dyn_pf = solve_powerflow(pf, sys) @test LinearAlgebra.norm(dyn_pf["bus_results"].Vm - base_res["bus_results"].Vm, Inf) <= 1e-6 @@ -71,7 +71,7 @@ end sys = PSB.build_system(PSB.PSITestSystems, "c_sys14"; add_forecasts = false) line = get_component(Line, sys, "Line4") PSY.set_available!(line, false) - solve_ac_powerflow!(pf, sys) + solve_powerflow!(pf, sys) @test PSY.get_active_power_flow(line) == 0.0 test_bus = get_component(PSY.Bus, sys, "Bus 4") @test isapprox(PSY.get_magnitude(test_bus), 1.002; atol = 1e-3, rtol = 0) @@ -119,7 +119,7 @@ end @test_logs( (:error, "The powerflow solver returned convergence = false"), match_mode = :any, - @test !solve_ac_powerflow!(pf, pf_sys5_re) + @test !solve_powerflow!(pf, pf_sys5_re) ) end @@ -145,7 +145,7 @@ end pf = ACPowerFlow{ACSolver}() - pf1 = solve_ac_powerflow!(pf, system) + pf1 = solve_powerflow!(pf, system) @test pf1 pf_result_df = solve_powerflow(pf, system) @@ -203,13 +203,13 @@ end ) add_component!(sys, s2) pf = ACPowerFlow{ACSolver}() - @test solve_ac_powerflow!(pf, sys) + @test solve_powerflow!(pf, sys) #Create power mismatch, test for error set_active_power!(get_component(Source, sys, "source_1"), -0.4) @test_throws ErrorException( "Sources do not match P and/or Q requirements for reference bus.", - ) solve_ac_powerflow!(pf, sys) + ) solve_powerflow!(pf, sys) end @testset "AC PowerFlow with Multiple sources at PV" for ACSolver in @@ -289,11 +289,11 @@ end pf = ACPowerFlow{ACSolver}() - @test solve_ac_powerflow!(pf, sys) + @test solve_powerflow!(pf, sys) #Create power mismatch, test for error set_reactive_power!(get_component(Source, sys, "source_3"), -0.5) - @test_throws ErrorException("Sources do not match Q requirements for PV bus.") solve_ac_powerflow!( + @test_throws ErrorException("Sources do not match Q requirements for PV bus.") solve_powerflow!( pf, sys, ) @@ -352,7 +352,7 @@ end pf = ACPowerFlow{ACSolver}() - @test solve_ac_powerflow!(pf, sys) + @test solve_powerflow!(pf, sys) @test isapprox( get_active_power(get_component(Source, sys, "source_1")), 0.5; @@ -453,7 +453,7 @@ end pf = ACPowerFlow{ACSolver}() - @test solve_ac_powerflow!(pf, sys) + @test solve_powerflow!(pf, sys) @test isapprox( get_active_power(get_component(Source, sys, "source_2")), 0.5; diff --git a/test/test_utils/psse_results_compare.jl b/test/test_utils/psse_results_compare.jl index 3d35e7c..dfe162b 100644 --- a/test/test_utils/psse_results_compare.jl +++ b/test/test_utils/psse_results_compare.jl @@ -15,8 +15,8 @@ function psse_bus_results_compare(file_name::String, pf_results::Dict) return v_diff, angle_diff, number end -function psse_bus_results_compare(file_name::String, pf_results::Bool) - throw(ArgumentError("pf_results not available - calculation failed")) +function psse_bus_results_compare(file_name::String, pf_results::Missing) + throw(ArgumentError("pf_results are missing - calculation failed")) end function psse_gen_results_compare(file_name, system::PSY.System)