From e7fc06118ee57415764470e9d5f657d52821fd69 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Fri, 29 Mar 2024 18:56:39 -0400 Subject: [PATCH 01/76] pass parameters (tests pass) --- src/PowerSimulationsDynamics.jl | 1 + src/base/branch_wrapper.jl | 4 + src/base/definitions.jl | 8 + src/base/device_wrapper.jl | 274 +++-- src/base/jacobian.jl | 17 +- src/base/nlsolve_wrapper.jl | 19 +- src/base/perturbations.jl | 106 +- src/base/simulation.jl | 19 +- src/base/simulation_initialization.jl | 35 +- src/base/simulation_inputs.jl | 158 ++- src/base/simulation_results.jl | 8 +- src/base/small_signal.jl | 43 +- .../generator_components/init_avr.jl | 149 +-- .../generator_components/init_machine.jl | 154 +-- .../generator_components/init_pss.jl | 10 +- .../generator_components/init_shaft.jl | 38 +- .../generator_components/init_tg.jl | 108 +- src/initialization/init_device.jl | 280 ++--- .../inverter_components/init_DCside.jl | 6 +- .../inverter_components/init_converter.jl | 27 +- .../inverter_components/init_filter.jl | 33 +- .../init_frequency_estimator.jl | 19 +- .../inverter_components/init_inner.jl | 53 +- .../inverter_components/init_outer.jl | 109 +- src/models/branch.jl | 4 + src/models/device.jl | 552 ++++++---- src/models/dynline_model.jl | 5 +- src/models/generator_models/avr_models.jl | 164 +-- src/models/generator_models/machine_models.jl | 160 +-- src/models/generator_models/pss_models.jl | 30 +- src/models/generator_models/shaft_models.jl | 47 +- src/models/generator_models/tg_models.jl | 111 +- src/models/inverter_models/DCside_models.jl | 6 +- .../inverter_models/converter_models.jl | 37 +- src/models/inverter_models/filter_models.jl | 18 +- .../frequency_estimator_models.jl | 17 +- .../inverter_models/inner_control_models.jl | 72 +- .../inverter_models/outer_control_models.jl | 354 +++++-- src/models/load_models.jl | 12 +- src/models/source_models.jl | 9 +- src/models/system.jl | 60 +- src/utils/parameters.jl | 967 ++++++++++++++++++ test/test_base.jl | 17 +- test/test_case22_SteamTurbineGov1.jl | 4 +- test/utils/mock_structs.jl | 2 +- 45 files changed, 2982 insertions(+), 1344 deletions(-) create mode 100644 src/utils/parameters.jl diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index b87c0b8b6..369e6ab12 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -184,5 +184,6 @@ include("utils/immutable_dicts.jl") include("utils/print.jl") include("utils/kwargs_check.jl") include("utils/logging.jl") +include("utils/parameters.jl") end # module diff --git a/src/base/branch_wrapper.jl b/src/base/branch_wrapper.jl index 9b96d733f..41f131831 100644 --- a/src/base/branch_wrapper.jl +++ b/src/base/branch_wrapper.jl @@ -11,6 +11,7 @@ struct BranchWrapper bus_ix_to::Int ix_range::Vector{Int} ode_range::Vector{Int} + p_range::Vector{Int} global_index::Base.ImmutableDict{Symbol, Int} function BranchWrapper( branch::PSY.DynamicBranch, @@ -18,6 +19,7 @@ struct BranchWrapper bus_ix_to::Int, ix_range, ode_range, + p_range, sys_base_power, sys_base_freq, ) @@ -31,6 +33,7 @@ struct BranchWrapper bus_ix_to, ix_range, ode_range, + p_range, Base.ImmutableDict(Dict(branch_states .=> ix_range)...), ) end @@ -41,6 +44,7 @@ get_bus_ix_from(wrapper::BranchWrapper) = wrapper.bus_ix_from get_bus_ix_to(wrapper::BranchWrapper) = wrapper.bus_ix_to get_ix_range(wrapper::BranchWrapper) = wrapper.ix_range get_ode_ouput_range(wrapper::BranchWrapper) = wrapper.ode_range +get_p_range(wrapper::BranchWrapper) = wrapper.p_range get_global_index(wrapper::BranchWrapper) = wrapper.global_index get_branch(wrapper::BranchWrapper) = wrapper.branch diff --git a/src/base/definitions.jl b/src/base/definitions.jl index c9aa22a60..869dd0edb 100644 --- a/src/base/definitions.jl +++ b/src/base/definitions.jl @@ -101,6 +101,14 @@ end Base.to_index(ix::dq_ref) = Int(ix) Base.to_index(ix::RI_ref) = Int(ix) +@enum ref_ix begin + Q_ref_ix = 1 + V_ref_ix = 2 + ω_ref_ix = 3 + P_ref_ix = 4 +end +Base.to_index(ix::ref_ix) = Int(ix) + const MAPPING_DICT = Dict{String, OrderedDict{Symbol, Int}} const DEVICE_INTERNAL_MAPPING = Base.ImmutableDict{Int, Vector{Int}} diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index 7ef0c79a6..b000bb25d 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -22,67 +22,61 @@ index(::Type{<:PSY.Filter}) = 6 """ Wraps DynamicInjection devices from PowerSystems to handle changes in controls and connection -status, and allocate the required indexes of the state space. +status, and allocate the required indexes of the state space and parameter space. """ struct DynamicWrapper{T <: PSY.DynamicInjection} - device::T + dynamic_device::T + static_device::PSY.StaticInjection system_base_power::Float64 system_base_frequency::Float64 - static_type::Type{<:PSY.StaticInjection} bus_category::Type{<:BusCategory} connection_status::Base.RefValue{Float64} - V_ref::Base.RefValue{Float64} - ω_ref::Base.RefValue{Float64} - P_ref::Base.RefValue{Float64} - Q_ref::Base.RefValue{Float64} inner_vars_index::Vector{Int} ix_range::Vector{Int} ode_range::Vector{Int} + p_range::Vector{Int} bus_ix::Int global_index::Base.ImmutableDict{Symbol, Int} component_state_mapping::Base.ImmutableDict{Int, Vector{Int}} + component_parameter_mapping::Base.ImmutableDict{Int, Vector{Int}} input_port_mapping::Base.ImmutableDict{Int, Vector{Int}} ext::Dict{String, Any} function DynamicWrapper( - device::T, + dynamic_device::T, + static_device::V, system_base_power::Float64, system_base_frequency::Float64, - static_type::Type{<:PSY.StaticInjection}, bus_category::Type{<:BusCategory}, connection_status::Base.RefValue{Float64}, - V_ref::Base.RefValue{Float64}, - ω_ref::Base.RefValue{Float64}, - P_ref::Base.RefValue{Float64}, - Q_ref::Base.RefValue{Float64}, inner_vars_index, ix_range, ode_range, + p_range, bus_ix::Int, global_index::Base.ImmutableDict{Symbol, Int}, component_state_mapping::Base.ImmutableDict{Int, Vector{Int}}, + component_parameter_mapping::Base.ImmutableDict{Int, Vector{Int}}, input_port_mapping::Base.ImmutableDict{Int, Vector{Int}}, ext::Dict{String, Any}, - ) where {T <: PSY.DynamicInjection} - is_valid(device) + ) where {V <: PSY.StaticInjection, T <: PSY.DynamicInjection} + is_valid(dynamic_device) new{T}( - device, + dynamic_device, + static_device, system_base_power, system_base_frequency, - static_type, bus_category, connection_status, - V_ref, - ω_ref, - P_ref, - Q_ref, Vector{Int}(inner_vars_index), Vector{Int}(ix_range), Vector{Int}(ode_range), + Vector{Int}(p_range), bus_ix, global_index, component_state_mapping, + component_parameter_mapping, input_port_mapping, ext, ) @@ -109,42 +103,72 @@ function state_port_mappings(dynamic_device::PSY.DynamicInjection, device_states return (component_state_mapping, input_port_mapping) end +function parameter_mappings( + dynamic_device::T, + device_parameters, +) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} + component_parameter_mapping = Dict{Int, Vector{Int}}() + for c in PSY.get_dynamic_components(dynamic_device) + ix = index(typeof(c)) + component_parameter_mapping[ix] = _index_local_parameters(c, device_parameters) + end + return component_parameter_mapping +end + +function parameter_mappings(dynamic_device::PSY.DynamicInjection, device_parameters) + return Dict{Int, Vector{Int}}() +end + +function _get_parameter_symbols( + dynamic_device::PSY.DynamicInjection, + static_device::PSY.StaticInjection, +) + return get_params_symbol(dynamic_device) +end + +function _get_parameter_symbols( + dynamic_device::T, + static_device::PSY.StaticInjection, +) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} + return vcat(get_params_symbol(static_device), get_params_symbol(dynamic_device)) +end + function DynamicWrapper( - device::T, + static_device::T, dynamic_device::D, bus_ix::Int, ix_range, ode_range, + p_range, inner_var_range, sys_base_power, sys_base_freq, ) where {T <: PSY.StaticInjection, D <: PSY.DynamicInjection} device_states = PSY.get_states(dynamic_device) + device_parameters = _get_parameter_symbols(dynamic_device, static_device) + @assert allunique(device_parameters) #mapping depends on unique parameters per device component_state_mapping, input_port_mapping = state_port_mappings(dynamic_device, device_states) - + component_parameter_mapping = parameter_mappings(dynamic_device, device_parameters) # Consider the special case when the static device is StandardLoad - if isa(device, PSY.StandardLoad) - reactive_power = PF.get_total_q(device) + if isa(static_device, PSY.StandardLoad) + reactive_power = PF.get_total_q(static_device) else - reactive_power = PSY.get_reactive_power(device) + reactive_power = PSY.get_reactive_power(static_device) end return DynamicWrapper( dynamic_device, + static_device, sys_base_power, sys_base_freq, - T, - BUS_MAP[PSY.get_bustype(PSY.get_bus(device))], + BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), - Base.Ref(PSY.get_V_ref(dynamic_device)), - Base.Ref(PSY.get_ω_ref(dynamic_device)), - Base.Ref(PSY.get_P_ref(dynamic_device)), - Base.Ref(reactive_power), inner_var_range, ix_range, ode_range, + p_range, bus_ix, Base.ImmutableDict( sort!(device_states .=> ix_range; by = x -> x.second, rev = true)..., @@ -154,6 +178,11 @@ function DynamicWrapper( else Base.ImmutableDict(component_state_mapping...) end, + if isempty(component_parameter_mapping) + Base.ImmutableDict{Int, Vector{Int}}() + else + Base.ImmutableDict(component_parameter_mapping...) + end, if isempty(input_port_mapping) Base.ImmutableDict{Int, Vector{Int}}() else @@ -164,11 +193,12 @@ function DynamicWrapper( end function DynamicWrapper( - device::PSY.ThermalStandard, + static_device::PSY.ThermalStandard, dynamic_device::PSY.AggregateDistributedGenerationA, bus_ix::Int, ix_range, ode_range, + p_range, inner_var_range, sys_base_power, sys_base_freq, @@ -181,18 +211,15 @@ function DynamicWrapper( return DynamicWrapper( dynamic_device, + static_device, sys_base_power, sys_base_freq, - PSY.ThermalStandard, - BUS_MAP[PSY.get_bustype(PSY.get_bus(device))], + BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), - Base.Ref(PSY.get_V_ref(dynamic_device)), - Base.Ref(PSY.get_ω_ref(dynamic_device)), - Base.Ref(PSY.get_P_ref(dynamic_device)), - Base.Ref(PSY.get_reactive_power(device)), inner_var_range, ix_range, ode_range, + p_range, bus_ix, Base.ImmutableDict( sort!(device_states .=> ix_range; by = x -> x.second, rev = true)..., @@ -202,6 +229,7 @@ function DynamicWrapper( else Base.ImmutableDict(component_state_mapping...) end, + Base.ImmutableDict{Int, Vector{Int}}(), if isempty(input_port_mapping) Base.ImmutableDict{Int, Vector{Int}}() else @@ -212,41 +240,52 @@ function DynamicWrapper( end function DynamicWrapper( - device::PSY.Source, + static_device::PSY.Source, dynamic_device::D, bus_ix::Int, ix_range, ode_range, + p_range, inner_var_range, sys_base_power, sys_base_freq, ) where {D <: PSY.DynamicInjection} device_states = PSY.get_states(dynamic_device) - IS.@assert_op PSY.get_X_th(dynamic_device) == PSY.get_X_th(device) - IS.@assert_op PSY.get_R_th(dynamic_device) == PSY.get_R_th(device) + IS.@assert_op PSY.get_X_th(dynamic_device) == PSY.get_X_th(static_device) + IS.@assert_op PSY.get_R_th(dynamic_device) == PSY.get_R_th(static_device) return DynamicWrapper( dynamic_device, + static_device, sys_base_power, sys_base_freq, - PSY.Source, - BUS_MAP[PSY.get_bustype(PSY.get_bus(device))], + BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), - Base.Ref(0.0), - Base.Ref(0.0), - Base.Ref(0.0), - Base.Ref(0.0), collect(inner_var_range), collect(ix_range), collect(ode_range), + collect(p_range), bus_ix, Base.ImmutableDict(Dict(device_states .=> ix_range)...), Base.ImmutableDict{Int, Vector{Int}}(), Base.ImmutableDict{Int, Vector{Int}}(), + Base.ImmutableDict{Int, Vector{Int}}(), Dict{String, Any}(), ) end +function _index_local_parameters( + component::PSY.DynamicComponent, + device_parameters::Vector{Symbol}, +) + component_paramter_index = Vector{Int}(undef, get_n_params(component)) + component_parameters = get_params_symbol(component) + for (ix, s) in enumerate(component_parameters) + component_paramter_index[ix] = findfirst(x -> x == s, device_parameters) + end + return component_paramter_index +end + function _index_local_states(component::PSY.DynamicComponent, device_states::Vector{Symbol}) component_state_index = Vector{Int}(undef, PSY.get_n_states(component)) component_states = PSY.get_states(component) @@ -270,61 +309,55 @@ function _index_port_mapping!( return index_component_inputs end -get_device(wrapper::DynamicWrapper) = wrapper.device +get_dynamic_device(wrapper::DynamicWrapper) = wrapper.dynamic_device +get_static_device(wrapper::DynamicWrapper) = wrapper.static_device get_device_type(::DynamicWrapper{T}) where {T <: PSY.DynamicInjection} = T get_bus_category(wrapper::DynamicWrapper) = wrapper.bus_category get_inner_vars_index(wrapper::DynamicWrapper) = wrapper.inner_vars_index get_ix_range(wrapper::DynamicWrapper) = wrapper.ix_range get_ode_ouput_range(wrapper::DynamicWrapper) = wrapper.ode_range +get_p_range(wrapper::DynamicWrapper) = wrapper.p_range get_bus_ix(wrapper::DynamicWrapper) = wrapper.bus_ix get_global_index(wrapper::DynamicWrapper) = wrapper.global_index get_component_state_mapping(wrapper::DynamicWrapper) = wrapper.component_state_mapping +get_component_parameter_mapping(wrapper::DynamicWrapper) = + wrapper.component_parameter_mapping get_input_port_mapping(wrapper::DynamicWrapper) = wrapper.input_port_mapping get_ext(wrapper::DynamicWrapper) = wrapper.ext get_system_base_power(wrapper::DynamicWrapper) = wrapper.system_base_power get_system_base_frequency(wrapper::DynamicWrapper) = wrapper.system_base_frequency -get_P_ref(wrapper::DynamicWrapper) = wrapper.P_ref[] -get_Q_ref(wrapper::DynamicWrapper) = wrapper.Q_ref[] -get_V_ref(wrapper::DynamicWrapper) = wrapper.V_ref[] -get_ω_ref(wrapper::DynamicWrapper) = wrapper.ω_ref[] - -set_P_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.P_ref[] = val -set_Q_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.Q_ref[] = val -set_V_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.V_ref[] = val -set_ω_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.ω_ref[] = val - # PSY overloads for the wrapper -PSY.get_name(wrapper::DynamicWrapper) = PSY.get_name(wrapper.device) -PSY.get_ext(wrapper::DynamicWrapper) = PSY.get_ext(wrapper.device) -PSY.get_states(wrapper::DynamicWrapper) = PSY.get_states(wrapper.device) -PSY.get_n_states(wrapper::DynamicWrapper) = PSY.get_n_states(wrapper.device) -PSY.get_base_power(wrapper::DynamicWrapper) = PSY.get_base_power(wrapper.device) +PSY.get_name(wrapper::DynamicWrapper) = PSY.get_name(wrapper.dynamic_device) +PSY.get_ext(wrapper::DynamicWrapper) = PSY.get_ext(wrapper.dynamic_device) +PSY.get_states(wrapper::DynamicWrapper) = PSY.get_states(wrapper.dynamic_device) +PSY.get_n_states(wrapper::DynamicWrapper) = PSY.get_n_states(wrapper.dynamic_device) +PSY.get_base_power(wrapper::DynamicWrapper) = PSY.get_base_power(wrapper.dynamic_device) PSY.get_machine(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} = - wrapper.device.machine + wrapper.dynamic_device.machine PSY.get_shaft(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} = - wrapper.device.shaft + wrapper.dynamic_device.shaft PSY.get_avr(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} = - wrapper.device.avr + wrapper.dynamic_device.avr PSY.get_prime_mover(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} = - wrapper.device.prime_mover + wrapper.dynamic_device.prime_mover PSY.get_pss(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} = - wrapper.device.pss + wrapper.dynamic_device.pss PSY.get_converter(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.device.converter + wrapper.dynamic_device.converter PSY.get_outer_control(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.device.outer_control + wrapper.dynamic_device.outer_control PSY.get_inner_control(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.device.inner_control + wrapper.dynamic_device.inner_control PSY.get_dc_source(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.device.dc_source + wrapper.dynamic_device.dc_source PSY.get_freq_estimator(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.device.freq_estimator + wrapper.dynamic_device.freq_estimator PSY.get_filter(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.device.filter + wrapper.dynamic_device.filter # PSY overloads of specific Dynamic Injectors @@ -342,6 +375,13 @@ function get_local_state_ix( return wrapper.component_state_mapping[index(T)] end +function get_local_parameter_ix( + wrapper::DynamicWrapper, + ::Type{T}, +) where {T <: PSY.DynamicComponent} + return wrapper.component_parameter_mapping[index(T)] +end + function get_input_port_ix( wrapper::DynamicWrapper, ::Type{T}, @@ -360,10 +400,7 @@ end struct StaticWrapper{T <: PSY.StaticInjection, V} device::T connection_status::Base.RefValue{Float64} - V_ref::Base.RefValue{Float64} - θ_ref::Base.RefValue{Float64} - P_ref::Base.RefValue{Float64} - Q_ref::Base.RefValue{Float64} + p_range::Vector{Int} bus_ix::Int ext::Dict{String, Any} end @@ -373,24 +410,18 @@ function DynamicWrapper(device::T, bus_ix::Int) where {T <: PSY.Device} StaticWrapper{T, BUS_MAP[PSY.get_bustype(bus)]}( device, Base.Ref(1.0), - Base.Ref(PSY.get_magnitude(bus)), - Base.Ref(PSY.get_angle(bus)), - Base.Ref(PSY.get_active_power(device)), - Base.Ref(PSY.get_reactive_power(device)), + Vector{Int}(), bus_ix, Dict{String, Any}(), ) end -function StaticWrapper(device::T, bus_ix::Int) where {T <: PSY.Source} +function StaticWrapper(device::T, bus_ix::Int, p_range) where {T <: PSY.Source} bus = PSY.get_bus(device) return StaticWrapper{T, BUS_MAP[PSY.get_bustype(bus)]}( device, Base.Ref(1.0), - Base.Ref(PSY.get_internal_voltage(device)), - Base.Ref(PSY.get_internal_angle(device)), - Base.Ref(PSY.get_active_power(device)), - Base.Ref(PSY.get_reactive_power(device)), + p_range, bus_ix, Dict{String, Any}(), ) @@ -401,19 +432,10 @@ get_bus_category(::StaticWrapper{<:PSY.StaticInjection, U}) where {U} = U # TODO: something smart to forward fields get_device(wrapper::StaticWrapper) = wrapper.device +get_p_range(wrapper::StaticWrapper) = wrapper.p_range get_bus_ix(wrapper::StaticWrapper) = wrapper.bus_ix get_ext(wrapper::StaticWrapper) = wrapper.ext -get_P_ref(wrapper::StaticWrapper) = wrapper.P_ref[] -get_Q_ref(wrapper::StaticWrapper) = wrapper.Q_ref[] -get_V_ref(wrapper::StaticWrapper) = wrapper.V_ref[] -get_θ_ref(wrapper::StaticWrapper) = wrapper.θ_ref[] - -set_P_ref(wrapper::StaticWrapper, val::Float64) = wrapper.P_ref[] = val -set_Q_ref(wrapper::StaticWrapper, val::Float64) = wrapper.Q_ref[] = val -set_V_ref(wrapper::StaticWrapper, val::Float64) = wrapper.V_ref[] = val -set_θ_ref(wrapper::StaticWrapper, val::Float64) = wrapper.θ_ref[] = val - PSY.get_bus(wrapper::StaticWrapper) = PSY.get_bus(wrapper.device) PSY.get_active_power(wrapper::StaticWrapper) = PSY.get_active_power(wrapper.device) PSY.get_reactive_power(wrapper::StaticWrapper) = PSY.get_reactive_power(wrapper.device) @@ -428,48 +450,22 @@ mutable struct ExpLoadParams end mutable struct StaticLoadWrapper + loads::Vector{PSY.ElectricLoad} bus::PSY.Bus - V_ref::Float64 - θ_ref::Float64 - P_power::Float64 - P_current::Float64 - P_impedance::Float64 - Q_power::Float64 - Q_current::Float64 - Q_impedance::Float64 exp_params::Vector{ExpLoadParams} exp_names::Dict{String, Int} + p_range::Vector{Int} bus_ix::Int + system_base_power::Float64 end function StaticLoadWrapper( bus::PSY.Bus, loads::Vector{PSY.ElectricLoad}, + p_range, bus_ix::Int, sys_base_power::Float64, ) - P_power = 0.0 - P_current = 0.0 - P_impedance = 0.0 - Q_power = 0.0 - Q_current = 0.0 - Q_impedance = 0.0 - - # Add ZIP Loads - for ld in loads - base_power_conversion = PSY.get_base_power(ld) / sys_base_power - if isa(ld, PSY.PowerLoad) - P_power += PSY.get_active_power(ld) * base_power_conversion - Q_power += PSY.get_reactive_power(ld) * base_power_conversion - elseif isa(ld, PSY.StandardLoad) - P_impedance += PSY.get_impedance_active_power(ld) * base_power_conversion - Q_impedance += PSY.get_impedance_reactive_power(ld) * base_power_conversion - P_current += PSY.get_current_active_power(ld) * base_power_conversion - Q_current += PSY.get_current_reactive_power(ld) * base_power_conversion - P_power += PSY.get_constant_active_power(ld) * base_power_conversion - Q_power += PSY.get_constant_reactive_power(ld) * base_power_conversion - end - end # Add Exponential Loads exp_loads = filter(x -> isa(x, PSY.ExponentialLoad) && PSY.get_available(x), loads) @@ -489,35 +485,25 @@ function StaticLoadWrapper( end return StaticLoadWrapper( + loads, bus, - PSY.get_magnitude(bus), - PSY.get_angle(bus), - P_power, - P_current, - P_impedance, - Q_power, - Q_current, - Q_impedance, exp_params, dict_names, + p_range, bus_ix, + sys_base_power, ) end PSY.get_bus(wrapper::StaticLoadWrapper) = wrapper.bus PSY.get_name(wrapper::StaticLoadWrapper) = PSY.get_name(wrapper.bus) -get_V_ref(wrapper::StaticLoadWrapper) = wrapper.V_ref -get_θ_ref(wrapper::StaticLoadWrapper) = wrapper.θ_ref -get_P_power(wrapper::StaticLoadWrapper) = wrapper.P_power -get_P_current(wrapper::StaticLoadWrapper) = wrapper.P_current -get_P_impedance(wrapper::StaticLoadWrapper) = wrapper.P_impedance -get_Q_power(wrapper::StaticLoadWrapper) = wrapper.Q_power -get_Q_current(wrapper::StaticLoadWrapper) = wrapper.Q_current -get_Q_impedance(wrapper::StaticLoadWrapper) = wrapper.Q_impedance +get_loads(wrapper::StaticLoadWrapper) = wrapper.loads +get_p_range(wrapper::StaticLoadWrapper) = wrapper.p_range get_exp_params(wrapper::StaticLoadWrapper) = wrapper.exp_params get_exp_names(wrapper::StaticLoadWrapper) = wrapper.exp_names get_bus_ix(wrapper::StaticLoadWrapper) = wrapper.bus_ix +get_system_base_power(wrapper::StaticLoadWrapper) = wrapper.system_base_power set_V_ref!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.V_ref = val set_θ_ref!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.θ_ref = val diff --git a/src/base/jacobian.jl b/src/base/jacobian.jl index 65fd020f3..b8a32a61d 100644 --- a/src/base/jacobian.jl +++ b/src/base/jacobian.jl @@ -54,13 +54,14 @@ end function JacobianFunctionWrapper( m!::SystemModel{MassMatrixModel}, - x0_guess::Vector{Float64}; + x0_guess::Vector{Float64}, + p::Vector{Float64}; # Improve the heuristic to do sparsity detection sparse_retrieve_loop::Int = 0, #max(3, length(x0_guess) ÷ 100), ) x0 = deepcopy(x0_guess) n = length(x0) - m_ = (residual, x) -> m!(residual, x, nothing, 0.0) + m_ = (residual, x) -> m!(residual, x, p, 0.0) jconfig = ForwardDiff.JacobianConfig(m_, similar(x0), x0, ForwardDiff.Chunk(x0)) Jf = (Jv, x) -> begin @debug "Evaluating Jacobian Function" @@ -89,12 +90,13 @@ end function JacobianFunctionWrapper( m!::SystemModel{ResidualModel}, - x0::Vector{Float64}; + x0::Vector{Float64}, + p::Vector{Float64}; # Improve the heuristic to do sparsity detection sparse_retrieve_loop::Int = max(3, length(x0) ÷ 100), ) n = length(x0) - m_ = (residual, x) -> m!(residual, zeros(n), x, nothing, 0.0) + m_ = (residual, x) -> m!(residual, zeros(n), x, p, 0.0) jconfig = ForwardDiff.JacobianConfig(m_, similar(x0), x0, ForwardDiff.Chunk(x0)) Jf = (Jv, x) -> begin @debug "Evaluating Jacobian Function" @@ -126,11 +128,13 @@ function get_jacobian( ::Type{T}, inputs::SimulationInputs, x0_init::Vector{Float64}, + p::Vector{Float64}, sparse_retrieve_loop::Int, ) where {T <: SimulationModel} return JacobianFunctionWrapper( T(inputs, x0_init, JacobianCache), - x0_init; + x0_init, + p; sparse_retrieve_loop = sparse_retrieve_loop, ) end @@ -157,7 +161,8 @@ function get_jacobian( # Deepcopy avoid system modifications simulation_system = deepcopy(system) inputs = SimulationInputs(T, simulation_system, ReferenceBus()) + p = get_parameters(inputs) x0_init = get_flat_start(inputs) set_operating_point!(x0_init, inputs, system) - return get_jacobian(T, inputs, x0_init, sparse_retrieve_loop) + return get_jacobian(T, inputs, x0_init, p, sparse_retrieve_loop) end diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index 13e4ec0b3..8115cf892 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -8,13 +8,21 @@ NLsolveWrapper() = NLsolveWrapper(Vector{Float64}(), false, true) converged(sol::NLsolveWrapper) = sol.converged failed(sol::NLsolveWrapper) = sol.failed -function _get_model_closure(model::SystemModel{MassMatrixModel}, ::Vector{Float64}) - return (residual, x) -> model(residual, x, nothing, 0.0) +function _get_model_closure( + model::SystemModel{MassMatrixModel}, + ::Vector{Float64}, + p::Vector{Float64}, +) + return (residual, x) -> model(residual, x, p, 0.0) end -function _get_model_closure(model::SystemModel{ResidualModel}, x0::Vector{Float64}) +function _get_model_closure( + model::SystemModel{ResidualModel}, + x0::Vector{Float64}, + p::Vector{Float64}, +) dx0 = zeros(length(x0)) - return (residual, x) -> model(residual, dx0, x, nothing, 0.0) + return (residual, x) -> model(residual, dx0, x, p, 0.0) end function _nlsolve_call( @@ -143,9 +151,10 @@ function refine_initial_condition!( converged = false initial_guess = get_initial_conditions(sim) inputs = get_simulation_inputs(sim) + parameters = get_parameters(inputs) bus_range = get_bus_range(inputs) powerflow_solution = deepcopy(initial_guess[bus_range]) - f! = _get_model_closure(model, initial_guess) + f! = _get_model_closure(model, initial_guess, parameters) residual = similar(initial_guess) f!(residual, initial_guess) _check_residual(residual, inputs, MAX_INIT_RESIDUAL) diff --git a/src/base/perturbations.jl b/src/base/perturbations.jl index 567145b4d..05abba6ff 100644 --- a/src/base/perturbations.jl +++ b/src/base/perturbations.jl @@ -74,7 +74,7 @@ function _get_branch_for_perturbation( return branch end -function get_affect(::SimulationInputs, sys::PSY.System, pert::BranchImpedanceChange) +function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::BranchImpedanceChange) branch = _get_branch_for_perturbation(sys, pert) mult = 0.0 if pert.multiplier < 0.0 @@ -93,17 +93,17 @@ function get_affect(::SimulationInputs, sys::PSY.System, pert::BranchImpedanceCh return (integrator) -> begin @debug "Changing impedance line $(PSY.get_name(branch)) by a factor of $(pert.multiplier)" - ybus_update!(integrator.p, branch, mult) + ybus_update!(inputs, branch, mult) end return end -function get_affect(::SimulationInputs, sys::PSY.System, pert::BranchTrip) +function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::BranchTrip) branch = _get_branch_for_perturbation(sys, pert) return (integrator) -> begin @debug "Tripping line $(PSY.get_name(branch))" - ybus_update!(integrator.p, branch, -1.0) + ybus_update!(inputs, branch, -1.0) end return end @@ -367,12 +367,12 @@ function NetworkSwitch(time::Float64, ybus::PNM.Ybus) return NetworkSwitch(time, ybus.data) end -function get_affect(::SimulationInputs, ::PSY.System, pert::NetworkSwitch) +function get_affect(inputs::SimulationInputs, ::PSY.System, pert::NetworkSwitch) return (integrator) -> begin # TODO: This code can be more performant using SparseMatrix methods for (i, v) in enumerate(pert.ybus_rectangular) @debug "Changing Ybus network" - integrator.p.ybus_rectangular[i] = v + inputs.ybus_rectangular[i] = v end return end @@ -473,9 +473,19 @@ end function get_affect(inputs::SimulationInputs, ::PSY.System, pert::ControlReferenceChange) wrapped_device_ix = _find_device_index(inputs, pert.device) return (integrator) -> begin - wrapped_device = get_dynamic_injectors(integrator.p)[wrapped_device_ix] - @debug "Changing $(PSY.get_name(wrapped_device)) $(pert.signal) to $(pert.ref_value)" - getfield(wrapped_device, pert.signal)[] = pert.ref_value + wrapped_device = get_dynamic_injectors(inputs)[wrapped_device_ix] + p_range = get_p_range(wrapped_device) + p_local = @view integrator.p[p_range] + if pert.signal == :P_ref + ix = P_ref_ix + elseif pert.signal == :Q_ref + ix = Q_ref_ix + elseif pert.signal == :V_ref + ix = V_ref_ix + elseif pert.signal == :ω_ref + ix = ω_ref_ix + end + p_local[ix] = pert.ref_value return end end @@ -509,11 +519,13 @@ end function get_affect(inputs::SimulationInputs, ::PSY.System, pert::SourceBusVoltageChange) wrapped_device_ix = _find_device_index(inputs, pert.device) return (integrator) -> begin - wrapped_device = get_static_injectors(integrator.p)[wrapped_device_ix] + wrapped_device = get_static_injectors(inputs)[wrapped_device_ix] + p_range = get_p_range(wrapped_device) + device_parameters = @view integrator.p[p_range] if pert.signal == :V_ref - set_V_ref(wrapped_device, pert.ref_value) + device_parameters[3] = pert.ref_value elseif pert.signal == :θ_ref - set_θ_ref(wrapped_device, pert.ref_value) + device_parameters[4] = pert.ref_value else error("Signal $signal not accepted as a control reference change in SourceBus") end @@ -542,7 +554,7 @@ end function get_affect(inputs::SimulationInputs, ::PSY.System, pert::GeneratorTrip) wrapped_device_ix = _find_device_index(inputs, pert.device) return (integrator) -> begin - wrapped_device = get_dynamic_injectors(integrator.p)[wrapped_device_ix] + wrapped_device = get_dynamic_injectors(inputs)[wrapped_device_ix] ix_range = get_ix_range(wrapped_device) @debug "Changing connection status $(PSY.get_name(wrapped_device)), setting states $ix_range to 0.0" if integrator.du !== nothing @@ -635,49 +647,45 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) "Signal is not accepted for Constant PowerLoad. Please specify the correct signal type.", ) end - wrapped_zip = get_static_loads(integrator.p)[wrapped_device_ix] - P_power = get_P_power(wrapped_zip) - Q_power = get_Q_power(wrapped_zip) - set_P_power!(wrapped_zip, P_power + P_change) - set_Q_power!(wrapped_zip, Q_power + Q_change) + wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] + p_range = get_p_range(wrapped_zip) + device_parameters = @view integrator.p[p_range] + device_parameters[3] += P_change + device_parameters[6] += Q_change @debug "Changing load at bus $(PSY.get_name(wrapped_zip)) $(pert.signal) to $(pert.ref_value)" return end elseif isa(ld, PSY.StandardLoad) return (integrator) -> begin base_power_conversion = PSY.get_base_power(ld) / sys_base_power - wrapped_zip = get_static_loads(integrator.p)[wrapped_device_ix] + wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] + p_range = get_p_range(wrapped_zip) + device_parameters = @view integrator.p[p_range] # List all cases for StandardLoad changes if signal ∈ [:P_ref, :P_ref_impedance] P_old = PSY.get_impedance_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - P_impedance = get_P_impedance(wrapped_zip) - set_P_impedance!(wrapped_zip, P_impedance + P_change) + device_parameters[5] += P_change elseif signal ∈ [:Q_ref, :Q_ref_impedance] Q_old = PSY.get_impedance_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - Q_impedance = get_Q_impedance(wrapped_zip) - set_Q_impedance!(wrapped_zip, Q_impedance + Q_change) + device_parameters[8] += Q_change elseif signal == :P_ref_power P_old = PSY.get_constant_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - P_power = get_P_power(wrapped_zip) - set_P_power!(wrapped_zip, P_power + P_change) + device_parameters[3] += P_change elseif signal == :Q_ref_power Q_old = PSY.get_constant_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - Q_power = get_Q_power(wrapped_zip) - set_Q_power!(wrapped_zip, Q_power + Q_change) + device_parameters[8] += Q_change elseif signal == :P_ref_current P_old = PSY.get_current_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - P_current = get_P_current(wrapped_zip) - set_P_current!(wrapped_zip, P_current + P_change) + device_parameters[4] += P_change elseif signal == :Q_ref_current Q_old = PSY.get_current_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - Q_current = get_Q_current(wrapped_zip) - set_Q_current!(wrapped_zip, Q_current + Q_change) + device_parameters[7] += Q_change else error("It should never be here. Should have failed in the constructor.") end @@ -685,7 +693,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) elseif isa(ld, PSY.ExponentialLoad) return (integrator) -> begin ld_name = PSY.get_name(ld) - wrapped_zip = get_static_loads(integrator.p)[wrapped_device_ix] + wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] exp_names = get_exp_names(wrapped_zip) exp_vects = get_exp_params(wrapped_zip) tuple_ix = exp_names[ld_name] @@ -737,11 +745,11 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) Q_trip = PSY.get_reactive_power(ld) * base_power_conversion return (integrator) -> begin PSY.set_available!(ld, false) - wrapped_zip = get_static_loads(integrator.p)[wrapped_device_ix] - P_power = get_P_power(wrapped_zip) - Q_power = get_Q_power(wrapped_zip) - set_P_power!(wrapped_zip, P_power - P_trip) - set_Q_power!(wrapped_zip, Q_power - Q_trip) + wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] + p_range = get_p_range(wrapped_zip) + device_parameters = @view integrator.p[p_range] + device_parameters[3] -= P_trip + device_parameters[6] -= Q_trip @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end @@ -755,22 +763,18 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) Q_impedance_trip = PSY.get_impedance_reactive_power(ld) * base_power_conversion return (integrator) -> begin PSY.set_available!(ld, false) - wrapped_zip = get_static_loads(integrator.p)[wrapped_device_ix] + wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] + p_range = get_p_range(wrapped_zip) + device_parameters = @view integrator.p[p_range] # Update Constant Power - P_power = get_P_power(wrapped_zip) - Q_power = get_Q_power(wrapped_zip) - set_P_power!(wrapped_zip, P_power - P_power_trip) - set_Q_power!(wrapped_zip, Q_power - Q_power_trip) + device_parameters[3] -= P_power_trip + device_parameters[6] -= Q_power_trip # Update Constant Current - P_current = get_P_current(wrapped_zip) - Q_current = get_Q_current(wrapped_zip) - set_P_current!(wrapped_zip, P_current - P_current_trip) - set_Q_current!(wrapped_zip, Q_current - Q_current_trip) + device_parameters[4] -= P_current_trip + device_parameters[7] -= Q_current_trip # Update Constant Impedance - P_impedance = get_P_impedance(wrapped_zip) - Q_impedance = get_Q_impedance(wrapped_zip) - set_P_impedance!(wrapped_zip, P_impedance - P_impedance_trip) - set_Q_impedance!(wrapped_zip, Q_impedance - Q_impedance_trip) + device_parameters[5] -= P_impedance_trip + device_parameters[8] -= Q_impedance_trip @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end @@ -778,7 +782,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) return (integrator) -> begin PSY.set_available!(ld, false) ld_name = PSY.get_name(ld) - wrapped_zip = get_static_loads(integrator.p)[wrapped_device_ix] + wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] exp_names = get_exp_names(wrapped_zip) exp_params = get_exp_params(wrapped_zip) tuple_ix = exp_names[ld_name] diff --git a/src/base/simulation.jl b/src/base/simulation.jl index f870709df..05f0217e7 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -263,7 +263,7 @@ function _pre_initialize_simulation!(sim::Simulation) _initialize_state_space(sim) if sim.initialized != true @info("Pre-Initializing Simulation States") - sim.initialized = precalculate_initial_conditions!(sim.x0_init, sim) + sim.initialized = precalculate_initial_conditions!(sim) if !sim.initialized error( "The simulation failed to find an adequate initial guess for the initialization. Check the intialization routine.", @@ -279,9 +279,11 @@ end function _get_jacobian(sim::Simulation{ResidualModel}) inputs = get_simulation_inputs(sim) x0_init = get_initial_conditions(sim) + parameters = get_parameters(inputs) return JacobianFunctionWrapper( ResidualModel(inputs, x0_init, JacobianCache), x0_init, + parameters, # sparse_retrieve_loop = 0, ) end @@ -289,7 +291,12 @@ end function _get_jacobian(sim::Simulation{MassMatrixModel}) inputs = get_simulation_inputs(sim) x0_init = get_initial_conditions(sim) - return JacobianFunctionWrapper(MassMatrixModel(inputs, x0_init, JacobianCache), x0_init) + parameters = get_parameters(inputs) + return JacobianFunctionWrapper( + MassMatrixModel(inputs, x0_init, JacobianCache), + x0_init, + parameters, + ) end function _build_perturbations!(sim::Simulation) @@ -335,6 +342,7 @@ function _get_diffeq_problem( x0 = get_initial_conditions(sim) dx0 = zeros(length(x0)) simulation_inputs = get_simulation_inputs(sim) + p = get_parameters(simulation_inputs) sim.problem = SciMLBase.DAEProblem( SciMLBase.DAEFunction{true}( model; @@ -345,7 +353,7 @@ function _get_diffeq_problem( dx0, x0, get_tspan(sim), - simulation_inputs; + p; differential_vars = get_DAE_vector(simulation_inputs), ) sim.status = BUILT @@ -358,6 +366,7 @@ function _get_diffeq_problem( jacobian::JacobianFunctionWrapper, ) simulation_inputs = get_simulation_inputs(sim) + p = get_parameters(simulation_inputs) sim.problem = SciMLBase.ODEProblem( SciMLBase.ODEFunction{true}( model; @@ -369,7 +378,7 @@ function _get_diffeq_problem( ), sim.x0_init, get_tspan(sim), - simulation_inputs, + p; ) sim.status = BUILT return @@ -480,7 +489,7 @@ function _prog_meter_enabled() end function _filter_kwargs(kwargs) - return Dict(k => v for (k, v) in kwargs if in(k, DIFFEQ_SOLVE_KWARGS)) + return filter(x -> in(x[1], DIFFEQ_SOLVE_KWARGS), kwargs) end function _execute!(sim::Simulation, solver; kwargs...) diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index a37786cd8..fbc4ff205 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -31,10 +31,13 @@ end function initialize_static_injection!(inputs::SimulationInputs) @debug "Updating Source internal voltage magnitude and angle" static_injection_devices = get_static_injectors(inputs) + parameters = get_parameters(inputs) if !isempty(static_injection_devices) try for s in static_injection_devices - initialize_static_device!(s) + p_range = get_p_range(s) + local_parameters = @view parameters[p_range] + initialize_static_device!(s, local_parameters) end catch e bt = catch_backtrace() @@ -74,21 +77,14 @@ function initialize_dynamic_injection!( ) @debug "Updating Dynamic Injection Component Initial Guess" initial_inner_vars = zeros(get_inner_vars_count(inputs)) + parameters = get_parameters(inputs) try for dynamic_device in get_dynamic_injectors(inputs) - static = PSY.get_component( - dynamic_device.static_type, - system, - PSY.get_name(dynamic_device), - ) @debug "Initializing $(PSY.get_name(dynamic_device)) - $(typeof(dynamic_device.device))" - n_states = PSY.get_n_states(dynamic_device) _inner_vars = @view initial_inner_vars[get_inner_vars_index(dynamic_device)] - x0_device = initialize_dynamic_device!(dynamic_device, static, _inner_vars) - @assert length(x0_device) == n_states - ix_range = get_ix_range(dynamic_device) - initial_guess[ix_range] = x0_device - @debug _initialization_debug(dynamic_device, static, x0_device) + _parameters = @view parameters[get_p_range(dynamic_device)] + _states = @view initial_guess[get_ix_range(dynamic_device)] + initialize_dynamic_device!(dynamic_device, _inner_vars, _parameters, _states) end catch e bt = catch_backtrace() @@ -102,15 +98,14 @@ function initialize_dynamic_branches!( initial_guess::Vector{Float64}, inputs::SimulationInputs, ) + parameters = get_parameters(inputs) try @debug "Initializing Dynamic Branches" for br in get_dynamic_branches(inputs) @debug "$(PSY.get_name(br)) - $(typeof(br))" - n_states = PSY.get_n_states(br) - x0_branch = initialize_dynamic_device!(br) - IS.@assert_op length(x0_branch) == n_states - ix_range = get_ix_range(br) - initial_guess[ix_range] = x0_branch + _parameters = @view parameters[get_p_range(br)] + _states = @view initial_guess[get_ix_range(br)] + initialize_dynamic_device!(br, _parameters, _states) end catch e bt = catch_backtrace() @@ -154,7 +149,7 @@ end # Default implementation for both models. This implementation is to future proof if there is # a divergence between the required build methods -function _calculate_initial_guess!(x0_init::Vector{Float64}, sim::Simulation) +function _calculate_initial_guess!(sim::Simulation) inputs = get_simulation_inputs(sim) @assert sim.status == BUILD_INCOMPLETE while sim.status == BUILD_INCOMPLETE @@ -180,8 +175,8 @@ function _calculate_initial_guess!(x0_init::Vector{Float64}, sim::Simulation) return end -function precalculate_initial_conditions!(x0_init::Vector{Float64}, sim::Simulation) - _calculate_initial_guess!(x0_init, sim) +function precalculate_initial_conditions!(sim::Simulation) + _calculate_initial_guess!(sim) return sim.status != BUILD_FAILED end diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index 925041dfe..14977b8b2 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -1,4 +1,4 @@ -struct SimulationInputs +mutable struct SimulationInputs dynamic_injectors::Vector{DynamicWrapper{<:PSY.DynamicInjection}} static_injectors::Vector static_loads::Vector @@ -18,6 +18,7 @@ struct SimulationInputs global_vars_update_pointers::Dict{Int, Int} global_state_map::MAPPING_DICT global_inner_var_map::Dict{String, Dict} + parameters::Vector{Float64} function SimulationInputs( sys::PSY.System, @@ -25,32 +26,40 @@ struct SimulationInputs ) where {T <: Union{ConstantFrequency, ReferenceBus}} n_buses = get_n_buses(sys) Ybus, lookup = _get_ybus(sys) - + state_count = 2 * n_buses + 1 + parameter_count = 1 TimerOutputs.@timeit BUILD_TIMER "Wrap Branches" begin - wrapped_branches = _wrap_dynamic_branches(sys, lookup) + wrapped_branches, state_count, parameter_count = + _wrap_dynamic_branches(sys, lookup, state_count, parameter_count) has_dyn_lines = !isempty(wrapped_branches) - aux_states = 0 - for br in wrapped_branches - aux_states += PSY.get_n_states(br) - end - branch_state_counts = aux_states - injection_start = 2 * n_buses + branch_state_counts + 1 end + n_branch_states = state_count - (2 * n_buses + 1) + injection_start = state_count TimerOutputs.@timeit BUILD_TIMER "Wrap Dynamic Injectors" begin - wrapped_injectors = _wrap_dynamic_injector_data(sys, lookup, injection_start) - var_count = wrapped_injectors[end].ix_range[end] + wrapped_injectors, state_count, parameter_count = + _wrap_dynamic_injector_data(sys, lookup, state_count, parameter_count) + n_vars = state_count - 1 end - TimerOutputs.@timeit BUILD_TIMER "Calculate MM, DAE_vector, Total Shunts" begin - mass_matrix = _make_mass_matrix(wrapped_injectors, var_count, n_buses) - DAE_vector = _make_DAE_vector(mass_matrix, var_count, n_buses) - total_shunts = _make_total_shunts(wrapped_branches, n_buses) + TimerOutputs.@timeit BUILD_TIMER "Wrap Static Injectors" begin + wrapped_loads, parameter_count = _wrap_loads(sys, lookup, parameter_count) + wrapped_static_injectors, parameter_count = + _wrap_static_injectors(sys, lookup, parameter_count) end - TimerOutputs.@timeit BUILD_TIMER "Wrap Static Injectors" begin - wrapped_loads = _wrap_loads(sys, lookup) - wrapped_static_injectors = _wrap_static_injectors(sys, lookup) + TimerOutputs.@timeit BUILD_TIMER "Build initial parameters" begin + initial_parameters = zeros(parameter_count) + _update_initial_parameters!(initial_parameters, wrapped_branches) + _update_initial_parameters!(initial_parameters, wrapped_injectors) + _update_initial_parameters!(initial_parameters, wrapped_loads) + _update_initial_parameters!(initial_parameters, wrapped_static_injectors) + end + + TimerOutputs.@timeit BUILD_TIMER "Calculate MM, DAE_vector, Total Shunts" begin + mass_matrix = _make_mass_matrix(wrapped_injectors, n_vars, n_buses) + DAE_vector = _make_DAE_vector(mass_matrix, n_vars, n_buses) + total_shunts = _make_total_shunts(wrapped_branches, n_buses) end _adjust_states!( @@ -76,12 +85,12 @@ struct SimulationInputs wrapped_static_injectors, wrapped_loads, wrapped_branches, - var_count - 2 * n_buses - branch_state_counts, - branch_state_counts, - var_count, + n_vars - 2 * n_buses - n_branch_states, + n_branch_states, + n_vars, inner_vars_count, n_buses, - injection_start:var_count, + injection_start:n_vars, Ybus, has_dyn_lines, total_shunts, @@ -91,6 +100,7 @@ struct SimulationInputs global_vars, MAPPING_DICT(), Dict{String, Dict}(), + initial_parameters, ) end end @@ -115,6 +125,7 @@ get_inner_vars_count(inputs::SimulationInputs) = inputs.inner_vars_count get_ode_ouput_range(inputs::SimulationInputs) = inputs.ode_range get_bus_count(inputs::SimulationInputs) = inputs.bus_count get_bus_range(inputs::SimulationInputs) = 1:(2 * inputs.bus_count) +get_parameters(inputs::SimulationInputs) = inputs.parameters # Utility function not to be used for performance sensitive operations function get_voltage_buses_ix(inputs::SimulationInputs) @@ -150,7 +161,34 @@ function SimulationInputs( return SimulationInputs(sys, frequency_reference) end -function _wrap_dynamic_injector_data(sys::PSY.System, lookup, injection_start::Int) +function _update_initial_parameters!(initial_parameters, wrapped_devices) + for wrapped_device in wrapped_devices + p = get_params(wrapped_device) + p_range = get_p_range(wrapped_device) + initial_parameters[p_range] .= p + end +end + +function _get_n_params( + dynamic_device::PSY.DynamicInjection, + static_device::PSY.StaticInjection, +) + return get_n_params(dynamic_device) +end + +function _get_n_params( + dynamic_device::T, + static_device::PSY.StaticInjection, +) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} + return get_n_params(dynamic_device) + get_n_params(static_device) +end + +function _wrap_dynamic_injector_data( + sys::PSY.System, + lookup, + state_count::Int, + parameter_count::Int, +) #injection_start injector_data = get_injectors_with_dynamics(sys) isempty(injector_data) && error("System doesn't contain any DynamicInjection devices") # TODO: Needs a better container that isn't parametrized on an abstract type @@ -164,13 +202,15 @@ function _wrap_dynamic_injector_data(sys::PSY.System, lookup, injection_start::I @debug "Wrapping $(PSY.get_name(device))" dynamic_device = PSY.get_dynamic_injector(device) n_states = PSY.get_n_states(dynamic_device) - ix_range = range(injection_start; length = n_states) + n_params = _get_n_params(dynamic_device, device) + n_inner_vars = get_inner_vars_count(dynamic_device) + ix_range = range(state_count; length = n_states) ode_range = range(injection_count; length = n_states) + p_range = range(parameter_count; length = n_params) bus_n = PSY.get_number(PSY.get_bus(device)) bus_ix = lookup[bus_n] - inner_vars_range = - range(inner_vars_count; length = get_inner_vars_count(dynamic_device)) - @debug "ix_range=$ix_range ode_range=$ode_range inner_vars_range= $inner_vars_range" + inner_vars_range = range(inner_vars_count; length = n_inner_vars) + @debug "ix_range=$ix_range ode_range=$ode_range inner_vars_range= $inner_vars_range p_range=$p_range" dynamic_device = PSY.get_dynamic_injector(device) @assert dynamic_device !== nothing wrapped_injector[ix] = DynamicWrapper( @@ -179,20 +219,25 @@ function _wrap_dynamic_injector_data(sys::PSY.System, lookup, injection_start::I bus_ix, ix_range, ode_range, + p_range, inner_vars_range, sys_base_power, sys_base_freq, ) injection_count += n_states - injection_start += n_states - inner_vars_count = - length(inner_vars_range) > 0 ? inner_vars_range[end] : inner_vars_count + state_count += n_states + parameter_count += n_params + inner_vars_count += n_inner_vars end - return wrapped_injector + return wrapped_injector, state_count, parameter_count end -function _wrap_dynamic_branches(sys::PSY.System, lookup::Dict{Int, Int}) - branches_start = 2 * get_n_buses(sys) + 1 +function _wrap_dynamic_branches( + sys::PSY.System, + lookup::Dict{Int, Int}, + state_count::Int, + parameter_count::Int, +) sys_base_power = PSY.get_base_power(sys) sys_base_freq = PSY.get_frequency(sys) dynamic_branches = get_dynamic_branches(sys) @@ -207,28 +252,36 @@ function _wrap_dynamic_branches(sys::PSY.System, lookup::Dict{Int, Int}) to_bus_number = PSY.get_number(arc.to) bus_ix_from = lookup[from_bus_number] bus_ix_to = lookup[to_bus_number] - ix_range = range(branches_start; length = n_states) + ix_range = range(state_count; length = n_states) ode_range = range(branches_count; length = n_states) - @debug "ix_range=$ix_range ode_range=$ode_range" + n_params = get_n_params(br) + p_range = range(parameter_count; length = n_params) + @debug "ix_range=$ix_range ode_range=$ode_range p_range=$ode_range" wrapped_branches[ix] = BranchWrapper( br, bus_ix_from, bus_ix_to, ix_range, ode_range, + p_range, sys_base_power, sys_base_freq, ) branches_count += n_states - branches_start += n_states + state_count += n_states + parameter_count += n_params end else @debug("System doesn't contain Dynamic Branches") end - return wrapped_branches + return wrapped_branches, state_count, parameter_count end -function _wrap_static_injectors(sys::PSY.System, lookup::Dict{Int, Int}) +function _wrap_static_injectors( + sys::PSY.System, + lookup::Dict{Int, Int}, + parameter_count::Int, +) static_injection_data = get_injection_without_dynamics(sys) container = Vector{StaticWrapper}(undef, length(static_injection_data)) for (ix, ld) in enumerate(static_injection_data) @@ -237,12 +290,15 @@ function _wrap_static_injectors(sys::PSY.System, lookup::Dict{Int, Int}) end bus_n = PSY.get_number(PSY.get_bus(ld)) bus_ix = lookup[bus_n] - container[ix] = StaticWrapper(ld, bus_ix) + n_params = get_n_params(ld) + p_range = range(parameter_count; length = n_params) + container[ix] = StaticWrapper(ld, bus_ix, p_range) + parameter_count += n_params end - return container + return container, parameter_count end -function _wrap_loads(sys::PSY.System, lookup::Dict{Int, Int}) +function _wrap_loads(sys::PSY.System, lookup::Dict{Int, Int}, parameter_count::Int) sys_base_power = PSY.get_base_power(sys) # This needs to change if we implement dynamic load models static_loads = @@ -256,21 +312,25 @@ function _wrap_loads(sys::PSY.System, lookup::Dict{Int, Int}) # Optimize this dictionary push push!(get!(map_bus_load, bus, PSY.ElectricLoad[]), ld) end - return _construct_load_wrapper(lookup, map_bus_load, sys_base_power) + return _construct_load_wrapper(lookup, map_bus_load, sys_base_power, parameter_count) end function _construct_load_wrapper( lookup::Dict{Int, Int}, map_bus_load::Dict{PSY.Bus, Vector{PSY.ElectricLoad}}, sys_base_power, + parameter_count, ) container = Vector{StaticLoadWrapper}(undef, length(map_bus_load)) for (ix, (bus, loads)) in enumerate(map_bus_load) bus_n = PSY.get_number(bus) bus_ix = lookup[bus_n] - container[ix] = StaticLoadWrapper(bus, loads, bus_ix, sys_base_power) + n_params = 8 + p_range = range(parameter_count; length = n_params) + container[ix] = StaticLoadWrapper(bus, loads, p_range, bus_ix, sys_base_power) + parameter_count += n_params end - return container + return container, parameter_count end function _get_ybus(sys::PSY.System) @@ -404,12 +464,14 @@ end function get_setpoints(inputs::SimulationInputs) dic = Dict{String, Dict{String, Float64}}() + parameters = get_parameters(inputs) for w in get_dynamic_injectors(inputs) dic_w = Dict{String, Float64}() - dic_w["P_ref"] = get_P_ref(w) - dic_w["Q_ref"] = get_Q_ref(w) - dic_w["ω_ref"] = get_ω_ref(w) - dic_w["V_ref"] = get_V_ref(w) + p_range = get_p_range(w) + dic_w["P_ref"] = parameters[p_range][P_ref_ix] + dic_w["Q_ref"] = parameters[p_range][Q_ref_ix] + dic_w["ω_ref"] = parameters[p_range][ω_ref_ix] + dic_w["V_ref"] = parameters[p_range][V_ref_ix] dic[PSY.get_name(w)] = dic_w end return dic diff --git a/src/base/simulation_results.jl b/src/base/simulation_results.jl index bd0d1f5bd..38bf4b5f9 100644 --- a/src/base/simulation_results.jl +++ b/src/base/simulation_results.jl @@ -44,14 +44,14 @@ function _post_proc_state_series(solution, ix::Int, dt::Nothing) end function _post_proc_state_series(solution, ix::Int, dt::Float64) - ts = range(0; stop = solution.t[end], step = dt) - state = solution(collect(ts); idxs = ix) - return ts, state + ts = collect(range(0; stop = solution.t[end], step = dt)) + state = solution(ts; idxs = ix) + return ts, state.u end function _post_proc_state_series(solution, ix::Int, dt::Vector{Float64}) state = solution(dt; idxs = ix) - return dt, state + return dt, state.u end """ diff --git a/src/base/small_signal.jl b/src/base/small_signal.jl index 545af4b43..e684e82f0 100644 --- a/src/base/small_signal.jl +++ b/src/base/small_signal.jl @@ -17,40 +17,6 @@ function _determine_stability(vals::Vector{Complex{Float64}}) return true end -function _calculate_forwardiff_jacobian( - sim::Simulation{ResidualModel}, - x_eval::Vector{Float64}, -) - var_count = get_variable_count(sim.inputs) - dx0 = zeros(var_count) #Define a vector of zeros for the derivative - sysf! = (out, x) -> system_implicit!( - out, #output of the function - dx0, #derivatives equal to zero - x, #states - sim.inputs, #Parameters - 0.0, #time equals to zero. - ) - out = zeros(var_count) #Define a vector of zeros for the output - jacobian = ForwardDiff.jacobian(sysf!, out, x_eval) - return jacobian -end - -function _calculate_forwardiff_jacobian( - sim::Simulation{MassMatrixModel}, - x_eval::Vector{Float64}, -) - var_count = get_variable_count(sim.inputs) - sysf! = (dx, x) -> system_mass_matrix!( - dx, #derivatives equal to zero - x, #states - sim.inputs, #Parameters - 0.0, #time equals to zero. - ) - dx = zeros(var_count) #Define a vector of zeros for the output - jacobian = ForwardDiff.jacobian(sysf!, dx, x_eval) - return jacobian -end - """ Finds the location of the differential states in the reduced Jacobian """ @@ -185,24 +151,27 @@ function _small_signal_analysis( ::Type{T}, inputs::SimulationInputs, x_eval::Vector{Float64}, + p::Vector{Float64}, multimachine = true, ) where {T <: SimulationModel} - jacwrapper = get_jacobian(T, inputs, x_eval, 0) + jacwrapper = get_jacobian(T, inputs, x_eval, p, 0) return _small_signal_analysis(jacwrapper.Jv, jacwrapper.x, inputs, multimachine) end function small_signal_analysis(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} inputs = get_simulation_inputs(sim) x_eval = get(kwargs, :operating_point, get_initial_conditions(sim)) - return _small_signal_analysis(T, inputs, x_eval, sim.multimachine) + p = get_parameters(inputs) + return _small_signal_analysis(T, inputs, x_eval, p, sim.multimachine) end function small_signal_analysis(::Type{T}, system::PSY.System) where {T <: SimulationModel} simulation_system = deepcopy(system) inputs = SimulationInputs(T, simulation_system, ReferenceBus) + p = get_parameters(inputs) x0_init = get_flat_start(inputs) set_operating_point!(x0_init, inputs, system) - return _small_signal_analysis(T, inputs, x0_init) + return _small_signal_analysis(T, inputs, x0_init, p) end function summary_participation_factors( diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index 4d18c35a5..00050542e 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -1,5 +1,6 @@ function initialize_avr!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRFixed, TG, P}}, inner_vars::AbstractVector, @@ -8,7 +9,7 @@ function initialize_avr!( Vf = inner_vars[Vf_var] #Update Control Refs avr = PSY.get_avr(dynamic_device) - set_V_ref(dynamic_device, Vf) + device_parameters[V_ref_ix] = Vf PSY.set_Vf!(avr, Vf) PSY.set_V_ref!(avr, Vf) return @@ -16,6 +17,7 @@ end function initialize_avr!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRSimple, TG, P}}, inner_vars::AbstractVector, @@ -32,12 +34,13 @@ function initialize_avr!( #Set V_ref PSY.set_V_ref!(PSY.get_avr(dynamic_device), Vm) #Update Control Refs - set_V_ref(dynamic_device, Vm) + device_parameters[V_ref_ix] = Vm return end function initialize_avr!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRTypeI, TG, P}}, inner_vars::AbstractVector, @@ -49,12 +52,9 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) - Ka = PSY.get_Ka(avr) - Ke = PSY.get_Ke(avr) - Kf = PSY.get_Kf(avr) - Tf = PSY.get_Tf(avr) - Ae = PSY.get_Ae(avr) - Be = PSY.get_Be(avr) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AVRTypeI) + internal_params = @view device_parameters[local_ix_params] + Ka, Ke, Kf, _, _, Tf, _, Ae, Be = internal_params #Obtain saturated Vf Se_Vf = Ae * exp(Be * abs(Vf0)) @@ -77,7 +77,7 @@ function initialize_avr!( sol_x0 = sol.zero #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - set_V_ref(dynamic_device, sol_x0[1]) + device_parameters[V_ref_ix] = sol_x0[1] #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeI) avr_states = @view device_states[avr_ix] @@ -91,6 +91,7 @@ end function initialize_avr!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRTypeII, TG, P}}, inner_vars::AbstractVector, @@ -102,18 +103,21 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) - K0 = PSY.get_K0(avr) - T1 = PSY.get_T1(avr) - T2 = PSY.get_T2(avr) - T3 = PSY.get_T3(avr) - T4 = PSY.get_T4(avr) - Te = PSY.get_Te(avr) - Tr = PSY.get_Tr(avr) - Ae = PSY.get_Ae(avr) - Be = PSY.get_Be(avr) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AVRTypeII) + internal_params = @view device_parameters[local_ix_params] + K0, + T1, + T2, + T3, + T4, + Te, + _, + Va_min, + Va_max, + Ae, + Be = internal_params #Obtain saturated Vf Se_Vf = Ae * (exp(Be * abs(Vf0))) - Va_min, Va_max = PSY.get_Va_lim(avr) #States of AVRTypeII are Vf, Vr1, Vr2, Vm #To solve V_ref, Vr1, Vr2 @@ -139,7 +143,7 @@ function initialize_avr!( sol_x0 = sol.zero #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - set_V_ref(dynamic_device, sol_x0[1]) + device_parameters[V_ref_ix] = sol_x0[1] #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeII) avr_states = @view device_states[avr_ix] @@ -158,6 +162,7 @@ end function initialize_avr!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.ESAC1A, TG, P}}, inner_vars::AbstractVector, @@ -171,21 +176,25 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) - Tr = PSY.get_Tr(avr) - Tb = PSY.get_Tb(avr) - Tc = PSY.get_Tc(avr) - Ka = PSY.get_Ka(avr) - Ta = PSY.get_Ta(avr) - Va_min, Va_max = PSY.get_Va_lim(avr) - Te = PSY.get_Te(avr) - Kf = PSY.get_Kf(avr) - Tf = PSY.get_Tf(avr) - Kc = PSY.get_Kc(avr) - Kd = PSY.get_Kd(avr) - Ke = PSY.get_Ke(avr) - E1, E2 = PSY.get_E_sat(avr) - SE1, SE2 = PSY.get_Se(avr) - Vr_min, Vr_max = PSY.get_Vr_lim(avr) + #Get parameters + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.ESAC1A) + internal_params = @view device_parameters[local_ix_params] + Tr, + Tb, + Tc, + Ka, + Ta, + Va_min, + Va_max, + Te, + Kf, + Tf, + Kc, + Kd, + Ke, + Vr_min, + Vr_max = internal_params + inv_Tr = Tr < eps() ? 1.0 : 1.0 / Tr #Obtain saturation #Se_Vf = saturation_function(Vm) @@ -249,7 +258,7 @@ function initialize_avr!( sol_x0 = sol.zero #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - set_V_ref(dynamic_device, sol_x0[1]) + device_parameters[V_ref_ix] = sol_x0[1] #Update AVR states avr_ix = get_local_state_ix(dynamic_device, typeof(avr)) avr_states = @view device_states[avr_ix] @@ -263,6 +272,7 @@ end function initialize_avr!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.SEXS, TG, P}}, inner_vars::AbstractVector, @@ -274,9 +284,9 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) - Ta_Tb = PSY.get_Ta_Tb(avr) - K = PSY.get_K(avr) - V_min, V_max = PSY.get_V_lim(avr) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SEXS) + internal_params = @view device_parameters[local_ix_params] + Ta_Tb, _, K, _, V_min, V_max = internal_params #States of AVRTypeI are Vf, Vr1, Vr2, Vm #To solve V_ref, Vr @@ -304,7 +314,8 @@ function initialize_avr!( end #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - set_V_ref(dynamic_device, sol_x0[1]) + device_parameters[V_ref_ix] = sol_x0[1] + #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.SEXS) avr_states = @view device_states[avr_ix] @@ -315,6 +326,7 @@ end function initialize_avr!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.SCRX, TG, P}}, inner_vars::AbstractVector, @@ -386,7 +398,7 @@ function initialize_avr!( end #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - set_V_ref(dynamic_device, sol_x0[1]) + device_parameters[V_ref_ix] = sol_x0[1] #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.SCRX) avr_states = @view device_states[avr_ix] @@ -397,6 +409,7 @@ end function initialize_avr!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.EXST1, TG, P}}, inner_vars::AbstractVector, @@ -410,13 +423,20 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) - Ka = PSY.get_Ka(avr) - Kf = PSY.get_Kf(avr) - Tf = PSY.get_Tf(avr) - Tc = PSY.get_Tc(avr) - Tb = PSY.get_Tb(avr) - Kc = PSY.get_Kc(avr) - Vr_min, Vr_max = PSY.get_Vr_lim(avr) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.EXST1) + internal_params = @view device_parameters[local_ix_params] + Tr, + Vi_min, + Vi_max, + Tc, + Tb, + Ka, + Ta, + Vr_min, + Vr_max, + Kc, + Kf, + Tf = internal_params # Check limits to field voltage if (Vt * Vr_min - Kc * Ifd > Vf0) || (Vf0 > Vt * Vr_max - Kc * Ifd) @@ -429,7 +449,7 @@ function initialize_avr!( Vref0 = Vt + Vf0 / Ka PSY.set_V_ref!(avr, Vref0) - set_V_ref(dynamic_device, Vref0) + device_parameters[V_ref_ix] = Vref0 #States of EXST1_PTI are Vm, Vll, Vr, Vfb @@ -445,6 +465,7 @@ end function initialize_avr!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.EXAC1, TG, P}}, inner_vars::AbstractVector, @@ -458,15 +479,22 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) - Tb = PSY.get_Tb(avr) - Tc = PSY.get_Tc(avr) - Ka = PSY.get_Ka(avr) - Kf = PSY.get_Kf(avr) - Tf = PSY.get_Tf(avr) - Kc = PSY.get_Kc(avr) - Kd = PSY.get_Kd(avr) - Ke = PSY.get_Ke(avr) - Vr_min, Vr_max = PSY.get_Vr_lim(avr) + #Get parameters + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.EXAC1) + internal_params = @view device_parameters[local_ix_params] + Tr, + Tb, + Tc, + Ka, + Ta, + Vr_min, + Vr_max, + Te, + Kf, + Tf, + Kc, + Kd, + Ke = internal_params #Solve Ve from rectifier function function f_Ve!(out, x) @@ -498,7 +526,7 @@ function initialize_avr!( #Update V_ref PSY.set_V_ref!(avr, Vref0) - set_V_ref(dynamic_device, Vref0) + device_parameters[V_ref_ix] = Vref0 #States of EXAC1 are Vm, Vr1, Vr2, Ve, Vr3 @@ -515,6 +543,7 @@ end function initialize_avr!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.ESST1A, TG, P}}, inner_vars::AbstractVector, @@ -557,7 +586,7 @@ function initialize_avr!( Vref0 = Vt + Va / Ka PSY.set_V_ref!(avr, Vref0) - set_V_ref(dynamic_device, Vref0) + device_parameters[V_ref_ix] = Vref0 #States of ESST1A_PTI are Vm, Vr1, Vr2, Va, Vr3 diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index b400bd7fc..2f8bbdb47 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -4,6 +4,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{PSY.BaseMachine, S, A, TG, P}}, inner_vars::AbstractVector, @@ -21,9 +22,9 @@ function initialize_mach_shaft!( #Machine Data machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - #Assumption of Classical Machine: Xq = Xd_p - Xd_p = PSY.get_Xd_p(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.BaseMachine) + internal_params = @view device_parameters[local_ix_params] + R, Xd_p, _ = internal_params δ0 = angle(V + (R + Xd_p * 1im) * I) ω0 = 1.0 @@ -62,6 +63,7 @@ function initialize_mach_shaft!( inner_vars[τm_var] = sol_x0[2] #Not necessary to update Vf for AVR in Base Machine. Update eq_p: PSY.set_eq_p!(machine, sol_x0[3]) + internal_params[3] = sol_x0[3] inner_vars[Vf_var] = sol_x0[3] end return @@ -73,6 +75,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{PSY.OneDOneQMachine, S, A, TG, P}}, inner_vars::AbstractVector, @@ -89,12 +92,9 @@ function initialize_mach_shaft!( I = conj(S0 / V) #Machine Data - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.OneDOneQMachine) + internal_params = @view device_parameters[local_ix_params] + R, Xd, Xq, Xd_p, Xq_p, _, _ = internal_params #States of OneDOneQMachine are [1] eq_p and [2] ed_p δ0 = angle(V + (R + Xq * 1im) * I) @@ -155,6 +155,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{PSY.SauerPaiMachine, S, A, TG, P}}, inner_vars::AbstractVector, @@ -263,6 +264,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{PSY.MarconatoMachine, S, A, TG, P}}, inner_vars::AbstractVector, @@ -280,18 +282,9 @@ function initialize_mach_shaft!( I = conj(S0 / V) #Machine Data - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) - Xq_pp = PSY.get_Xq_pp(machine) - T_AA = PSY.get_T_AA(machine) - Td0_p = PSY.get_Td0_p(machine) - γd = PSY.get_γd(machine) - γq = PSY.get_γq(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.MarconatoMachine) + internal_params = @view device_parameters[local_ix_params] + R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, _, _, _, T_AA, γd, γq = internal_params #States of MarconatoMachine are [1] ψq, [2] ψd, [3] eq_p, [4] ed_p, [5] eq_pp and [6] ed_pp δ0 = angle(V + (R + Xq * 1im) * I) @@ -367,6 +360,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicGenerator{PSY.SimpleMarconatoMachine, S, A, TG, P}, @@ -467,6 +461,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicGenerator{PSY.AndersonFouadMachine, S, A, TG, P}, @@ -486,14 +481,19 @@ function initialize_mach_shaft!( I = conj(S0 / V) #Machine Data - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) - Xq_pp = PSY.get_Xq_pp(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AndersonFouadMachine) + internal_params = @view device_parameters[local_ix_params] + R, + Xd, + Xq, + Xd_p, + Xq_p, + Xd_pp, + Xq_pp, + _, + _, + _, + _ = internal_params #States of Anderson-Fouad are [1] ψq, [2] ψd, [3] eq_p, [4] ed_p, [5] eq_pp and [6] ed_pp δ0 = angle(V + (R + Xq * 1im) * I) @@ -570,6 +570,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{PSY.SimpleAFMachine, S, A, TG, P}}, inner_vars::AbstractVector, @@ -660,6 +661,7 @@ end function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, P}}, inner_vars::AbstractVector, @@ -684,26 +686,27 @@ function initialize_mach_shaft!( #Get parameters machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Td0_p = PSY.get_Td0_p(machine) - Td0_pp = PSY.get_Td0_pp(machine) - Tq0_p = PSY.get_Tq0_p(machine) - Tq0_pp = PSY.get_Tq0_pp(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, typeof(machine)) + internal_params = @view device_parameters[local_ix_params] + R, + Td0_p, + Td0_pp, + Tq0_p, + Tq0_pp, + Xd, + Xq, + Xd_p, + Xq_p, + Xd_pp, + Xl, + γ_d1, + γ_q1, + γ_d2, + γ_q2, + γ_qd = internal_params Xq_pp = Xd_pp - Xl = PSY.get_Xl(machine) - Se = PSY.get_Se(machine) # Initialization doesn't consider saturation #Sat_A, Sat_B = PSY.get_saturation_coeffs(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) - γ_q2 = PSY.get_γ_q2(machine) - γ_qd = PSY.get_γ_qd(machine) ## Initialization ## ## Fluxes @@ -812,6 +815,7 @@ end function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicGenerator{PSY.SalientPoleQuadratic, S, A, TG, P}, @@ -831,21 +835,23 @@ function initialize_mach_shaft!( V = V_R + V_I * 1im I = conj(S0 / V) - #Get parameters machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Td0_p = PSY.get_Td0_p(machine) - Td0_pp = PSY.get_Td0_pp(machine) - Tq0_pp = PSY.get_Tq0_pp(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) + #Get parameters + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SalientPoleQuadratic) + internal_params = @view device_parameters[local_ix_params] + R, + Td0_p, + Td0_pp, + Tq0_pp, + Xd, + Xq, + Xd_p, + Xd_pp, + Xl, + γ_d1, + γ_q1, + γ_d2 = internal_params Xq_pp = Xd_pp - Xl = PSY.get_Xl(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) ## Initialization ## E = V + (R + Xq * 1im) * I @@ -934,6 +940,7 @@ end function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicGenerator{PSY.SalientPoleExponential, S, A, TG, P}, @@ -953,21 +960,23 @@ function initialize_mach_shaft!( V = V_R + V_I * 1im I = conj(S0 / V) - #Get parameters machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Td0_p = PSY.get_Td0_p(machine) - Td0_pp = PSY.get_Td0_pp(machine) - Tq0_pp = PSY.get_Tq0_pp(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) + #Get parameters + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SalientPoleExponential) + internal_params = @view device_parameters[local_ix_params] + R, + Td0_p, + Td0_pp, + Tq0_pp, + Xd, + Xq, + Xd_p, + Xd_pp, + Xl, + γ_d1, + γ_q1, + γ_d2 = internal_params Xq_pp = Xd_pp - Xl = PSY.get_Xl(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) γ_qd = (Xq - Xl) / (Xd - Xl) ## Initialization ## @@ -1073,6 +1082,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::PSY.DynamicGenerator{PSY.FullMachine, S, A, TG, P}}, ) where {S <: PSY.Shaft, A <: PSY.AVR, TG <: PSY.TurbineGov, P <: PSY.PSS} diff --git a/src/initialization/generator_components/init_pss.jl b/src/initialization/generator_components/init_pss.jl index f971bc675..db5733aab 100644 --- a/src/initialization/generator_components/init_pss.jl +++ b/src/initialization/generator_components/init_pss.jl @@ -1,5 +1,6 @@ function initialize_pss!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSSFixed}}, inner_vars::AbstractVector, @@ -7,6 +8,7 @@ function initialize_pss!( function initialize_pss!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.IEEEST}}, inner_vars::AbstractVector, @@ -116,15 +118,14 @@ end function initialize_pss!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.STAB1}}, inner_vars::AbstractVector, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, TG <: PSY.TurbineGov} - #Get Signal Input Integer - pss = PSY.get_pss(dynamic_device) #Obtain PSS States - pss_ix = get_local_state_ix(dynamic_device, typeof(pss)) + pss_ix = get_local_state_ix(dynamic_device, PSY.STAB1) pss_states = @view device_states[pss_ix] #Compute steady-state values @@ -147,6 +148,7 @@ end function initialize_pss!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSS2A}}, inner_vars::AbstractVector, @@ -270,6 +272,7 @@ end function initialize_pss!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSS2B}}, inner_vars::AbstractVector, @@ -406,6 +409,7 @@ end function initialize_pss!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSS2C}}, inner_vars::AbstractVector, diff --git a/src/initialization/generator_components/init_shaft.jl b/src/initialization/generator_components/init_shaft.jl index 05669e62f..56f62b7c8 100644 --- a/src/initialization/generator_components/init_shaft.jl +++ b/src/initialization/generator_components/init_shaft.jl @@ -1,5 +1,6 @@ function initialize_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, PSY.SingleMass, A, TG, P}}, inner_vars::AbstractVector, @@ -7,6 +8,7 @@ function initialize_shaft!( function initialize_shaft!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, PSY.FiveMassShaft, A, TG, P}}, inner_vars::AbstractVector, @@ -22,21 +24,27 @@ function initialize_shaft!( ω_ex = ω ω_sys = ω - #Obtain parameters - shaft = PSY.get_shaft(dynamic_device) - D = PSY.get_D(shaft) - D_hp = PSY.get_D_hp(shaft) - D_ip = PSY.get_D_ip(shaft) - D_lp = PSY.get_D_lp(shaft) - D_ex = PSY.get_D_ex(shaft) - D_12 = PSY.get_D_12(shaft) - D_23 = PSY.get_D_23(shaft) - D_34 = PSY.get_D_34(shaft) - D_45 = PSY.get_D_45(shaft) - K_hp = PSY.get_K_hp(shaft) - K_ip = PSY.get_K_ip(shaft) - K_lp = PSY.get_K_lp(shaft) - K_ex = PSY.get_K_ex(shaft) + #Get parameters + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SingleMass) + internal_params = @view device_parameters[local_ix_params] + _, + _, + _, + _, + _, + D, + D_hp, + D_ip, + D_lp, + D_ex, + D_12, + D_23, + D_34, + D_45, + K_hp, + K_ip, + K_lp, + K_ex = internal_params #Obtain inner vars τe = inner_vars[τe_var] diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index af4f5a725..212850dc1 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -1,21 +1,26 @@ function initialize_tg!( device_states, + device_parameters, ::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGFixed, P}}, inner_vars::AbstractVector, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} tg = PSY.get_prime_mover(dynamic_device) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.TGFixed) + internal_params = @view device_parameters[local_ix_params] + eff = internal_params[1] τm0 = inner_vars[τm_var] - eff = PSY.get_efficiency(tg) + P_ref = τm0 / eff - PSY.set_P_ref!(tg, P_ref) #Update Control Refs - set_P_ref(dynamic_device, P_ref) + PSY.set_P_ref!(tg, P_ref) + device_parameters[P_ref_ix] = P_ref return end function initialize_tg!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGTypeI, P}}, inner_vars::AbstractVector, @@ -23,17 +28,16 @@ function initialize_tg!( #Get mechanical torque to SyncMach τm0 = inner_vars[τm_var] - #Get Parameters + tg = PSY.get_prime_mover(dynamic_device) - inv_R = PSY.get_R(tg) < eps() ? 0.0 : (1.0 / PSY.get_R(tg)) - Tc = PSY.get_Tc(tg) - T3 = PSY.get_T3(tg) - T4 = PSY.get_T4(tg) - T5 = PSY.get_T5(tg) - V_min, V_max = PSY.get_valve_position_limits(tg) + #Get Parameters + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.TGTypeI) + internal_params = @view device_parameters[local_ix_params] + R, _, Tc, T3, T4, T5, V_min, V_max = internal_params + inv_R = R < eps() ? 0.0 : (1.0 / R) #Get References - ω_ref = get_ω_ref(dynamic_device) + ω_ref = device_parameters[ω_ref_ix] ω0 = 1.0 function f!(out, x) P_ref = x[1] @@ -62,7 +66,7 @@ function initialize_tg!( sol_x0 = sol.zero #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - set_P_ref(dynamic_device, sol_x0[1]) + device_parameters[P_ref_ix] = sol_x0[1] #Update states tg_ix = get_local_state_ix(dynamic_device, PSY.TGTypeI) tg_states = @view device_states[tg_ix] @@ -80,6 +84,7 @@ end function initialize_tg!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGTypeII, P}}, inner_vars::AbstractVector, @@ -89,10 +94,11 @@ function initialize_tg!( τm0 = inner_vars[τm_var] #Get parameters tg = PSY.get_prime_mover(dynamic_device) - inv_R = PSY.get_R(tg) < eps() ? 0.0 : (1.0 / PSY.get_R(tg)) - T1 = PSY.get_T1(tg) - T2 = PSY.get_T2(tg) - ω_ref = get_ω_ref(dynamic_device) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.TGTypeII) + internal_params = @view device_parameters[local_ix_params] + R, T1, T2 = internal_params + inv_R = R < eps() ? 0.0 : (1.0 / R) + ω_ref = device_parameters[ω_ref_ix] ω0 = ω_ref function f!(out, x) @@ -109,7 +115,7 @@ function initialize_tg!( sol_x0 = sol.zero #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - set_P_ref(dynamic_device, sol_x0[1]) + device_parameters[P_ref_ix] = sol_x0[1] #Update states tg_ix = get_local_state_ix(dynamic_device, PSY.TGTypeII) tg_states = @view device_states[tg_ix] @@ -120,6 +126,7 @@ end function initialize_tg!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.GasTG, P}}, inner_vars::AbstractVector, @@ -128,13 +135,13 @@ function initialize_tg!( #Get mechanical torque to SyncMach τm0 = inner_vars[τm_var] Δω = 0.0 - #Get parameters + tg = PSY.get_prime_mover(dynamic_device) - inv_R = PSY.get_R(tg) < eps() ? 0.0 : (1.0 / PSY.get_R(tg)) - D_turb = PSY.get_D_turb(tg) - AT = PSY.get_AT(tg) - KT = PSY.get_Kt(tg) - V_min, V_max = PSY.get_V_lim(tg) + #Get parameters + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.TGTypeI) + internal_params = @view device_parameters[local_ix_params] + R, _, _, _, AT, Kt, V_min, V_max, D_turb = internal_params + inv_R = R < eps() ? 0.0 : (1.0 / R) function f!(out, x) P_ref = x[1] @@ -142,7 +149,7 @@ function initialize_tg!( x_g2 = x[3] x_g3 = x[4] - x_in = min((P_ref - inv_R * Δω), (AT + KT * (AT - x_g3))) + x_in = min((P_ref - inv_R * Δω), (AT + Kt * (AT - x_g3))) out[1] = (x_in - x_g1) #dx_g1/dt x_g1_sat = V_min < x_g1 < V_max ? x_g1 : max(V_min, min(V_max, x_g1)) out[2] = (x_g1_sat - x_g2) @@ -157,7 +164,7 @@ function initialize_tg!( sol_x0 = sol.zero #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - set_P_ref(dynamic_device, sol_x0[1]) + device_parameters[P_ref_ix] = sol_x0[1] #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] @@ -170,6 +177,7 @@ end function initialize_tg!( device_states, + device_parameters, ::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.SteamTurbineGov1, P}}, inner_vars::AbstractVector, @@ -178,14 +186,19 @@ function initialize_tg!( #Get mechanical torque to SyncMach τm0 = inner_vars[τm_var] Δω = 0.0 - #Get parameters + tg = PSY.get_prime_mover(dynamic_device) - inv_R = PSY.get_R(tg) < eps() ? 0.0 : (1.0 / PSY.get_R(tg)) - T1 = PSY.get_T1(tg) - T2 = PSY.get_T2(tg) - T3 = PSY.get_T3(tg) - V_min, V_max = PSY.get_valve_position_limits(tg) - D_T = PSY.get_D_T(tg) + #Get Parameters + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SteamTurbineGov1) + internal_params = @view device_parameters[local_ix_params] + R, + T1, + V_min, + V_max, + T2, + T3, + D_T = internal_params + inv_R = R < eps() ? 0.0 : (1.0 / R) function f!(out, x) P_ref = x[1] @@ -214,7 +227,7 @@ function initialize_tg!( end #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - set_P_ref(dynamic_device, sol_x0[1]) + device_parameters[P_ref_ix] = sol_x0[1] #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] @@ -226,6 +239,7 @@ end function initialize_tg!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.HydroTurbineGov, P}}, inner_vars::AbstractVector, @@ -234,17 +248,23 @@ function initialize_tg!( #Get mechanical torque to SyncMach τm0 = inner_vars[τm_var] Δω = 0.0 - #Get parameters + tg = PSY.get_prime_mover(dynamic_device) - R = PSY.get_R(tg) - r = PSY.get_r(tg) - Tr = PSY.get_Tr(tg) - #Gate velocity limits not implemented - #VELM = PSY.get_VELM(tg) - G_min, G_max = PSY.get_gate_position_limits(tg) - At = PSY.get_At(tg) - D_T = PSY.get_D_T(tg) - q_nl = PSY.get_q_nl(tg) + #Get Parameters + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.HydroTurbineGov) + internal_params = @view device_parameters[local_ix_params] + R, + r, + Tr, + Tf, + Tg, + VELM, #Gate velocity limits not implemented + G_min, + G_max, + Tw, + At, + D_T, + q_nl = internal_params function f!(out, x) P_ref = x[1] @@ -278,7 +298,7 @@ function initialize_tg!( end #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - set_P_ref(dynamic_device, sol_x0[1]) + device_parameters[P_ref_ix] = sol_x0[1] #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index 76592cf33..58af1a62c 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -1,60 +1,64 @@ function initialize_dynamic_device!( dynamic_device::DynamicWrapper{DynG}, - static::PSY.StaticInjection, initial_inner_vars::AbstractVector, + parameters::AbstractVector, + states::AbstractVector, ) where {DynG <: PSY.DynamicGenerator} #Obtain States - device_states = zeros(PSY.get_n_states(dynamic_device)) - + static = get_static_device(dynamic_device) #Initialize Machine and Shaft: δ and ω - initialize_mach_shaft!(device_states, static, dynamic_device, initial_inner_vars) + initialize_mach_shaft!(states, parameters, static, dynamic_device, initial_inner_vars) #Initialize extra Shaft states - initialize_shaft!(device_states, static, dynamic_device, initial_inner_vars) + initialize_shaft!(states, parameters, static, dynamic_device, initial_inner_vars) #Initialize AVR - initialize_avr!(device_states, static, dynamic_device, initial_inner_vars) + initialize_avr!(states, parameters, static, dynamic_device, initial_inner_vars) #Initialize TG - initialize_tg!(device_states, static, dynamic_device, initial_inner_vars) + initialize_tg!(states, parameters, static, dynamic_device, initial_inner_vars) #Initialize PSS - initialize_pss!(device_states, static, dynamic_device, initial_inner_vars) - - return device_states + initialize_pss!(states, parameters, static, dynamic_device, initial_inner_vars) + return end function initialize_dynamic_device!( dynamic_device::DynamicWrapper{DynI}, - static::PSY.StaticInjection, initial_inner_vars::AbstractVector, + parameters::AbstractVector, + states::AbstractVector, ) where {DynI <: PSY.DynamicInverter} - #Obtain States - device_states = zeros(PSY.get_n_states(dynamic_device)) + static = get_static_device(dynamic_device) #Initialize Machine and Shaft: V and I - initialize_filter!(device_states, static, dynamic_device, initial_inner_vars) + initialize_filter!(states, parameters, static, dynamic_device, initial_inner_vars) #Initialize freq estimator initialize_frequency_estimator!( - device_states, + states, + parameters, static, dynamic_device, initial_inner_vars, ) #Initialize OuterLoop - initialize_outer!(device_states, static, dynamic_device, initial_inner_vars) + initialize_outer!(states, parameters, static, dynamic_device, initial_inner_vars) #Initialize DCside - initialize_DCside!(device_states, static, dynamic_device, initial_inner_vars) + initialize_DCside!(states, parameters, static, dynamic_device, initial_inner_vars) #Initialize Converter - initialize_converter!(device_states, static, dynamic_device, initial_inner_vars) + initialize_converter!(states, parameters, static, dynamic_device, initial_inner_vars) #Initialize InnerLoop - initialize_inner!(device_states, static, dynamic_device, initial_inner_vars) - return device_states + initialize_inner!(states, parameters, static, dynamic_device, initial_inner_vars) + return end -function initialize_static_device!(::StaticLoadWrapper) +function initialize_static_device!( + ::StaticLoadWrapper, + local_parameters::AbstractArray{V}, +) where {V <: ACCEPTED_REAL_TYPES} return end function initialize_static_device!( device::StaticWrapper{PSY.Source, T}, -) where {T <: BusCategory} + local_parameters::AbstractArray{U}, +) where {T <: BusCategory, U <: ACCEPTED_REAL_TYPES} #PowerFlow Data P0 = PSY.get_active_power(device) Q0 = PSY.get_reactive_power(device) @@ -91,19 +95,19 @@ function initialize_static_device!( θ_internal = atan(sol_x0[2], sol_x0[1]) PSY.set_internal_voltage!(device.device, V_internal) PSY.set_internal_angle!(device.device, θ_internal) - set_V_ref(device, PSY.get_internal_voltage(device.device)) - set_θ_ref(device, PSY.get_internal_angle(device.device)) + local_parameters[3] = V_internal + local_parameters[4] = θ_internal end return end function initialize_dynamic_device!( dynamic_device::DynamicWrapper{PSY.PeriodicVariableSource}, - source::PSY.Source, - ::AbstractVector, + initial_inner_vars::AbstractVector, + parameters::AbstractVector, + device_states::AbstractVector, ) - device_states = zeros(PSY.get_n_states(dynamic_device)) - + source = get_static_device(dynamic_device) #PowerFlow Data P0 = PSY.get_active_power(source) Q0 = PSY.get_reactive_power(source) @@ -139,15 +143,15 @@ function initialize_dynamic_device!( θ_internal = atan(sol_x0[2], sol_x0[1]) V_internal_freqs = 0.0 - V_freqs = PSY.get_internal_voltage_frequencies(get_device(dynamic_device)) - V_coeff = PSY.get_internal_voltage_coefficients(get_device(dynamic_device)) + V_freqs = PSY.get_internal_voltage_frequencies(get_dynamic_device(dynamic_device)) + V_coeff = PSY.get_internal_voltage_coefficients(get_dynamic_device(dynamic_device)) for (ix, ω) in enumerate(V_freqs) V_internal_freqs += V_coeff[ix][2] #sin(0) = 0; cos(0)=1 end θ_internal_freqs = 0.0 - θ_freqs = PSY.get_internal_angle_frequencies(get_device(dynamic_device)) - θ_coeff = PSY.get_internal_angle_coefficients(get_device(dynamic_device)) + θ_freqs = PSY.get_internal_angle_frequencies(get_dynamic_device(dynamic_device)) + θ_coeff = PSY.get_internal_angle_coefficients(get_dynamic_device(dynamic_device)) for (ix, ω) in enumerate(θ_freqs) θ_internal_freqs += θ_coeff[ix][2] #sin(0) = 0; cos(0)=1 end @@ -156,14 +160,15 @@ function initialize_dynamic_device!( device_states[1] = V_internal device_states[2] = θ_internal - PSY.set_internal_voltage_bias!(get_device(dynamic_device), V_internal_bias) - PSY.set_internal_angle_bias!(get_device(dynamic_device), θ_internal_bias) + PSY.set_internal_voltage_bias!(get_dynamic_device(dynamic_device), V_internal_bias) + PSY.set_internal_angle_bias!(get_dynamic_device(dynamic_device), θ_internal_bias) end - return device_states + return end -function initialize_dynamic_device!(branch::BranchWrapper) - device_states = zeros(PSY.get_n_states(branch)) +function initialize_dynamic_device!(branch::BranchWrapper, + parameters::AbstractVector, + device_states::AbstractVector) #PowerFlow Data arc = PSY.get_arc(branch) Vm_from = PSY.get_magnitude(PSY.get_from(arc)) @@ -174,8 +179,7 @@ function initialize_dynamic_device!(branch::BranchWrapper) V_I_from = Vm_from * sin(θ_from) V_R_to = Vm_to * cos(θ_to) V_I_to = Vm_to * sin(θ_to) - R = PSY.get_r(branch) - X = PSY.get_x(branch) + R, X = parameters Zmag_sq = R^2 + X^2 #Compute Current I_R = R * (V_R_from - V_R_to) / Zmag_sq + X * (V_I_from - V_I_to) / Zmag_sq @@ -183,31 +187,38 @@ function initialize_dynamic_device!(branch::BranchWrapper) #Update Current device_states[1] = I_R device_states[2] = I_I - return device_states + return end function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.SingleCageInductionMachine}, - device::PSY.StaticInjection, ::AbstractVector, + device_parameters::AbstractVector, + device_states::AbstractVector, ) Sbase = get_system_base_power(dynamic_wrapper) - - #Obtain States - device_states = zeros(PSY.get_n_states(dynamic_wrapper)) + device = get_static_device(dynamic_wrapper) # Get parameters - dynamic_device = get_device(dynamic_wrapper) - R_s = PSY.get_R_s(dynamic_device) - X_ls = PSY.get_X_ls(dynamic_device) - R_r = PSY.get_R_r(dynamic_device) - X_lr = PSY.get_X_lr(dynamic_device) - A = PSY.get_A(dynamic_device) - B = PSY.get_B(dynamic_device) - C = PSY.get_C(dynamic_device) - base_power = PSY.get_base_power(dynamic_device) - X_ad = PSY.get_X_ad(dynamic_device) - X_aq = PSY.get_X_aq(dynamic_device) + dynamic_device = get_dynamic_device(dynamic_wrapper) + _, + _, + _, + _, + R_s, + R_r, + X_ls, + X_lr, + X_m, + H, + A, + B, + base_power, + C, + τ_m0, + B_sh, + X_ad, + X_aq = device_parameters #PowerFlow Data if isa(device, PSY.StandardLoad) @@ -279,36 +290,46 @@ function initialize_dynamic_device!( device_states[4] = sol_x0[7] # ψ_dr device_states[5] = sol_x0[8] # ωr # update τ_ref and B_sh + device_parameters[16] = sol_x0[3] # B_sh PSY.set_B_shunt!(dynamic_device, sol_x0[3]) # B_sh - #set_B_shunt(dynamic_device, sol_x0[3]) # B_sh + device_parameters[15] = sol_x0[9] # τ_m0 PSY.set_τ_ref!(dynamic_device, sol_x0[9]) # τ_m0 - set_P_ref(dynamic_wrapper, sol_x0[9]) # τ_m0 + device_parameters[P_ref_ix] = sol_x0[9] # τ_m0 end - return device_states + return end function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.SimplifiedSingleCageInductionMachine}, - device::PSY.StaticInjection, ::AbstractVector, + device_parameters::AbstractVector, + device_states::AbstractVector, ) Sbase = get_system_base_power(dynamic_wrapper) - #Obtain States - device_states = zeros(PSY.get_n_states(dynamic_wrapper)) - # Get parameters - dynamic_device = get_device(dynamic_wrapper) - R_s = PSY.get_R_s(dynamic_device) - X_m = PSY.get_X_m(dynamic_device) - R_r = PSY.get_R_r(dynamic_device) - A = PSY.get_A(dynamic_device) - B = PSY.get_B(dynamic_device) - C = PSY.get_C(dynamic_device) - base_power = PSY.get_base_power(dynamic_device) - X_ss = PSY.get_X_ss(dynamic_device) - X_rr = PSY.get_X_rr(dynamic_device) - X_p = PSY.get_X_p(dynamic_device) + dynamic_device = get_dynamic_device(dynamic_wrapper) + device = get_static_device(dynamic_wrapper) + #Get parameters + _, + _, + _, + _, + R_s, + R_r, + X_ls, + X_lr, + X_m, + H, + A, + B, + base_power, + C, + τ_m0, + B_sh, + X_ss, + X_rr, + X_p = device_parameters #PowerFlow Data if isa(device, PSY.StandardLoad) @@ -382,38 +403,44 @@ function initialize_dynamic_device!( device_states[3] = sol_x0[10] # ωr # update τ_ref and B_sh PSY.set_B_shunt!(dynamic_device, sol_x0[5]) # B_sh - #set_B_shunt(dynamic_device, sol_x0[5]) # B_sh + device_parameters[16] = sol_x0[5] # B_sh PSY.set_τ_ref!(dynamic_device, sol_x0[11]) # τ_m0 - set_P_ref(dynamic_wrapper, sol_x0[11]) # τ_m0 + device_parameters[15] = sol_x0[11] # τ_m0 + device_parameters[P_ref_ix] = sol_x0[11] # τ_m0 end return device_states end function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.CSVGN1}, - device::PSY.StaticInjection, ::AbstractVector, + device_parameters::AbstractVector, + device_states::AbstractVector, ) Sbase = get_system_base_power(dynamic_wrapper) - - # Obtain States - device_states = zeros(PSY.get_n_states(dynamic_wrapper)) - + device = get_static_device(dynamic_wrapper) # Get parameters - dynamic_device = get_device(dynamic_wrapper) - K = PSY.get_K(dynamic_device) - T1 = PSY.get_T1(dynamic_device) - T2 = PSY.get_T2(dynamic_device) - T3 = PSY.get_T3(dynamic_device) - T4 = PSY.get_T4(dynamic_device) - T5 = PSY.get_T5(dynamic_device) - Rmin = PSY.get_Rmin(dynamic_device) - Vmax = PSY.get_Vmax(dynamic_device) - Vmin = PSY.get_Vmin(dynamic_device) - Cbase = PSY.get_CBase(dynamic_device) + dynamic_device = get_dynamic_device(dynamic_wrapper) + Q_ref, + V_ref, + ω_ref, + P_ref, + K, + T1, + T2, + T3, + T4, + T5, + Rmin, + Vmax, + Vmin, + Cbase, + Mbase, + R_th, + X_th = device_parameters + # FIXME: base_power is changed to system's base_power when a CSVGN1 is attached to a Source using add_component!() # Temporarily, to avoid that, set_dynamic_injector!() could be used - Mbase = PSY.get_base_power(dynamic_device) Rbase = Mbase # PowerFlow Data @@ -425,7 +452,7 @@ function initialize_dynamic_device!( V_ref0 = V_abs - (Cbase / Sbase - Y) * 1 / K * Sbase / Mbase # update V_ref - set_V_ref(dynamic_wrapper, V_ref0) + device_parameters[V_ref_ix] = V_ref0 thy = K * (V_abs - V_ref0) vr2 = thy @@ -447,25 +474,34 @@ end function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.ActiveConstantPowerLoad}, - device::PSY.StaticInjection, ::AbstractVector, + device_parameters::AbstractVector, + device_states::AbstractVector, ) + device = get_static_device(dynamic_wrapper) Sbase = get_system_base_power(dynamic_wrapper) - #Obtain States - device_states = zeros(PSY.get_n_states(dynamic_wrapper)) - - # Get parameters - dynamic_device = get_device(dynamic_wrapper) - r_load = PSY.get_r_load(dynamic_device) - rf = PSY.get_rf(dynamic_device) - lf = PSY.get_lf(dynamic_device) - cf = PSY.get_cf(dynamic_device) - rg = PSY.get_rg(dynamic_device) - lg = PSY.get_lg(dynamic_device) - kiv = PSY.get_kiv(dynamic_device) - kic = PSY.get_kic(dynamic_device) - base_power = PSY.get_base_power(dynamic_device) + dynamic_device = get_dynamic_device(dynamic_wrapper) + + #Get parameters + Q_ref, + V_ref, + ω_ref, + P_ref, + r_load, + _, + rf, + lf, + cf, + rg, + lg, + _, + _, + _, + kiv, + _, + kic, + base_power = device_parameters #PowerFlow Data if isa(device, PSY.StandardLoad) @@ -545,20 +581,20 @@ function initialize_dynamic_device!( # update V_ref PSY.set_V_ref!(dynamic_device, V_ref0) - set_V_ref(dynamic_wrapper, V_ref0) - set_Q_ref(dynamic_wrapper, sol_x0[5]) + device_parameters[V_ref_ix] = V_ref0 + device_parameters[Q_ref_ix] = sol_x0[5] end return device_states end function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.AggregateDistributedGenerationA}, - static::PSY.StaticInjection, - initial_inner_vars::AbstractVector, + ::AbstractVector, + device_parameters::AbstractVector, + device_states::AbstractVector, ) - device_states = zeros(PSY.get_n_states(dynamic_wrapper)) - dynamic_device = get_device(dynamic_wrapper) - + dynamic_device = get_dynamic_device(dynamic_wrapper) + static = get_static_device(dynamic_wrapper) #Get PowerFlow Data P0 = PSY.get_active_power(static) Q0 = PSY.get_reactive_power(static) @@ -629,7 +665,7 @@ function initialize_dynamic_device!( #See Note 2 on PSSE Documentation Vref0 = PSY.get_V_ref(dynamic_device) - K_qv = PSY.get_K_qv(dynamic_device) + K_qv = device_parameters[9] (dbd1, dbd2) = PSY.get_dbd_pnts(dynamic_device) if Vref0 == 0.0 Vref = Vmeas @@ -639,12 +675,12 @@ function initialize_dynamic_device!( Vref = Vmeas end - set_P_ref(dynamic_wrapper, Pref) + device_parameters[P_ref_ix] = Pref PSY.set_P_ref!(dynamic_device, Pref) - set_Q_ref(dynamic_wrapper, Qref) - set_V_ref(dynamic_wrapper, Vref) - set_ω_ref(dynamic_wrapper, Freq_ref) + device_parameters[Q_ref_ix] = Qref + device_parameters[V_ref_ix] = Vref + device_parameters[ω_ref_ix] = Freq_ref PSY.set_Pfa_ref!(dynamic_device, pfaref) - - return device_states + device_parameters[33] = pfaref + return end diff --git a/src/initialization/inverter_components/init_DCside.jl b/src/initialization/inverter_components/init_DCside.jl index 95fe06f56..bbf8c6784 100644 --- a/src/initialization/inverter_components/init_DCside.jl +++ b/src/initialization/inverter_components/init_DCside.jl @@ -1,5 +1,6 @@ function initialize_DCside!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, IC, PSY.FixedDCSource, P, F, L}, @@ -13,8 +14,9 @@ function initialize_DCside!( F <: PSY.Filter, L <: Union{Nothing, PSY.InverterLimiter}, } - + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.FixedDCSource) + internal_params = @view device_parameters[local_ix_params] #Update inner_vars - inner_vars[Vdc_var] = PSY.get_voltage(PSY.get_dc_source(dynamic_device)) + inner_vars[Vdc_var] = internal_params[1] return end diff --git a/src/initialization/inverter_components/init_converter.jl b/src/initialization/inverter_components/init_converter.jl index e4538b3a6..e276ffadb 100644 --- a/src/initialization/inverter_components/init_converter.jl +++ b/src/initialization/inverter_components/init_converter.jl @@ -1,5 +1,6 @@ function initialize_converter!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{PSY.AverageConverter, O, IC, DC, P, F, L}, @@ -16,6 +17,7 @@ function initialize_converter!( function initialize_converter!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{PSY.RenewableEnergyConverterTypeA, O, IC, DC, P, F, L}, @@ -42,9 +44,29 @@ function initialize_converter!( #Reference Transformation Ip = Ip_external * cos(-θ) - Iq_external * sin(-θ) Iq = Ip_external * sin(-θ) + Iq_external * cos(-θ) + + #Get Converter parameters converter = PSY.get_converter(dynamic_device) - Io_lim = PSY.get_Io_lim(converter) - Vo_lim = PSY.get_Vo_lim(converter) + local_ix_params = + get_local_parameter_ix(dynamic_device, PSY.RenewableEnergyConverterTypeA) + internal_params = @view device_parameters[local_ix_params] + T_g, + Rrpwr, + Brkpt, + Zerox, + Lvpl1, + Vo_lim, + Lv_pnt0, + Lv_pnt1, + Io_lim, + T_fltr, + K_hv, + Iqr_min, + Iqr_max, + Accel, + Q_ref, + R_source, + X_source = internal_params # Lv_pnt0 is unused in the initialization _, Lv_pnt1 = PSY.get_Lv_pnts(converter) @@ -71,6 +93,7 @@ end function initialize_converter!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{PSY.RenewableEnergyVoltageConverterTypeA, O, IC, DC, P, F, L}, diff --git a/src/initialization/inverter_components/init_filter.jl b/src/initialization/inverter_components/init_filter.jl index c59e391c7..c15cc6725 100644 --- a/src/initialization/inverter_components/init_filter.jl +++ b/src/initialization/inverter_components/init_filter.jl @@ -1,5 +1,6 @@ function initialize_filter!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicInverter{C, O, IC, DC, P, PSY.LCLFilter, L}}, inner_vars::AbstractVector, @@ -25,15 +26,12 @@ function initialize_filter!( Ii_filter = imag(I) #Get Parameters - filter = PSY.get_filter(dynamic_device) - lf = PSY.get_lf(filter) - rf = PSY.get_rf(filter) - cf = PSY.get_cf(filter) - lg = PSY.get_lg(filter) - rg = PSY.get_rg(filter) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.LCLFilter) + internal_params = @view device_parameters[local_ix_params] + lf, rf, cf, lg, rg = internal_params #Set parameters - ω_sys = get_ω_ref(dynamic_device) + ω_sys = device_parameters[ω_ref_ix] #To solve Vr_cnv, Vi_cnv, Ir_cnv, Ii_cnv, Vr_filter, Vi_filter function f!(out, x) @@ -92,11 +90,21 @@ end function initialize_filter!( device_states, + device_parameters, static::PSY.StaticInjection, - dynamic_device::DynamicWrapper{PSY.DynamicInverter{C, O, IC, DC, P, PSY.RLFilter, L}}, + dynamic_device::DynamicWrapper{ + PSY.DynamicInverter{ + PSY.RenewableEnergyConverterTypeA, + O, + IC, + DC, + P, + PSY.RLFilter, + L, + }, + }, inner_vars::AbstractVector, ) where { - C <: PSY.Converter, O <: PSY.OuterControl, IC <: PSY.InnerControl, DC <: PSY.DCSource, @@ -120,9 +128,10 @@ function initialize_filter!( I_I = imag(I) #Get Parameters - filt = PSY.get_filter(dynamic_device) - rf = PSY.get_rf(filt) - lf = PSY.get_lf(filt) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.RLFilter) + internal_params = @view device_parameters[local_ix_params] + rf, lf = internal_params + converter = PSY.get_converter(dynamic_device) R_source = PSY.get_R_source(converter) X_source = PSY.get_X_source(converter) diff --git a/src/initialization/inverter_components/init_frequency_estimator.jl b/src/initialization/inverter_components/init_frequency_estimator.jl index 3901e7905..adca14c22 100644 --- a/src/initialization/inverter_components/init_frequency_estimator.jl +++ b/src/initialization/inverter_components/init_frequency_estimator.jl @@ -1,5 +1,6 @@ function initialize_frequency_estimator!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicInverter{C, O, IC, DC, PSY.KauraPLL, F, L}}, inner_vars::AbstractVector, @@ -15,9 +16,10 @@ function initialize_frequency_estimator!( Vi_filter = inner_vars[Vi_filter_var] #Get parameters - pll_control = PSY.get_freq_estimator(dynamic_device) - kp_pll = PSY.get_kp_pll(pll_control) - ki_pll = PSY.get_ki_pll(pll_control) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.KauraPLL) + internal_params = @view device_parameters[local_ix_params] + _, kp_pll, ki_pll = internal_params + ω_ref = device_parameters[ω_ref_ix] #Get initial guess θ0_pll = atan(Vi_filter, Vr_filter) @@ -58,13 +60,14 @@ function initialize_frequency_estimator!( pll_states[4] = sol_x0[4] #Update guess of frequency estimator - inner_vars[ω_freq_estimator_var] = get_ω_ref(dynamic_device) + inner_vars[ω_freq_estimator_var] = ω_ref inner_vars[θ_freq_estimator_var] = sol_x0[4] end end function initialize_frequency_estimator!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, IC, DC, PSY.ReducedOrderPLL, F, L}, @@ -120,7 +123,7 @@ function initialize_frequency_estimator!( pll_states[3] = sol_x0[3] #Update guess of frequency estimator - inner_vars[ω_freq_estimator_var] = get_ω_ref(dynamic_device) + inner_vars[ω_freq_estimator_var] = device_parameters[ω_ref_ix] inner_vars[θ_freq_estimator_var] = sol_x0[3] end return @@ -128,6 +131,7 @@ end function initialize_frequency_estimator!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, IC, DC, PSY.FixedFrequency, F, L}, @@ -142,8 +146,9 @@ function initialize_frequency_estimator!( L <: Union{Nothing, PSY.InverterLimiter}, } #Get parameters - pll_control = PSY.get_freq_estimator(dynamic_device) - frequency = PSY.get_frequency(pll_control) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.FixedFrequency) + internal_params = @view device_parameters[local_ix_params] + frequency = internal_params[1] #Update guess of frequency estimator inner_vars[ω_freq_estimator_var] = frequency diff --git a/src/initialization/inverter_components/init_inner.jl b/src/initialization/inverter_components/init_inner.jl index 5a4184a6e..a80419f3a 100644 --- a/src/initialization/inverter_components/init_inner.jl +++ b/src/initialization/inverter_components/init_inner.jl @@ -1,8 +1,9 @@ function initialize_inner!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ - PSY.DynamicInverter{C, O, PSY.VoltageModeControl, DC, P, F, L}, + PSY.DynamicInverter{C, O, PSY.VoltageModeControl, DC, P, PSY.LCLFilter, L}, }, inner_vars::AbstractVector, ) where { @@ -10,7 +11,6 @@ function initialize_inner!( O <: PSY.OuterControl, DC <: PSY.DCSource, P <: PSY.FrequencyEstimator, - F <: PSY.Filter, L <: Union{Nothing, PSY.InverterLimiter}, } @@ -24,7 +24,7 @@ function initialize_inner!( Vi_filter = device_states[external_ix[6]] #Obtain inner variables for component - ω_oc = get_ω_ref(dynamic_device) + ω_oc = device_parameters[ω_ref_ix] θ0_oc = inner_vars[θ_oc_var] Vdc = inner_vars[Vdc_var] @@ -33,22 +33,15 @@ function initialize_inner!( Vi_cnv0 = inner_vars[Vi_cnv_var] #Get Voltage Controller parameters - inner_control = PSY.get_inner_control(dynamic_device) filter = PSY.get_filter(dynamic_device) - kpv = PSY.get_kpv(inner_control) - kiv = PSY.get_kiv(inner_control) - kffi = PSY.get_kffi(inner_control) - cf = PSY.get_cf(filter) - rv = PSY.get_rv(inner_control) - lv = PSY.get_lv(inner_control) + filter_ix_params = get_local_parameter_ix(dynamic_device, typeof(filter)) + filter_params = @view device_parameters[filter_ix_params] + cf = filter_params[3] + lf = filter_params[1] - #Get Current Controller parameters - kpc = PSY.get_kpc(inner_control) - kic = PSY.get_kic(inner_control) - kffv = PSY.get_kffv(inner_control) - lf = PSY.get_lf(filter) - ωad = PSY.get_ωad(inner_control) - kad = PSY.get_kad(inner_control) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.VoltageModeControl) + internal_params = @view device_parameters[local_ix_params] + kpv, kiv, kffv, rv, lv, kpc, kic, kffi, ωad, kad = internal_params function f!(out, x) θ_oc = x[1] @@ -116,7 +109,7 @@ function initialize_inner!( #Assumes that angle is in second position outer_states[1] = sol_x0[1] inner_vars[θ_oc_var] = sol_x0[1] - set_V_ref(dynamic_device, sol_x0[2]) + device_parameters[V_ref_ix] = sol_x0[2] PSY.set_V_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), sol_x0[2], @@ -145,6 +138,7 @@ end function initialize_inner!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, PSY.CurrentModeControl, DC, P, F, L}, @@ -168,7 +162,7 @@ function initialize_inner!( Vi_filter = device_states[external_ix[6]] #Obtain inner variables for component - ω_oc = get_ω_ref(dynamic_device) + ω_oc = device_parameters[ω_ref_ix] θ0_oc = inner_vars[θ_freq_estimator_var] Vdc = inner_vars[Vdc_var] Id_cnv_ref = inner_vars[Id_oc_var] @@ -231,6 +225,7 @@ end function initialize_inner!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, PSY.RECurrentControlB, DC, P, F, L}, @@ -256,7 +251,21 @@ function initialize_inner!( inner_control = PSY.get_inner_control(dynamic_device) Q_Flag = PSY.get_Q_Flag(inner_control) PQ_Flag = PSY.get_PQ_Flag(inner_control) - + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.RECurrentControlB) + internal_params = @view device_parameters[local_ix_params] + Vdip_min, + Vdip_max, + T_rv, + dbd1, + dbd2, + K_qv, + I_ql1, + I_qh1, + V_ref0, + K_vp, + K_vi, + T_iq, + I_max = internal_params Ip_min, Ip_max, Iq_min, Iq_max = current_limit_logic(inner_control, Val(PQ_Flag), V_t, Ip_oc, Iq_cmd) @@ -290,8 +299,8 @@ function initialize_inner!( #Update additional variables # Based on PSS/E manual, if user does not provide V_ref0, then # V_ref0 is considered to be the output voltage of the PF solution - if PSY.get_V_ref0(inner_control) == 0.0 - PSY.set_V_ref0!(inner_control, V_t) + if V_ref0 == 0.0 + internal_params[9] = V_t end return end diff --git a/src/initialization/inverter_components/init_outer.jl b/src/initialization/inverter_components/init_outer.jl index 33f2163e3..511a4d39e 100644 --- a/src/initialization/inverter_components/init_outer.jl +++ b/src/initialization/inverter_components/init_outer.jl @@ -1,5 +1,6 @@ function initialize_outer!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -36,6 +37,7 @@ function initialize_outer!( Vi_cnv = inner_vars[Vi_cnv_var] θ0_oc = atan(Vi_cnv, Vr_cnv) + ω_ref = device_parameters[ω_ref_ix] #Obtain additional expressions p_elec_out = Ir_filter * Vr_filter + Ii_filter * Vi_filter q_elec_out = -Ii_filter * Vr_filter + Ir_filter * Vi_filter @@ -49,24 +51,25 @@ function initialize_outer!( ) outer_states = @view device_states[outer_ix] outer_states[1] = θ0_oc #θ_oc - outer_states[2] = get_ω_ref(dynamic_device) #ω + outer_states[2] = ω_ref outer_states[3] = q_elec_out #qm #Update inner vars inner_vars[θ_oc_var] = θ0_oc - inner_vars[ω_oc_var] = get_ω_ref(dynamic_device) - #Update Q_ref. Initialization assumes q_ref = q_elec_out of PF solution - set_P_ref(dynamic_device, p_elec_out) + inner_vars[ω_oc_var] = ω_ref + device_parameters[P_ref_ix] = p_elec_out PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - set_Q_ref(dynamic_device, q_elec_out) + #Update Q_ref. Initialization assumes q_ref = q_elec_out of PF solution + device_parameters[Q_ref_ix] = q_elec_out return end function initialize_outer!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -121,18 +124,19 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc - inner_vars[ω_oc_var] = get_ω_ref(dynamic_device) + inner_vars[ω_oc_var] = device_parameters[ω_ref_ix] #Update Q_ref. Initialization assumes q_ref = q_elec_out of PF solution - set_P_ref(dynamic_device, p_elec_out) + device_parameters[P_ref_ix] = p_elec_out PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - set_Q_ref(dynamic_device, q_elec_out) + device_parameters[Q_ref_ix] = q_elec_out end function initialize_outer!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -186,18 +190,19 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc - inner_vars[ω_oc_var] = get_ω_ref(dynamic_device) + inner_vars[ω_oc_var] = device_parameters[ω_ref_ix] #Update Q_ref. Initialization assumes q_ref = q_elec_out of PF solution - set_P_ref(dynamic_device, p_elec_out) + device_parameters[P_ref_ix] = p_elec_out PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - set_Q_ref(dynamic_device, q_elec_out) + device_parameters[Q_ref_ix] = q_elec_out end function initialize_outer!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -260,16 +265,16 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc - inner_vars[ω_oc_var] = get_ω_ref(dynamic_device) + inner_vars[ω_oc_var] = device_parameters[ω_ref_ix] inner_vars[Id_oc_var] = I_dq_cnv[d] inner_vars[Iq_oc_var] = I_dq_cnv[q] #Update Q_ref. Initialization assumes q_ref = q_elec_out from PF solution - set_P_ref(dynamic_device, p_elec_out) + device_parameters[P_ref_ix] = p_elec_out PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - set_Q_ref(dynamic_device, q_elec_out) + device_parameters[Q_ref_ix] = q_elec_out PSY.set_Q_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), q_elec_out, @@ -279,6 +284,7 @@ end function initialize_outer!( device_states, + device_parameters, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -322,7 +328,7 @@ function initialize_outer!( ## Set references Vm = V_t PSY.set_Q_ref!(PSY.get_converter(dynamic_device), q_elec_out) - set_Q_ref(dynamic_device, q_elec_out) + device_parameters[Q_ref_ix] = q_elec_out PSY.set_Q_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), q_elec_out, @@ -331,17 +337,18 @@ function initialize_outer!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - set_P_ref(dynamic_device, p_elec_out) + device_parameters[P_ref_ix] = p_elec_out PSY.set_V_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), Vm, ) - set_V_ref(dynamic_device, Vm) + device_parameters[V_ref_ix] = Vm #Get Outer Controller parameters - q_ref = get_Q_ref(dynamic_device) + q_ref = device_parameters[Q_ref_ix] outer_control = PSY.get_outer_control(dynamic_device) active_power_control = PSY.get_active_power_control(outer_control) + reactive_power_control = PSY.get_reactive_power_control(outer_control) Freq_Flag = PSY.get_Freq_Flag(active_power_control) #Frequency Flag #Set state counter for variable number of states due to flags @@ -360,9 +367,62 @@ function initialize_outer!( ) internal_states = @view device_states[local_ix] + #Get all parameters once + local_ix_params = get_local_parameter_ix( + dynamic_device, + PSY.OuterControl{ + PSY.ActiveRenewableControllerAB, + PSY.ReactiveRenewableControllerAB, + }, + ) + internal_params = @view device_parameters[local_ix_params] + active_n_params = get_n_params(active_power_control) + active_ix_range_params = 1:active_n_params + active_params = @view internal_params[active_ix_range_params] + reactive_n_params = get_n_params(reactive_power_control) + reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) + reactive_params = @view internal_params[reactive_ix_range_params] + K_pg, + K_ig, + T_p, + fdbd1, + fdbd2, + fe_min, + fe_max, + P_min, + P_max, + T_g, + D_dn, + D_up, + dP_min, + dP_max, + P_min_inner, + P_max_inner, + T_pord = active_params + T_fltr, + K_p, + K_i, + T_ft, + T_fv, + V_frz, # V_frz not implemented yet + R_c, + X_c, + K_c, + e_min, + e_max, + dbd1, + dbd2, + Q_min, + Q_max, + T_p, + Q_min_inner, + Q_max_inner, + V_min, + V_max, + K_qp, + K_qi = reactive_params + if Freq_Flag == 1 - #Obtain Parameters - K_ig = PSY.get_K_ig(active_power_control) #Update States internal_states[state_ct] = p_elec_out internal_states[state_ct + 1] = p_elec_out / K_ig @@ -387,9 +447,6 @@ function initialize_outer!( V_Flag = PSY.get_V_Flag(reactive_power_control) # Update references if Ref_Flag == 0 && PF_Flag == 0 && V_Flag == 1 - #Get Reactive Controller Parameters - K_i = PSY.get_K_i(reactive_power_control) - K_qi = PSY.get_K_qi(reactive_power_control) #Update states internal_states[state_ct] = q_elec_out internal_states[state_ct + 1] = q_elec_out / K_i @@ -400,7 +457,6 @@ function initialize_outer!( inner_vars[V_oc_var] = 0.0 inner_vars[Iq_oc_var] = q_elec_out / max(V_t, 0.01) elseif Ref_Flag == 0 && PF_Flag == 0 && V_Flag == 0 - K_i = PSY.get_K_i(reactive_power_control) #Update states internal_states[state_ct] = q_ref internal_states[state_ct + 1] = q_ref / K_i @@ -438,11 +494,6 @@ function initialize_outer!( inner_vars[Iq_oc_var] = q_elec_out / max(V_t, 0.01) elseif Ref_Flag == 1 && PF_Flag == 0 && V_Flag == 0 # TODO: Fix and debug this case when Q_Flag = 1 - K_i = PSY.get_K_i(reactive_power_control) - K_qi = PSY.get_K_qi(reactive_power_control) - K_c = PSY.get_K_c(reactive_power_control) - R_c = PSY.get_R_c(reactive_power_control) - X_c = PSY.get_R_c(reactive_power_control) VC_Flag = PSY.get_VC_Flag(reactive_power_control) V_reg = sqrt(Vr_filter^2 + Vi_filter^2) # Compute input to the compensated voltage filter diff --git a/src/models/branch.jl b/src/models/branch.jl index e33256836..f1b13dbf5 100644 --- a/src/models/branch.jl +++ b/src/models/branch.jl @@ -1,6 +1,7 @@ function branch!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r_from::T, voltage_i_from::T, voltage_r_to::T, @@ -15,6 +16,7 @@ function branch!( mdl_branch_ode!( device_states, output_ode, + device_parameters, voltage_r_from, voltage_i_from, voltage_r_to, @@ -32,6 +34,7 @@ end function branch!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r_from::T, voltage_i_from::T, voltage_r_to::T, @@ -46,6 +49,7 @@ function branch!( mdl_transformer_Lshape_ode!( device_states, output_ode, + device_parameters, voltage_r_from, voltage_i_from, voltage_r_to, diff --git a/src/models/device.jl b/src/models/device.jl index e6972ed7b..95053048d 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -18,6 +18,7 @@ end function device!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -38,21 +39,43 @@ function device!( sys_ω = global_vars[GLOBAL_VAR_SYS_FREQ_INDEX] #Update Inner Vars - _update_inner_vars!(device_states, output_ode, sys_ω, inner_vars, dynamic_device) + _update_inner_vars!( + device_states, + output_ode, + device_parameters, + sys_ω, + inner_vars, + dynamic_device, + ) #Obtain ODEs and Mechanical Power for Turbine Governor - mdl_tg_ode!(device_states, output_ode, inner_vars, sys_ω, dynamic_device) + mdl_tg_ode!( + device_states, + output_ode, + device_parameters, + inner_vars, + sys_ω, + dynamic_device, + ) #Obtain ODEs for PSS - mdl_pss_ode!(device_states, output_ode, inner_vars, sys_ω, dynamic_device) + mdl_pss_ode!( + device_states, + output_ode, + device_parameters, + inner_vars, + sys_ω, + dynamic_device, + ) #Obtain ODEs for AVR - mdl_avr_ode!(device_states, output_ode, inner_vars, dynamic_device) + mdl_avr_ode!(device_states, output_ode, device_parameters, inner_vars, dynamic_device) #Obtain ODEs for Machine mdl_machine_ode!( device_states, output_ode, + device_parameters, inner_vars, current_r, current_i, @@ -60,11 +83,19 @@ function device!( ) #Obtain ODEs for PSY.Shaft - mdl_shaft_ode!(device_states, output_ode, inner_vars, sys_ω, dynamic_device) + mdl_shaft_ode!( + device_states, + output_ode, + device_parameters, + inner_vars, + sys_ω, + dynamic_device, + ) return end function device!( + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -74,11 +105,12 @@ function device!( device::StaticWrapper{PSY.Source, U}, t, ) where {T <: ACCEPTED_REAL_TYPES, U <: BusCategory} - mdl_source!(voltage_r, voltage_i, current_r, current_i, device) + mdl_source!(device_parameters, voltage_r, voltage_i, current_r, current_i, device) return end function device!( + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -88,7 +120,7 @@ function device!( device::StaticLoadWrapper, t, ) where {T <: ACCEPTED_REAL_TYPES} - mdl_zip_load!(voltage_r, voltage_i, current_r, current_i, device) + mdl_zip_load!(device_parameters, voltage_r, voltage_i, current_r, current_i, device) return end @@ -135,6 +167,7 @@ end function device!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -157,31 +190,66 @@ function device!( inner_vars[Vi_inv_var] = voltage_i #Update V_ref - V_ref = get_V_ref(dynamic_device) + V_ref = device_parameters[V_ref_ix] inner_vars[V_oc_var] = V_ref #Update current inner_vars - _update_inner_vars!(device_states, output_ode, sys_ω, inner_vars, dynamic_device) + _update_inner_vars!( + device_states, + output_ode, + device_parameters, + sys_ω, + inner_vars, + dynamic_device, + ) #Obtain ODES for DC side - mdl_DCside_ode!(device_states, output_ode, sys_ω, inner_vars, dynamic_device) + mdl_DCside_ode!( + device_states, + output_ode, + device_parameters, + sys_ω, + inner_vars, + dynamic_device, + ) #Obtain ODEs for PLL - mdl_freq_estimator_ode!(device_states, output_ode, inner_vars, sys_ω, dynamic_device) + mdl_freq_estimator_ode!( + device_states, + output_ode, + device_parameters, + inner_vars, + sys_ω, + dynamic_device, + ) #Obtain ODEs for OuterLoop - mdl_outer_ode!(device_states, output_ode, inner_vars, sys_ω, dynamic_device) + mdl_outer_ode!( + device_states, + output_ode, + device_parameters, + inner_vars, + sys_ω, + dynamic_device, + ) #Obtain inner controller ODEs and modulation commands - mdl_inner_ode!(device_states, output_ode, inner_vars, dynamic_device) + mdl_inner_ode!(device_states, output_ode, device_parameters, inner_vars, dynamic_device) #Obtain converter relations - mdl_converter_ode!(device_states, output_ode, inner_vars, dynamic_device) + mdl_converter_ode!( + device_states, + output_ode, + device_parameters, + inner_vars, + dynamic_device, + ) #Obtain ODEs for output filter mdl_filter_ode!( device_states, output_ode, + device_parameters, current_r, current_i, inner_vars, @@ -212,6 +280,7 @@ end function device!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -221,19 +290,19 @@ function device!( dynamic_device::DynamicWrapper{PSY.PeriodicVariableSource}, t, ) where {T <: ACCEPTED_REAL_TYPES} - ω_θ = PSY.get_internal_angle_frequencies(get_device(dynamic_device)) - ω_V = PSY.get_internal_angle_frequencies(get_device(dynamic_device)) + ω_θ = PSY.get_internal_angle_frequencies(get_dynamic_device(dynamic_device)) + ω_V = PSY.get_internal_angle_frequencies(get_dynamic_device(dynamic_device)) dV = 0 for (ix, A) in - enumerate(PSY.get_internal_voltage_coefficients(get_device(dynamic_device))) + enumerate(PSY.get_internal_voltage_coefficients(get_dynamic_device(dynamic_device))) t <= 0 && continue dV += ω_V[ix] * (A[1] * cos(ω_V[ix] * t) - A[2] * sin(ω_V[ix] * t)) end dθ = 0 for (ix, A) in - enumerate(PSY.get_internal_angle_coefficients(get_device(dynamic_device))) + enumerate(PSY.get_internal_angle_coefficients(get_dynamic_device(dynamic_device))) t <= 0 && continue dθ += ω_θ[ix] * (A[1] * cos(ω_θ[ix] * t) - A[2] * sin(ω_θ[ix] * t)) end @@ -245,8 +314,8 @@ function device!( output_ode[2] = dθ #update current - R_th = PSY.get_R_th(get_device(dynamic_device)) - X_th = PSY.get_X_th(get_device(dynamic_device)) + R_th = PSY.get_R_th(get_dynamic_device(dynamic_device)) + X_th = PSY.get_X_th(get_dynamic_device(dynamic_device)) Zmag = R_th^2 + X_th^2 current_r[1] += R_th * (V_R - voltage_r[1]) / Zmag + X_th * (V_I - voltage_i[1]) / Zmag #in system pu flowing out current_i[1] += R_th * (V_I - voltage_i[1]) / Zmag - X_th * (V_R - voltage_r[1]) / Zmag #in system pu flowing out @@ -255,6 +324,7 @@ function device!( end function _update_inner_vars!( + ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, @@ -267,6 +337,7 @@ end function _update_inner_vars!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, P}}, @@ -297,16 +368,25 @@ function _update_inner_vars!( V_tI = inner_vars[VI_gen_var] #Get parameters - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xd_p = PSY.get_Xd_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) + machine_ix_params = get_local_parameter_ix(dynamic_device, typeof(machine)) + machine_params = @view device_parameters[machine_ix_params] + R, + Td0_p, + Td0_pp, + Tq0_p, + Tq0_pp, + Xd, + Xq, + Xd_p, + Xq_p, + Xd_pp, + Xl, + γ_d1, + γ_q1, + γ_d2, + γ_q2, + γ_qd = machine_params #RoundRotorQuadratic and RoundRotorExponential have same params; otherwise would need separate methods Xq_pp = Xd_pp - Xl = PSY.get_Xl(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) - #RI to dq transformation V_dq = ri_dq(δ) * [V_tR; V_tI] @@ -329,6 +409,7 @@ end function _update_inner_vars!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ @@ -354,14 +435,20 @@ function _update_inner_vars!( V_tI = inner_vars[VI_gen_var] #Get parameters - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xd_p = PSY.get_Xd_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) - Xl = PSY.get_Xl(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) + machine_ix_params = get_local_parameter_ix(dynamic_device, typeof(machine)) + machine_params = @view device_parameters[machine_ix_params] + R, + Td0_p, + Td0_pp, + Tq0_pp, + Xd, + Xq, + Xd_p, + Xd_pp, + Xl, + γ_d1, + γ_q1, + γ_d2 = machine_params #RI to dq transformation V_d, V_q = ri_dq(δ) * [V_tR; V_tI] @@ -383,6 +470,7 @@ end function _update_inner_vars!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ @@ -408,15 +496,21 @@ function _update_inner_vars!( V_tI = inner_vars[VI_gen_var] #Get parameters - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xd_p = PSY.get_Xd_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) + machine_ix_params = get_local_parameter_ix(dynamic_device, typeof(machine)) + machine_params = @view device_parameters[machine_ix_params] + R, + Td0_p, + Td0_pp, + Tq0_pp, + Xd, + Xq, + Xd_p, + Xd_pp, + Xl, + γ_d1, + γ_q1, + γ_d2 = machine_params Xq_pp = Xd_pp - Xl = PSY.get_Xl(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) #RI to dq transformation V_d, V_q = ri_dq(δ) * [V_tR; V_tI] @@ -437,6 +531,7 @@ function _update_inner_vars!( end function _update_inner_vars!( + ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, @@ -457,6 +552,7 @@ end function _update_inner_vars!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ @@ -484,17 +580,34 @@ function _update_inner_vars!( #Get Converter parameters converter = PSY.get_converter(dynamic_device) - Brkpt = PSY.get_Brkpt(converter) - Zerox = PSY.get_Zerox(converter) - Lvpl1 = PSY.get_Lvpl1(converter) - Vo_lim = PSY.get_Vo_lim(converter) - Lv_pnt0, Lv_pnt1 = PSY.get_Lv_pnts(converter) - K_hv = PSY.get_K_hv(converter) + converter_ix_params = get_local_parameter_ix(dynamic_device, typeof(converter)) + converter_params = @view device_parameters[converter_ix_params] + T_g, + Rrpwr, + Brkpt, + Zerox, + Lvpl1, + Vo_lim, + Lv_pnt0, + Lv_pnt1, + Io_lim, + T_fltr, + K_hv, + Iqr_min, + Iqr_max, + Accel, + Q_ref, + R_source, + X_source = converter_params Lvpl_sw = PSY.get_Lvpl_sw(converter) - R_source = PSY.get_R_source(converter) - X_source = PSY.get_X_source(converter) Z_source_sq = R_source^2 + X_source^2 + #Obtain filter parameters + filt = PSY.get_filter(dynamic_device) + filter_ix_params = get_local_parameter_ix(dynamic_device, typeof(filt)) + filter_params = @view device_parameters[filter_ix_params] + rf, lf = filter_params + #Define internal states for Converter converter_ix = get_local_state_ix(dynamic_device, PSY.RenewableEnergyConverterTypeA) converter_states = @view device_states[converter_ix] @@ -516,11 +629,6 @@ function _update_inner_vars!( Ir_cnv = Id_cnv * cos(θ) - Iq_cnv * sin(θ) Ii_cnv = Id_cnv * sin(θ) + Iq_cnv * cos(θ) - #Obtain parameters - filt = PSY.get_filter(dynamic_device) - rf = PSY.get_rf(filt) - lf = PSY.get_lf(filt) - function V_cnv_calc(Ir_cnv, Ii_cnv, Vr_inv, Vi_inv) if lf != 0.0 || rf != 0.0 Z_source_mag_sq = R_source^2 + X_source^2 @@ -578,6 +686,7 @@ end function _update_inner_vars!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, + ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ @@ -648,6 +757,7 @@ Oleg Wasynczuk and Scott Sudhoff for the equations function device!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -675,20 +785,24 @@ function device!( ωr = device_states[5] #Get parameters - dynamic_device = get_device(dynamic_wrapper) - R_s = PSY.get_R_s(dynamic_device) - X_ls = PSY.get_X_ls(dynamic_device) - R_r = PSY.get_R_r(dynamic_device) - X_lr = PSY.get_X_lr(dynamic_device) - A = PSY.get_A(dynamic_device) - B = PSY.get_B(dynamic_device) - C = PSY.get_C(dynamic_device) - H = PSY.get_H(dynamic_device) - base_power = PSY.get_base_power(dynamic_device) - B_sh = PSY.get_B_shunt(dynamic_device) - τ_m0 = PSY.get_τ_ref(dynamic_device) - X_ad = PSY.get_X_ad(dynamic_device) - X_aq = PSY.get_X_aq(dynamic_device) + _, + _, + _, + _, + R_s, + R_r, + X_ls, + X_lr, + X_m, + H, + A, + B, + base_power, + C, + τ_m0, + B_sh, + X_ad, + X_aq = device_parameters # voltages in QD v_qs = voltage_i @@ -731,6 +845,7 @@ Oleg Wasynczuk and Scott Sudhoff. function device!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -756,19 +871,25 @@ function device!( ωr = device_states[3] #Get parameters - dynamic_device = get_device(dynamic_wrapper) - R_s = PSY.get_R_s(dynamic_device) - X_m = PSY.get_X_m(dynamic_device) - R_r = PSY.get_R_r(dynamic_device) - A = PSY.get_A(dynamic_device) - B = PSY.get_B(dynamic_device) - C = PSY.get_C(dynamic_device) - H = PSY.get_H(dynamic_device) - base_power = PSY.get_base_power(dynamic_device) - B_sh = PSY.get_B_shunt(dynamic_device) - τ_m0 = PSY.get_τ_ref(dynamic_device) - X_rr = PSY.get_X_rr(dynamic_device) - X_p = PSY.get_X_p(dynamic_device) + _, + _, + _, + _, + R_s, + R_r, + X_ls, + X_lr, + X_m, + H, + A, + B, + base_power, + C, + τ_m0, + B_sh, + X_ss, + X_rr, + X_p = device_parameters # voltages in QD v_qs = voltage_i @@ -827,6 +948,7 @@ Model of Static Shunt Compensator: CSVGN1. function device!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -837,7 +959,6 @@ function device!( t, ) where {T <: ACCEPTED_REAL_TYPES} Sbase = get_system_base_power(dynamic_wrapper) - V_ref = get_V_ref(dynamic_wrapper) # TODO: V_abs is the voltage magnitude on the high side of generator step-up transformer, if present. V_abs = sqrt(voltage_r^2 + voltage_i^2) @@ -852,20 +973,26 @@ function device!( vr2 = device_states[3] #Get parameters - dynamic_device = get_device(dynamic_wrapper) - K = PSY.get_K(dynamic_device) - T1 = PSY.get_T1(dynamic_device) - T2 = PSY.get_T2(dynamic_device) - T3 = PSY.get_T3(dynamic_device) - T4 = PSY.get_T4(dynamic_device) - T5 = PSY.get_T5(dynamic_device) - Rmin = PSY.get_Rmin(dynamic_device) - Vmax = PSY.get_Vmax(dynamic_device) - Vmin = PSY.get_Vmin(dynamic_device) - Cbase = PSY.get_CBase(dynamic_device) + Q_ref, + V_ref, + ω_ref, + P_ref, + K, + T1, + T2, + T3, + T4, + T5, + Rmin, + Vmax, + Vmin, + Cbase, + Mbase, + R_th, + X_th = device_parameters + # FIXME: base_power is changed to system's base_power when a CSVGN1 is attached to a Source using add_component!() # Temporarily, to avoid that, set_dynamic_injector!() could be used - Mbase = PSY.get_base_power(dynamic_device) Rbase = Mbase # Regulator @@ -908,7 +1035,7 @@ function device_mass_matrix_entries!( dynamic_device::DynamicWrapper{PSY.ActiveConstantPowerLoad}, ) global_index = get_global_index(dynamic_device) - device = get_device(dynamic_device) + device = get_dynamic_device(dynamic_device) bool_mm_value = PSY.get_is_filter_differential(device) f0 = get_system_base_frequency(dynamic_device) ωb = 2 * pi * f0 @@ -935,6 +1062,7 @@ by C. Roberts, U. Markovic, D. Arnold and D. Callaway. function device!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -946,7 +1074,6 @@ function device!( ) where {T <: ACCEPTED_REAL_TYPES} Sbase = get_system_base_power(dynamic_wrapper) f0 = get_system_base_frequency(dynamic_wrapper) - V_ref = get_V_ref(dynamic_wrapper) if get_connection_status(dynamic_wrapper) < 1.0 output_ode .= zero(T) return @@ -977,21 +1104,24 @@ function device!( I_dq_cnv = ri_dq(θ_pll + pi / 2) * [Ir_cnv; Ii_cnv] #Get parameters - dynamic_device = get_device(dynamic_wrapper) - r_load = PSY.get_r_load(dynamic_device) - c_dc = PSY.get_c_dc(dynamic_device) - rf = PSY.get_rf(dynamic_device) - lf = PSY.get_lf(dynamic_device) - cf = PSY.get_cf(dynamic_device) - rg = PSY.get_rg(dynamic_device) - lg = PSY.get_lg(dynamic_device) - kp_pll = PSY.get_kp_pll(dynamic_device) - ki_pll = PSY.get_ki_pll(dynamic_device) - kpv = PSY.get_kpv(dynamic_device) - kiv = PSY.get_kiv(dynamic_device) - kpc = PSY.get_kpc(dynamic_device) - kic = PSY.get_kic(dynamic_device) - base_power = PSY.get_base_power(dynamic_device) + Q_ref, + V_ref, + ω_ref, + P_ref, + r_load, + c_dc, + rf, + lf, + cf, + rg, + lg, + kp_pll, + ki_pll, + kpv, + kiv, + kpc, + kic, + base_power = device_parameters # Compute PLL expressions V_dq_pll = ri_dq(θ_pll + pi / 2) * [Vr_filter; Vi_filter] @@ -1000,8 +1130,7 @@ function device!( # Compute DC side output Id_ref, dη_dt = pi_block(V_ref - v_dc, η, kpv, kiv) - Iq_ref = get_Q_ref(dynamic_wrapper) - + Iq_ref = Q_ref # Compute AC controller expressions Vd_ref_uncomp, dγd_dt = pi_block(-Id_ref + I_dq_cnv[d], γd, kpc, kic) Vq_ref_uncomp, dγq_dt = pi_block(-Iq_ref + I_dq_cnv[q], γq, kpc, kic) @@ -1060,8 +1189,8 @@ function mass_matrix_dera_entries!( dera::DynamicWrapper{PSY.AggregateDistributedGenerationA}, global_index::ImmutableDict{Symbol, Int64}, ) - ddera = get_device(dera) - Freq_Flag = PSY.get_Freq_Flag(get_device(dera)) + ddera = get_dynamic_device(dera) + Freq_Flag = PSY.get_Freq_Flag(get_dynamic_device(dera)) if Freq_Flag == 1 mass_matrix[global_index[:Vmeas], global_index[:Vmeas]] = PSY.get_T_rv(ddera) mass_matrix[global_index[:Pmeas], global_index[:Pmeas]] = PSY.get_Tp(ddera) @@ -1081,19 +1210,21 @@ end function device!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, current_i::AbstractArray{T}, global_vars::AbstractArray{T}, inner_vars::AbstractArray{T}, - dynamic_device::DynamicWrapper{PSY.AggregateDistributedGenerationA}, + dynamic_wrapper::DynamicWrapper{PSY.AggregateDistributedGenerationA}, t, ) where {T <: ACCEPTED_REAL_TYPES} - Freq_Flag = PSY.get_Freq_Flag(get_device(dynamic_device)) + Freq_Flag = PSY.get_Freq_Flag(get_dynamic_device(dynamic_wrapper)) _mdl_ode_AggregateDistributedGenerationA!( device_states, output_ode, + device_parameters, Val(Freq_Flag), voltage_r, voltage_i, @@ -1101,7 +1232,7 @@ function device!( current_i, global_vars, inner_vars, - dynamic_device, + dynamic_wrapper, t, ) return @@ -1115,6 +1246,7 @@ end function _mdl_ode_AggregateDistributedGenerationA!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::Val{0}, voltage_r::T, voltage_i::T, @@ -1122,21 +1254,21 @@ function _mdl_ode_AggregateDistributedGenerationA!( current_i::AbstractArray{T}, global_vars::AbstractArray{T}, inner_vars::AbstractArray{T}, - dynamic_device::DynamicWrapper{PSY.AggregateDistributedGenerationA}, + dynamic_wrapper::DynamicWrapper{PSY.AggregateDistributedGenerationA}, t, ) where {T <: ACCEPTED_REAL_TYPES} sys_ω = global_vars[GLOBAL_VAR_SYS_FREQ_INDEX] - Sbase = get_system_base_power(dynamic_device) + Sbase = get_system_base_power(dynamic_wrapper) Vt = sqrt(voltage_r^2 + voltage_i^2) - + dynamic_device = get_dynamic_device(dynamic_wrapper) #Obtain References (from wrapper and device) - Pfa_ref = PSY.get_Pfa_ref(get_device(dynamic_device)) - P_ref = get_P_ref(dynamic_device) - Q_ref = get_Q_ref(dynamic_device) - V_ref = get_V_ref(dynamic_device) + Pfa_ref = PSY.get_Pfa_ref(dynamic_device) + P_ref = device_parameters[P_ref_ix] + Q_ref = device_parameters[Q_ref_ix] + V_ref = device_parameters[V_ref_ix] #Get flags - Pf_Flag = PSY.get_Pf_Flag(get_device(dynamic_device)) + Pf_Flag = PSY.get_Pf_Flag(dynamic_device) #Get device states Vmeas = device_states[1] @@ -1151,18 +1283,40 @@ function _mdl_ode_AggregateDistributedGenerationA!( Iq_cmd = Iq #Get parameters - T_rv = PSY.get_T_rv(get_device(dynamic_device)) - Trf = PSY.get_Trf(get_device(dynamic_device)) - (dbd1, dbd2) = PSY.get_dbd_pnts(get_device(dynamic_device)) - K_qv = PSY.get_K_qv(get_device(dynamic_device)) - Tp = PSY.get_Tp(get_device(dynamic_device)) - T_iq = PSY.get_T_iq(get_device(dynamic_device)) - - Tg = PSY.get_Tg(get_device(dynamic_device)) - rrpwr = PSY.get_rrpwr(get_device(dynamic_device)) - Tv = PSY.get_Tv(get_device(dynamic_device)) - Iq_lim = PSY.get_Iq_lim(get_device(dynamic_device)) - basepower = PSY.get_base_power(get_device(dynamic_device)) + Q_ref, + V_ref, + ω_ref, + P_ref, + T_rv, + Trf, + dbd1, + dbd2, + K_qv, + Tp, + T_iq, + D_dn, + D_up, + fdbd_pnts, + fdbd_pnts, + fe_min, + fe_max, + P_min, + P_max, + dP_min, + dP_max, + Tpord, + Kpg, + Kig, + I_max, + Tg, + rrpwr, + Tv, + Vpr, + Iq_min, + Iq_max, + basepower, + Pfa_ref = device_parameters + base_power_ratio = basepower / Sbase #STATE Vmeas @@ -1178,17 +1332,17 @@ function _mdl_ode_AggregateDistributedGenerationA!( end #STATE Iq - Ip_min, Ip_max, Iq_min, Iq_max = - current_limit_logic(get_device(dynamic_device), Ip_cmd, Iq_cmd) + Ip_min, Ip_max, _Iq_min, _Iq_max = + current_limit_logic(dynamic_device, Ip_cmd, Iq_cmd) Iq_input = clamp( clamp( deadband_function(V_ref - Vmeas, dbd1, dbd2) * K_qv, - Iq_lim[:min], - Iq_lim[:max], + Iq_min, + Iq_max, ) + Q_V, - Iq_min, - Iq_max, + _Iq_min, + _Iq_max, ) * Mult _, dIq_dt = low_pass(Iq_input, Iq, 1.0, Tg) @@ -1237,6 +1391,7 @@ end function _mdl_ode_AggregateDistributedGenerationA!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::Val{1}, voltage_r::T, voltage_i::T, @@ -1244,22 +1399,22 @@ function _mdl_ode_AggregateDistributedGenerationA!( current_i::AbstractArray{T}, global_vars::AbstractArray{T}, inner_vars::AbstractArray{T}, - dynamic_device::DynamicWrapper{PSY.AggregateDistributedGenerationA}, + dynamic_wrapper::DynamicWrapper{PSY.AggregateDistributedGenerationA}, t, ) where {T <: ACCEPTED_REAL_TYPES} sys_ω = global_vars[GLOBAL_VAR_SYS_FREQ_INDEX] - Sbase = get_system_base_power(dynamic_device) + Sbase = get_system_base_power(dynamic_wrapper) Vt = sqrt(voltage_r^2 + voltage_i^2) - + dynamic_device = get_dynamic_device(dynamic_wrapper) #Obtain References (from wrapper and device) - Pfa_ref = PSY.get_Pfa_ref(get_device(dynamic_device)) - P_ref = get_P_ref(dynamic_device) - Q_ref = get_Q_ref(dynamic_device) - V_ref = get_V_ref(dynamic_device) - ω_ref = get_ω_ref(dynamic_device) + Pfa_ref = PSY.get_Pfa_ref(dynamic_device) + P_ref = device_parameters[P_ref_ix] + Q_ref = device_parameters[Q_ref_ix] + V_ref = device_parameters[V_ref_ix] + ω_ref = device_parameters[ω_ref_ix] #Get flags - Pf_Flag = PSY.get_Pf_Flag(get_device(dynamic_device)) + Pf_Flag = PSY.get_Pf_Flag(dynamic_device) #Get device states Vmeas = device_states[1] @@ -1277,27 +1432,40 @@ function _mdl_ode_AggregateDistributedGenerationA!( Iq_cmd = Iq #Get parameters - T_rv = PSY.get_T_rv(get_device(dynamic_device)) - Trf = PSY.get_Trf(get_device(dynamic_device)) - (dbd1, dbd2) = PSY.get_dbd_pnts(get_device(dynamic_device)) - K_qv = PSY.get_K_qv(get_device(dynamic_device)) - Tp = PSY.get_Tp(get_device(dynamic_device)) - T_iq = PSY.get_T_iq(get_device(dynamic_device)) - D_dn = PSY.get_D_dn(get_device(dynamic_device)) - D_up = PSY.get_D_up(get_device(dynamic_device)) - (fdbd1, fdbd2) = PSY.get_fdbd_pnts(get_device(dynamic_device)) - fe_lim = PSY.get_fe_lim(get_device(dynamic_device)) - P_lim = PSY.get_P_lim(get_device(dynamic_device)) - dP_lim = PSY.get_dP_lim(get_device(dynamic_device)) - Tpord = PSY.get_Tpord(get_device(dynamic_device)) - Kpg = PSY.get_Kpg(get_device(dynamic_device)) - Kig = PSY.get_Kig(get_device(dynamic_device)) - - Tg = PSY.get_Tg(get_device(dynamic_device)) - rrpwr = PSY.get_rrpwr(get_device(dynamic_device)) - Tv = PSY.get_Tv(get_device(dynamic_device)) - Iq_lim = PSY.get_Iq_lim(get_device(dynamic_device)) - basepower = PSY.get_base_power(get_device(dynamic_device)) + Q_ref, + V_ref, + ω_ref, + P_ref, + T_rv, + Trf, + dbd1, + dbd2, + K_qv, + Tp, + T_iq, + D_dn, + D_up, + fdbd1, + fdbd2, + fe_min, + fe_max, + P_min, + P_max, + dP_min, + dP_max, + Tpord, + Kpg, + Kig, + I_max, + Tg, + rrpwr, + Tv, + Vpr, + Iq_min, + Iq_max, + basepower, + Pfa_ref = device_parameters + base_power_ratio = basepower / Sbase #STATE Vmeas @@ -1313,17 +1481,17 @@ function _mdl_ode_AggregateDistributedGenerationA!( end #STATE Iq - Ip_min, Ip_max, Iq_min, Iq_max = - current_limit_logic(get_device(dynamic_device), Ip_cmd, Iq_cmd) + Ip_min, Ip_max, _Iq_min, _Iq_max = + current_limit_logic(dynamic_device, Ip_cmd, Iq_cmd) Iq_input = clamp( clamp( deadband_function(V_ref - Vmeas, dbd1, dbd2) * K_qv, - Iq_lim[:min], - Iq_lim[:max], + Iq_min, + Iq_max, ) + Q_V, - Iq_min, - Iq_max, + _Iq_min, + _Iq_max, ) * Mult _, dIq_dt = low_pass(Iq_input, Iq, 1.0, Tg) @@ -1349,24 +1517,24 @@ function _mdl_ode_AggregateDistributedGenerationA!( PowerPI_input = clamp( min(deadband_function(ω_ref - Fmeas, fdbd1, fdbd2) * D_dn, 0.0) + max(deadband_function(ω_ref - Fmeas, fdbd1, fdbd2) * D_up, 0.0) - Pmeas + P_ref, - fe_lim[:min], - fe_lim[:max], + fe_min, + fe_max, ) _, dPowerPI_dt = - pi_block_nonwindup(PowerPI_input, PowerPI, Kpg, Kig, P_lim[:min], P_lim[:max]) + pi_block_nonwindup(PowerPI_input, PowerPI, Kpg, Kig, P_min, P_max) #STATE dPord - if dPowerPI_dt > dP_lim[:max] - ddPord_dt = dP_lim[:max] - elseif dPowerPI_dt < dP_lim[:min] - ddPord_dt = dP_lim[:min] + if dPowerPI_dt > dP_max + ddPord_dt = dP_max + elseif dPowerPI_dt < dP_min + ddPord_dt = dP_min else ddPord_dt = dPowerPI_dt end #State Pord Pord_limited, dPord_dt = - low_pass_nonwindup_mass_matrix(dPord, Pord, 1.0, Tpord, P_lim[:min], P_lim[:max]) + low_pass_nonwindup_mass_matrix(dPord, Pord, 1.0, Tpord, P_min, P_max) #STATE Ip Ip_input = clamp(Pord_limited / max(Vmeas, 0.01), Ip_min, Ip_max) * Mult diff --git a/src/models/dynline_model.jl b/src/models/dynline_model.jl index 00c6f6764..ae0cfd883 100644 --- a/src/models/dynline_model.jl +++ b/src/models/dynline_model.jl @@ -1,6 +1,7 @@ function mdl_branch_ode!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r_from::T, voltage_i_from::T, voltage_r_to::T, @@ -11,8 +12,7 @@ function mdl_branch_ode!( current_i_to::AbstractArray{T}, branch::BranchWrapper, ) where {T <: ACCEPTED_REAL_TYPES} - L = PSY.get_x(branch) - R = PSY.get_r(branch) + R, L = device_parameters ω_b = get_system_base_frequency(branch) * 2 * π Il_r = device_states[1] @@ -30,6 +30,7 @@ end function mdl_transformer_Lshape_ode!( device_states::AbstractArray{T}, output_ode::AbstractArray{T}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r_from::T, voltage_i_from::T, voltage_r_to::T, diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index 78492ac34..3a8a42e2b 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -64,12 +64,13 @@ end function mdl_avr_ode!( ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRFixed, TG, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Update Vf voltage on inner vars. In AVRFixed, Vf = V_ref - inner_vars[Vf_var] = get_V_ref(dynamic_device) + inner_vars[Vf_var] = device_parameters[V_ref_ix] return end @@ -77,12 +78,13 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRSimple, TG, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V_ref = get_V_ref(dynamic_device) + V_ref = device_parameters[V_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.AVRSimple) @@ -95,7 +97,9 @@ function mdl_avr_ode!( V_th = sqrt(inner_vars[VR_gen_var]^2 + inner_vars[VI_gen_var]^2) #Get Parameters - Kv = PSY.get_Kv(PSY.get_avr(dynamic_device)) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AVRSimple) + internal_params = @view device_parameters[local_ix_params] + Kv = internal_params[1] #Compute ODEs output_ode[local_ix[1]] = Kv * (V_ref - V_th) @@ -109,12 +113,13 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRTypeI, TG, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = device_parameters[V_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeI) @@ -131,16 +136,9 @@ function mdl_avr_ode!( Vs = inner_vars[V_pss_var] #Get parameters - avr = PSY.get_avr(dynamic_device) - Ka = PSY.get_Ka(avr) - Ke = PSY.get_Ke(avr) - Kf = PSY.get_Kf(avr) - Ta = PSY.get_Ta(avr) - Te = PSY.get_Te(avr) - Tf = PSY.get_Tf(avr) - Tr = PSY.get_Tr(avr) - Ae = PSY.get_Ae(avr) - Be = PSY.get_Be(avr) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AVRTypeI) + internal_params = @view device_parameters[local_ix_params] + Ka, Ke, Kf, Ta, Te, Tf, Tr, Ae, Be = internal_params #Compute auxiliary parameters Se_Vf = Ae * exp(Be * abs(Vf)) #16.13 @@ -167,12 +165,13 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRTypeII, TG, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = device_parameters[V_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeII) @@ -189,17 +188,19 @@ function mdl_avr_ode!( Vs = inner_vars[V_pss_var] #Get parameters - avr = PSY.get_avr(dynamic_device) - K0 = PSY.get_K0(avr) - T1 = PSY.get_T1(avr) - T2 = PSY.get_T2(avr) - T3 = PSY.get_T3(avr) - T4 = PSY.get_T4(avr) - Te = PSY.get_Te(avr) - Tr = PSY.get_Tr(avr) - Ae = PSY.get_Ae(avr) - Be = PSY.get_Be(avr) - Va_min, Va_max = PSY.get_Va_lim(avr) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AVRTypeII) + internal_params = @view device_parameters[local_ix_params] + K0, + T1, + T2, + T3, + T4, + Te, + Tr, + Va_min, + Va_max, + Ae, + Be = internal_params #Compute auxiliary parameters Se_Vf = Ae * exp(Be * abs(Vf)) #16.13 @@ -227,12 +228,13 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.ESAC1A, TG, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V_ref = get_V_ref(dynamic_device) + V_ref = device_parameters[V_ref_ix] #Obtain avr avr = PSY.get_avr(dynamic_device) @@ -254,20 +256,24 @@ function mdl_avr_ode!( Xad_Ifd = inner_vars[Xad_Ifd_var] #Get parameters - Tr = PSY.get_Tr(avr) - Ta = PSY.get_Ta(avr) - Tb = PSY.get_Tb(avr) - Tc = PSY.get_Tc(avr) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.ESAC1A) + internal_params = @view device_parameters[local_ix_params] + Tr, + Tb, + Tc, + Ka, + Ta, + Va_min, + Va_max, + Te, + Kf, + Tf, + Kc, + Kd, + Ke, + Vr_min, + Vr_max = internal_params inv_Tr = Tr < eps() ? 1.0 : 1.0 / Tr - Ka = PSY.get_Ka(avr) - Va_min, Va_max = PSY.get_Va_lim(avr) #Not used without UEL or OEL - Te = PSY.get_Te(avr) # Te > 0 - Kf = PSY.get_Kf(avr) - Tf = PSY.get_Tf(avr) # Te > 0 - Kc = PSY.get_Kc(avr) - Kd = PSY.get_Kd(avr) - Ke = PSY.get_Ke(avr) - Vr_min, Vr_max = PSY.get_Vr_lim(avr) #Obtain saturation Se = saturation_function(avr, Ve) @@ -302,12 +308,13 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.SEXS, TG, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = device_parameters[V_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.SEXS) @@ -322,13 +329,10 @@ function mdl_avr_ode!( Vs = inner_vars[V_pss_var] #Get parameters - avr = PSY.get_avr(dynamic_device) - Ta_Tb = PSY.get_Ta_Tb(avr) - Tb = PSY.get_Tb(avr) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SEXS) + internal_params = @view device_parameters[local_ix_params] + Ta_Tb, Tb, K, Te, V_min, V_max = internal_params Ta = Tb * Ta_Tb - Te = PSY.get_Te(avr) - K = PSY.get_K(avr) - V_min, V_max = PSY.get_V_lim(avr) #Compute auxiliary parameters V_in = V0_ref + Vs - V_th @@ -348,12 +352,13 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.SCRX, TG, P}}, # ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = device_parameters[V_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.SCRX) # @@ -408,12 +413,13 @@ end function mdl_avr_ode!( device_states::AbstractArray, output_ode::AbstractArray, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.EXST1, TG, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = device_parameters[V_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.EXST1) @@ -430,18 +436,21 @@ function mdl_avr_ode!( Vs = inner_vars[V_pss_var] # PSS output Ifd = inner_vars[Xad_Ifd_var] # machine's field current in exciter base - #Get parameters - avr = PSY.get_avr(dynamic_device) - Tr = PSY.get_Tr(avr) - Vi_min, Vi_max = PSY.get_Vi_lim(avr) - Tc = PSY.get_Tc(avr) - Tb = PSY.get_Tb(avr) - Ka = PSY.get_Ka(avr) - Ta = PSY.get_Ta(avr) - Vr_min, Vr_max = PSY.get_Vr_lim(avr) - Kc = PSY.get_Kc(avr) - Kf = PSY.get_Kf(avr) - Tf = PSY.get_Tf(avr) + #Get Parameters + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.EXST1) + internal_params = @view device_parameters[local_ix_params] + Tr, + Vi_min, + Vi_max, + Tc, + Tb, + Ka, + Ta, + Vr_min, + Vr_max, + Kc, + Kf, + Tf = internal_params #Compute auxiliary parameters V_ref = V0_ref + Vs @@ -468,12 +477,13 @@ end function mdl_avr_ode!( device_states::AbstractArray, output_ode::AbstractArray, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.EXAC1, TG, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V_ref = get_V_ref(dynamic_device) + V_ref = device_parameters[V_ref_ix] #Obtain avr avr = PSY.get_avr(dynamic_device) @@ -495,18 +505,21 @@ function mdl_avr_ode!( Xad_Ifd = inner_vars[Xad_Ifd_var] # machine's field current in exciter base #Get parameters - Tr = PSY.get_Tr(avr) - Tb = PSY.get_Tb(avr) - Tc = PSY.get_Tc(avr) - Ka = PSY.get_Ka(avr) - Ta = PSY.get_Ta(avr) - Vr_min, Vr_max = PSY.get_Vr_lim(avr) - Te = PSY.get_Te(avr) # Te > 0 - Kf = PSY.get_Kf(avr) - Tf = PSY.get_Tf(avr) # Tf > 0 - Kc = PSY.get_Kc(avr) - Kd = PSY.get_Kd(avr) - Ke = PSY.get_Ke(avr) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.EXAC1) + internal_params = @view device_parameters[local_ix_params] + Tr, + Tb, + Tc, + Ka, + Ta, + Vr_min, + Vr_max, + Te, + Kf, + Tf, + Kc, + Kd, + Ke = internal_params #Obtain saturation Se = saturation_function(avr, Ve) @@ -539,12 +552,13 @@ end function mdl_avr_ode!( device_states::AbstractArray, output_ode::AbstractArray, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.ESST1A, TG, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = device_parameters[V_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.ESST1A) diff --git a/src/models/generator_models/machine_models.jl b/src/models/generator_models/machine_models.jl index c8cac83e3..91dffb7af 100644 --- a/src/models/generator_models/machine_models.jl +++ b/src/models/generator_models/machine_models.jl @@ -13,6 +13,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -28,10 +29,9 @@ function mdl_machine_ode!( V_tI = inner_vars[VI_gen_var] #Get parameters - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd_p = PSY.get_Xd_p(machine) - eq_p = PSY.get_eq_p(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.BaseMachine) + internal_params = @view device_parameters[local_ix_params] + R, Xd_p, eq_p = internal_params basepower = PSY.get_base_power(dynamic_device) #RI to dq transformation @@ -62,6 +62,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -87,14 +88,10 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #Get parameters - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Td0_p = PSY.get_Td0_p(machine) - Tq0_p = PSY.get_Tq0_p(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.OneDOneQMachine) + internal_params = @view device_parameters[local_ix_params] + R, Xd, Xq, Xd_p, Xq_p, Td0_p, Tq0_p = internal_params + basepower = PSY.get_base_power(dynamic_device) #RI to dq transformation @@ -129,6 +126,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -219,6 +217,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -250,21 +249,10 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #Get parameters - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) - Xq_pp = PSY.get_Xq_pp(machine) - Td0_p = PSY.get_Td0_p(machine) - Tq0_p = PSY.get_Tq0_p(machine) - Td0_pp = PSY.get_Td0_pp(machine) - Tq0_pp = PSY.get_Tq0_pp(machine) - T_AA = PSY.get_T_AA(machine) - γd = PSY.get_γd(machine) - γq = PSY.get_γq(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.MarconatoMachine) + internal_params = @view device_parameters[local_ix_params] + R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, T_AA, γd, γq = + internal_params basepower = PSY.get_base_power(dynamic_device) #RI to dq transformation @@ -305,6 +293,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -390,6 +379,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -423,18 +413,19 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #Get parameters - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) - Xq_pp = PSY.get_Xq_pp(machine) - Td0_p = PSY.get_Td0_p(machine) - Tq0_p = PSY.get_Tq0_p(machine) - Td0_pp = PSY.get_Td0_pp(machine) - Tq0_pp = PSY.get_Tq0_pp(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AndersonFouadMachine) + internal_params = @view device_parameters[local_ix_params] + R, + Xd, + Xq, + Xd_p, + Xq_p, + Xd_pp, + Xq_pp, + Td0_p, + Tq0_p, + Td0_pp, + Tq0_pp = internal_params basepower = PSY.get_base_power(dynamic_device) #RI to dq transformation @@ -473,6 +464,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -548,6 +540,7 @@ end function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -583,23 +576,25 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #E_fd: Field voltage #Get parameters - R = PSY.get_R(machine) - Td0_p = PSY.get_Td0_p(machine) - Td0_pp = PSY.get_Td0_pp(machine) - Tq0_p = PSY.get_Tq0_p(machine) - Tq0_pp = PSY.get_Tq0_pp(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, typeof(machine)) + internal_params = @view device_parameters[local_ix_params] + R, + Td0_p, + Td0_pp, + Tq0_p, + Tq0_pp, + Xd, + Xq, + Xd_p, + Xq_p, + Xd_pp, + Xl, + γ_d1, + γ_q1, + γ_d2, + γ_q2, + γ_qd = internal_params Xq_pp = Xd_pp - Xl = PSY.get_Xl(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) - γ_q2 = PSY.get_γ_q2(machine) - γ_qd = PSY.get_γ_qd(machine) basepower = PSY.get_base_power(dynamic_device) #RI to dq transformation @@ -644,6 +639,7 @@ end function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -674,19 +670,21 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #E_fd: Field voltage #Get parameters - R = PSY.get_R(machine) - Td0_p = PSY.get_Td0_p(machine) - Td0_pp = PSY.get_Td0_pp(machine) - Tq0_pp = PSY.get_Tq0_pp(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SalientPoleQuadratic) + internal_params = @view device_parameters[local_ix_params] + R, + Td0_p, + Td0_pp, + Tq0_pp, + Xd, + Xq, + Xd_p, + Xd_pp, + Xl, + γ_d1, + γ_q1, + γ_d2 = internal_params Xq_pp = Xd_pp - Xl = PSY.get_Xl(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) basepower = PSY.get_base_power(dynamic_device) #RI to dq transformation @@ -725,6 +723,7 @@ end function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -755,19 +754,21 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #E_fd: Field voltage #Get parameters - R = PSY.get_R(machine) - Td0_p = PSY.get_Td0_p(machine) - Td0_pp = PSY.get_Td0_pp(machine) - Tq0_pp = PSY.get_Tq0_pp(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SalientPoleExponential) + internal_params = @view device_parameters[local_ix_params] + R, + Td0_p, + Td0_pp, + Tq0_pp, + Xd, + Xq, + Xd_p, + Xd_pp, + Xl, + γ_d1, + γ_q1, + γ_d2 = internal_params Xq_pp = Xd_pp - Xl = PSY.get_Xl(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) γ_qd = (Xq - Xl) / (Xd - Xl) basepower = PSY.get_base_power(dynamic_device) @@ -816,6 +817,7 @@ or Power System Stability and Control by P. Kundur, for the equations function mdl_machine_ode!( device_states, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode, inner_vars, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, diff --git a/src/models/generator_models/pss_models.jl b/src/models/generator_models/pss_models.jl index b83c965c6..354c1ad3d 100644 --- a/src/models/generator_models/pss_models.jl +++ b/src/models/generator_models/pss_models.jl @@ -115,13 +115,17 @@ end function mdl_pss_ode!( ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSSFixed}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, TG <: PSY.TurbineGov} #Update V_pss on inner vars - inner_vars[V_pss_var] = PSY.get_V_pss(PSY.get_pss(dynamic_device)) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.PSSFixed) + internal_params = @view device_parameters[local_ix_params] + V_pss = internal_params[1] + inner_vars[V_pss_var] = V_pss return end @@ -129,6 +133,7 @@ end function mdl_pss_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.IEEEST}}, @@ -226,14 +231,12 @@ end function mdl_pss_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.STAB1}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, TG <: PSY.TurbineGov} - #Get Signal Input Integer - pss = PSY.get_pss(dynamic_device) - # Get Input Signal - only speed deviation for STAB1 external_ix = get_input_port_ix(dynamic_device, PSY.STAB1) ω = device_states[external_ix[1]] # get machine speed @@ -249,13 +252,15 @@ function mdl_pss_ode!( x_p3 = internal_states[3] # state for Lead Lag 2 # Get Parameters - KT = PSY.get_KT(pss) - T = PSY.get_T(pss) - T1T3 = PSY.get_T1T3(pss) - T3 = PSY.get_T3(pss) - T2T4 = PSY.get_T2T4(pss) - T4 = PSY.get_T4(pss) - H_lim = PSY.get_H_lim(pss) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.STAB1) + internal_params = @view device_parameters[local_ix_params] + KT, + T, + T1T3, + T3, + T2T4, + T4, + H_lim = internal_params K = T * KT T1 = T3 * T1T3 @@ -281,6 +286,7 @@ end function mdl_pss_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSS2A}}, @@ -449,6 +455,7 @@ end function mdl_pss_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSS2B}}, @@ -628,6 +635,7 @@ end function mdl_pss_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSS2C}}, diff --git a/src/models/generator_models/shaft_models.jl b/src/models/generator_models/shaft_models.jl index 3de6ecc21..8b3719b1c 100644 --- a/src/models/generator_models/shaft_models.jl +++ b/src/models/generator_models/shaft_models.jl @@ -9,6 +9,7 @@ end function mdl_shaft_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, PSY.SingleMass, A, TG, P}}, @@ -26,9 +27,9 @@ function mdl_shaft_ode!( τm = inner_vars[τm_var] #Get parameters - shaft = PSY.get_shaft(dynamic_device) - H = PSY.get_H(shaft) - D = PSY.get_D(shaft) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SingleMass) + internal_params = @view device_parameters[local_ix_params] + H, D = internal_params #Compute 2 states ODEs output_ode[local_ix[1]] = 2 * π * f0 * (ω - ω_sys) #15.5 @@ -40,6 +41,7 @@ end function mdl_shaft_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, PSY.FiveMassShaft, A, TG, P}}, @@ -67,25 +69,26 @@ function mdl_shaft_ode!( τm = inner_vars[τm_var] #Get parameters - shaft = PSY.get_shaft(dynamic_device) - H = PSY.get_H(shaft) - H_hp = PSY.get_H_hp(shaft) - H_ip = PSY.get_H_ip(shaft) - H_lp = PSY.get_H_lp(shaft) - H_ex = PSY.get_H_ex(shaft) - D = PSY.get_D(shaft) - D_hp = PSY.get_D_hp(shaft) - D_ip = PSY.get_D_ip(shaft) - D_lp = PSY.get_D_lp(shaft) - D_ex = PSY.get_D_ex(shaft) - D_12 = PSY.get_D_12(shaft) - D_23 = PSY.get_D_23(shaft) - D_34 = PSY.get_D_34(shaft) - D_45 = PSY.get_D_45(shaft) - K_hp = PSY.get_K_hp(shaft) - K_ip = PSY.get_K_ip(shaft) - K_lp = PSY.get_K_lp(shaft) - K_ex = PSY.get_K_ex(shaft) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SingleMass) + internal_params = @view device_parameters[local_ix_params] + H, + H_hp, + H_ip, + H_lp, + H_ex, + D, + D_hp, + D_ip, + D_lp, + D_ex, + D_12, + D_23, + D_34, + D_45, + K_hp, + K_ip, + K_lp, + K_ex = internal_params #Compute 10 states ODEs #15.51 output_ode[local_ix[1]] = 2.0 * π * f0 * (ω - ω_sys) diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index 54a5f9770..219e69678 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -19,29 +19,33 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGFixed, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Update inner vars - P_ref = get_P_ref(device) - inner_vars[τm_var] = P_ref * PSY.get_efficiency(PSY.get_prime_mover(device)) - + local_ix_params = get_local_parameter_ix(device, PSY.TGFixed) + internal_params = @view device_parameters[local_ix_params] + efficiency = internal_params[1] + P_ref = device_parameters[P_ref_ix] + inner_vars[τm_var] = P_ref * efficiency return end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGTypeI, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - ω_ref = get_ω_ref(device) - P_ref = get_P_ref(device) + ω_ref = device_parameters[ω_ref_ix] + P_ref = device_parameters[P_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.TGTypeI) @@ -57,14 +61,10 @@ function mdl_tg_ode!( ω = @view device_states[external_ix] #Get Parameters - tg = PSY.get_prime_mover(device) - inv_R = PSY.get_R(tg) < eps() ? 0.0 : (1.0 / PSY.get_R(tg)) - Ts = PSY.get_Ts(tg) - Tc = PSY.get_Tc(tg) - T3 = PSY.get_T3(tg) - T4 = PSY.get_T4(tg) - T5 = PSY.get_T5(tg) - V_min, V_max = PSY.get_valve_position_limits(tg) + local_ix_params = get_local_parameter_ix(device, PSY.TGTypeI) + internal_params = @view device_parameters[local_ix_params] + R, Ts, Tc, T3, T4, T5, V_min, V_max = internal_params + inv_R = R < eps() ? 0.0 : (1.0 / R) #Compute auxiliary parameters P_in_sat = clamp(P_ref + inv_R * (ω_ref - ω[1]), V_min, V_max) @@ -88,14 +88,15 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGTypeII, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - ω_ref = get_ω_ref(device) - P_ref = get_P_ref(device) + ω_ref = device_parameters[ω_ref_ix] + P_ref = device_parameters[P_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.TGTypeII) @@ -108,11 +109,11 @@ function mdl_tg_ode!( external_ix = get_input_port_ix(device, PSY.TGTypeII) ω = @view device_states[external_ix] - #Get Parameters - tg = PSY.get_prime_mover(device) - inv_R = PSY.get_R(tg) < eps() ? 0.0 : (1.0 / PSY.get_R(tg)) - T1 = PSY.get_T1(tg) - T2 = PSY.get_T2(tg) + #Get parameters + local_ix_params = get_local_parameter_ix(device, PSY.TGTypeII) + internal_params = @view device_parameters[local_ix_params] + R, T1, T2 = internal_params + inv_R = R < eps() ? 0.0 : (1.0 / R) #Compute block derivatives y_ll1, dxg_dt = lead_lag(inv_R * (ω_ref - ω[1]), xg, 1.0, T1, T2) @@ -130,6 +131,7 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.SteamTurbineGov1, P}}, @@ -138,7 +140,7 @@ function mdl_tg_ode!( #Obtain TG tg = PSY.get_prime_mover(device) #Obtain references - P_ref = get_P_ref(device) + P_ref = device_parameters[P_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, typeof(tg)) @@ -153,13 +155,16 @@ function mdl_tg_ode!( ω = @view device_states[external_ix] #Get Parameters - tg = PSY.get_prime_mover(device) - inv_R = PSY.get_R(tg) < eps() ? 0.0 : (1.0 / PSY.get_R(tg)) - T1 = PSY.get_T1(tg) - T2 = PSY.get_T2(tg) - V_min, V_max = PSY.get_valve_position_limits(tg) - T3 = PSY.get_T3(tg) - D_T = PSY.get_D_T(tg) + local_ix_params = get_local_parameter_ix(device, PSY.SteamTurbineGov1) + internal_params = @view device_parameters[local_ix_params] + R, + T1, + V_min, + V_max, + T2, + T3, + D_T = internal_params + inv_R = R < eps() ? 0.0 : (1.0 / R) #Compute auxiliary parameters ref_in = inv_R * (P_ref - (ω[1] - 1.0)) @@ -182,13 +187,14 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.GasTG, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - P_ref = get_P_ref(device) + P_ref = device_parameters[P_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.GasTG) @@ -204,18 +210,13 @@ function mdl_tg_ode!( ω = @view device_states[external_ix] #Get Parameters - tg = PSY.get_prime_mover(device) - inv_R = PSY.get_R(tg) < eps() ? 0.0 : (1.0 / PSY.get_R(tg)) - T1 = PSY.get_T1(tg) - T2 = PSY.get_T2(tg) - T3 = PSY.get_T3(tg) - D_turb = PSY.get_D_turb(tg) - AT = PSY.get_AT(tg) - KT = PSY.get_Kt(tg) - V_min, V_max = PSY.get_V_lim(tg) + local_ix_params = get_local_parameter_ix(device, PSY.GasTG) + internal_params = @view device_parameters[local_ix_params] + R, T1, T2, T3, AT, Kt, V_min, V_max, D_turb = internal_params + inv_R = R < eps() ? 0.0 : (1.0 / R) #Compute auxiliary parameters - x_in = min((P_ref - inv_R * (ω[1] - 1.0)), (AT + KT * (AT - x_g3))) + x_in = min((P_ref - inv_R * (ω[1] - 1.0)), (AT + Kt * (AT - x_g3))) #Compute block derivatives x_g1_sat, dxg1_dt = low_pass_nonwindup(x_in, x_g1, 1.0, T1, V_min, V_max) @@ -239,14 +240,15 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.HydroTurbineGov, P}}, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - P_ref = get_P_ref(device) - ω_ref = get_ω_ref(device) + P_ref = device_parameters[P_ref_ix] + ω_ref = device_parameters[ω_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.HydroTurbineGov) @@ -264,19 +266,20 @@ function mdl_tg_ode!( Δω = ω - ω_ref #Get Parameters - tg = PSY.get_prime_mover(device) - R = PSY.get_R(tg) - r = PSY.get_r(tg) - Tr = PSY.get_Tr(tg) - Tf = PSY.get_Tf(tg) - Tg = PSY.get_Tg(tg) - - VELM = PSY.get_VELM(tg) - G_min, G_max = PSY.get_gate_position_limits(tg) - Tw = PSY.get_Tw(tg) - At = PSY.get_At(tg) - D_T = PSY.get_D_T(tg) - q_nl = PSY.get_q_nl(tg) + local_ix_params = get_local_parameter_ix(device, PSY.HydroTurbineGov) + internal_params = @view device_parameters[local_ix_params] + R, + r, + Tr, + Tf, + Tg, + VELM, + G_min, + G_max, + Tw, + At, + D_T, + q_nl = internal_params #Compute block derivatives c, dxg2_dt = pi_block_nonwindup(x_g1, x_g2, 1.0 / r, 1.0 / (r * Tr), G_min, G_max) diff --git a/src/models/inverter_models/DCside_models.jl b/src/models/inverter_models/DCside_models.jl index 9a1269cc0..e7a7d813d 100644 --- a/src/models/inverter_models/DCside_models.jl +++ b/src/models/inverter_models/DCside_models.jl @@ -9,6 +9,7 @@ end function mdl_DCside_ode!( ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ @@ -22,7 +23,8 @@ function mdl_DCside_ode!( F <: PSY.Filter, L <: Union{Nothing, PSY.InverterLimiter}, } - + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.FixedDCSource) + internal_params = @view device_parameters[local_ix_params] #Update inner_vars - inner_vars[Vdc_var] = PSY.get_voltage(PSY.get_dc_source(dynamic_device)) + inner_vars[Vdc_var] = internal_params[1] end diff --git a/src/models/inverter_models/converter_models.jl b/src/models/inverter_models/converter_models.jl index bfecc4668..8b14de0e5 100644 --- a/src/models/inverter_models/converter_models.jl +++ b/src/models/inverter_models/converter_models.jl @@ -9,6 +9,7 @@ end function mdl_converter_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{PSY.AverageConverter, O, IC, DC, P, F, L}, @@ -40,6 +41,7 @@ end function mdl_converter_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -68,22 +70,28 @@ function mdl_converter_ode!( Iq_cmd = inner_vars[Iq_ic_var] #Get Converter parameters + local_ix_params = + get_local_parameter_ix(dynamic_device, PSY.RenewableEnergyConverterTypeA) + internal_params = @view device_parameters[local_ix_params] + T_g, + Rrpwr, + Brkpt, + Zerox, + Lvpl1, + Vo_lim, + Lv_pnt0, + Lv_pnt1, + Io_lim, + T_fltr, + K_hv, + Iqr_min, + Iqr_max, + Accel, + Q_ref, + R_source, + X_source = internal_params converter = PSY.get_converter(dynamic_device) - T_g = PSY.get_T_g(converter) - Rrpwr = PSY.get_Rrpwr(converter) - Brkpt = PSY.get_Brkpt(converter) - Zerox = PSY.get_Zerox(converter) - Lvpl1 = PSY.get_Lvpl1(converter) - Vo_lim = PSY.get_Vo_lim(converter) - Lv_pnt0, Lv_pnt1 = PSY.get_Lv_pnts(converter) - # Io_lim = PSY.get_Io_lim(converter) - T_fltr = PSY.get_T_fltr(converter) - K_hv = PSY.get_K_hv(converter) - Iqr_min, Iqr_max = PSY.get_Iqr_lims(converter) Lvpl_sw = PSY.get_Lvpl_sw(converter) - Q_ref = PSY.get_Q_ref(converter) - R_source = PSY.get_R_source(converter) - X_source = PSY.get_X_source(converter) #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.RenewableEnergyConverterTypeA) @@ -173,6 +181,7 @@ end function mdl_converter_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ diff --git a/src/models/inverter_models/filter_models.jl b/src/models/inverter_models/filter_models.jl index aac31ac46..f710db629 100644 --- a/src/models/inverter_models/filter_models.jl +++ b/src/models/inverter_models/filter_models.jl @@ -35,6 +35,7 @@ end function mdl_filter_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -59,14 +60,12 @@ function mdl_filter_ode!( Vi_cnv = inner_vars[Vi_cnv_var] #Get parameters - filter = PSY.get_filter(dynamic_device) f0 = get_system_base_frequency(dynamic_device) ωb = 2 * pi * f0 - lf = PSY.get_lf(filter) - rf = PSY.get_rf(filter) - cf = PSY.get_cf(filter) - lg = PSY.get_lg(filter) - rg = PSY.get_rg(filter) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.LCLFilter) + internal_params = @view device_parameters[local_ix_params] + lf, rf, cf, lg, rg = internal_params + basepower = PSY.get_base_power(dynamic_device) sys_Sbase = get_system_base_power(dynamic_device) @@ -117,6 +116,7 @@ end function mdl_filter_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -136,9 +136,9 @@ function mdl_filter_ode!( ratio_power = basepower / sys_Sbase #Obtain parameters - filt = PSY.get_filter(dynamic_device) - rf = PSY.get_rf(filt) - lf = PSY.get_lf(filt) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.RLFilter) + internal_params = @view device_parameters[local_ix_params] + rf, lf = internal_params Vr_cnv = inner_vars[Vr_cnv_var] Vi_cnv = inner_vars[Vi_cnv_var] diff --git a/src/models/inverter_models/frequency_estimator_models.jl b/src/models/inverter_models/frequency_estimator_models.jl index 9f68a392e..2b2fb922d 100644 --- a/src/models/inverter_models/frequency_estimator_models.jl +++ b/src/models/inverter_models/frequency_estimator_models.jl @@ -9,6 +9,7 @@ end function mdl_freq_estimator_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicInverter{C, O, IC, DC, PSY.KauraPLL, F, L}}, @@ -27,10 +28,10 @@ function mdl_freq_estimator_ode!( Vi_filter = device_states[external_ix[2]] #Get parameters - pll_control = PSY.get_freq_estimator(dynamic_device) - ω_lp = PSY.get_ω_lp(pll_control) - kp_pll = PSY.get_kp_pll(pll_control) - ki_pll = PSY.get_ki_pll(pll_control) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.KauraPLL) + internal_params = @view device_parameters[local_ix_params] + ω_lp, kp_pll, ki_pll = internal_params + f0 = get_system_base_frequency(dynamic_device) ωb = 2.0 * pi * f0 @@ -73,6 +74,7 @@ end function mdl_freq_estimator_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -134,6 +136,7 @@ end function mdl_freq_estimator_ode!( ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -147,10 +150,10 @@ function mdl_freq_estimator_ode!( F <: PSY.Filter, L <: Union{Nothing, PSY.InverterLimiter}, } - #Get parameters - pll_control = PSY.get_freq_estimator(dynamic_device) - frequency = PSY.get_frequency(pll_control) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.FixedFrequency) + internal_params = @view device_parameters[local_ix_params] + frequency = internal_params[1] #Update inner_vars #PLL frequency diff --git a/src/models/inverter_models/inner_control_models.jl b/src/models/inverter_models/inner_control_models.jl index a538939f0..001cc95f2 100644 --- a/src/models/inverter_models/inner_control_models.jl +++ b/src/models/inverter_models/inner_control_models.jl @@ -31,6 +31,7 @@ end function _mdl_ode_RE_inner_controller_B!( inner_controller_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_controller_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, + inner_controller_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::Val{0}, inner_control::PSY.RECurrentControlB, dynamic_device::DynamicWrapper{ @@ -52,12 +53,19 @@ function _mdl_ode_RE_inner_controller_B!( #Get Current Controller parameters PQ_Flag = PSY.get_PQ_Flag(inner_control) - dbd1, dbd2 = PSY.get_dbd_pnts(inner_control) - K_qv = PSY.get_K_qv(inner_control) - I_ql1, I_qh1 = PSY.get_Iqinj_lim(inner_control) - V_ref0 = PSY.get_V_ref0(inner_control) - T_rv = PSY.get_T_rv(inner_control) - T_iq = PSY.get_T_iq(inner_control) + Vdip_min, + Vdip_max, + T_rv, + dbd1, + dbd2, + K_qv, + I_ql1, + I_qh1, + V_ref0, + K_vp, + K_vi, + T_iq, + I_max = inner_controller_parameters #Read local states Vt_filt = inner_controller_states[1] @@ -86,6 +94,7 @@ end function _mdl_ode_RE_inner_controller_B!( inner_controller_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_controller_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, + inner_controller_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::Val{1}, inner_control::PSY.RECurrentControlB, dynamic_device::DynamicWrapper{ @@ -107,13 +116,19 @@ function _mdl_ode_RE_inner_controller_B!( #Get Current Controller parameters PQ_Flag = PSY.get_PQ_Flag(inner_control) - K_vp = PSY.get_K_vp(inner_control) - K_vi = PSY.get_K_vi(inner_control) - V_ref0 = PSY.get_V_ref0(inner_control) - dbd1, dbd2 = PSY.get_dbd_pnts(inner_control) - K_qv = PSY.get_K_qv(inner_control) - I_ql1, I_qh1 = PSY.get_Iqinj_lim(inner_control) - T_rv = PSY.get_T_rv(inner_control) + Vdip_min, + Vdip_max, + T_rv, + dbd1, + dbd2, + K_qv, + I_ql1, + I_qh1, + V_ref0, + K_vp, + K_vi, + T_iq, + I_max = inner_controller_parameters #Read local states Vt_filt = inner_controller_states[1] @@ -149,16 +164,16 @@ end function mdl_inner_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ - PSY.DynamicInverter{C, O, PSY.VoltageModeControl, DC, P, F, L}, + PSY.DynamicInverter{C, O, PSY.VoltageModeControl, DC, P, PSY.LCLFilter, L}, }, ) where { C <: PSY.Converter, O <: PSY.OuterControl, DC <: PSY.DCSource, P <: PSY.FrequencyEstimator, - F <: PSY.Filter, L <: Union{Nothing, PSY.InverterLimiter}, } @@ -178,22 +193,15 @@ function mdl_inner_ode!( Vdc = inner_vars[Vdc_var] #Get Voltage Controller parameters - inner_control = PSY.get_inner_control(dynamic_device) filter = PSY.get_filter(dynamic_device) - kpv = PSY.get_kpv(inner_control) - kiv = PSY.get_kiv(inner_control) - kffi = PSY.get_kffi(inner_control) - cf = PSY.get_cf(filter) - rv = PSY.get_rv(inner_control) - lv = PSY.get_lv(inner_control) + filter_ix_params = get_local_parameter_ix(dynamic_device, typeof(filter)) + filter_params = @view device_parameters[filter_ix_params] + cf = filter_params[3] + lf = filter_params[1] - #Get Current Controller parameters - kpc = PSY.get_kpc(inner_control) - kic = PSY.get_kic(inner_control) - kffv = PSY.get_kffv(inner_control) - lf = PSY.get_lf(filter) - ωad = PSY.get_ωad(inner_control) - kad = PSY.get_kad(inner_control) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.VoltageModeControl) + internal_params = @view device_parameters[local_ix_params] + kpv, kiv, kffv, rv, lv, kpc, kic, kffi, ωad, kad = internal_params #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.VoltageModeControl) @@ -259,6 +267,7 @@ end function mdl_inner_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, PSY.CurrentModeControl, DC, P, F, L}, @@ -331,6 +340,7 @@ end function mdl_inner_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, PSY.RECurrentControlB, DC, P, F, L}, @@ -349,16 +359,18 @@ function mdl_inner_ode!( #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.RECurrentControlB) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.RECurrentControlB) #Define internal states for Inner Control internal_states = @view device_states[local_ix] internal_ode = @view output_ode[local_ix] - + internal_parameters = @view device_parameters[local_ix_params] # TODO: Voltage Dip Freeze logic #Dispatch inner controller ODE calculation _mdl_ode_RE_inner_controller_B!( internal_ode, internal_states, + internal_parameters, Val(Q_Flag), inner_control, dynamic_device, diff --git a/src/models/inverter_models/outer_control_models.jl b/src/models/inverter_models/outer_control_models.jl index 14e2c5891..a57dcb095 100644 --- a/src/models/inverter_models/outer_control_models.jl +++ b/src/models/inverter_models/outer_control_models.jl @@ -16,6 +16,7 @@ end function _mdl_ode_RE_active_controller_AB!( active_controller_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, active_controller_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, p_elec_out::ACCEPTED_REAL_TYPES, ω_sys::ACCEPTED_REAL_TYPES, Vt_filt::ACCEPTED_REAL_TYPES, @@ -46,24 +47,40 @@ function _mdl_ode_RE_active_controller_AB!( } #Obtain external parameters - p_ref = get_P_ref(dynamic_device) - ω_ref = get_ω_ref(dynamic_device) + p_ref = device_parameters[P_ref_ix] + ω_ref = device_parameters[ω_ref_ix] # To do: Obtain proper frequency for a plant. For now using the system frequency. ω_plant = ω_sys #Obtain additional Active Power Controller parameters - K_pg = PSY.get_K_pg(active_power_control) - K_ig = PSY.get_K_ig(active_power_control) - T_p = PSY.get_T_p(active_power_control) - fdbd1, fdbd2 = PSY.get_fdbd_pnts(active_power_control) - fe_min, fe_max = PSY.get_fe_lim(active_power_control) - P_min, P_max = PSY.get_P_lim(active_power_control) - T_g = PSY.get_T_g(active_power_control) - D_dn = PSY.get_D_dn(active_power_control) - D_up = PSY.get_D_up(active_power_control) - dP_min, dP_max = PSY.get_dP_lim(active_power_control) - P_min_inner, P_max_inner = PSY.get_P_lim_inner(active_power_control) - T_pord = PSY.get_T_pord(active_power_control) + local_ix_params = get_local_parameter_ix( + dynamic_device, + PSY.OuterControl{ + PSY.ActiveRenewableControllerAB, + PSY.ReactiveRenewableControllerAB, + }, + ) + internal_params = @view device_parameters[local_ix_params] + active_n_params = get_n_params(active_power_control) + active_ix_range_params = 1:active_n_params + active_params = @view internal_params[active_ix_range_params] + K_pg, + K_ig, + T_p, + fdbd1, + fdbd2, + fe_min, + fe_max, + P_min, + P_max, + T_g, + D_dn, + D_up, + dP_min, + dP_max, + P_min_inner, + P_max_inner, + T_pord = active_params #Define internal states for outer control p_flt = active_controller_states[1] @@ -108,6 +125,7 @@ end function _mdl_ode_RE_active_controller_AB!( active_controller_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, active_controller_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, p_elec_out::ACCEPTED_REAL_TYPES, ω_sys::ACCEPTED_REAL_TYPES, Vt_filt::ACCEPTED_REAL_TYPES, @@ -138,9 +156,36 @@ function _mdl_ode_RE_active_controller_AB!( } #Obtain external parameters - p_ref = get_P_ref(dynamic_device) + p_ref = device_parameters[P_ref_ix] #Obtain additional Active Power Controller parameters - T_pord = PSY.get_T_pord(active_power_control) + local_ix_params = get_local_parameter_ix( + dynamic_device, + PSY.OuterControl{ + PSY.ActiveRenewableControllerAB, + PSY.ReactiveRenewableControllerAB, + }, + ) + internal_params = @view device_parameters[local_ix_params] + active_n_params = get_n_params(active_power_control) + active_ix_range_params = 1:active_n_params + active_params = @view internal_params[active_ix_range_params] + K_pg, + K_ig, + T_p, + fdbd1, + fdbd2, + fe_min, + fe_max, + P_min, + P_max, + T_g, + D_dn, + D_up, + dP_min, + dP_max, + P_min_inner, + P_max_inner, + T_pord = active_params #Define internal states for outer control p_ord = active_controller_states[1] @@ -167,6 +212,7 @@ end function _mdl_ode_RE_reactive_controller_AB!( reactive_controller_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, reactive_controller_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, q_elec_out::ACCEPTED_REAL_TYPES, Vt_filt::ACCEPTED_REAL_TYPES, ::Val{0}, @@ -198,23 +244,45 @@ function _mdl_ode_RE_reactive_controller_AB!( } #Obtain external parameters - q_ref = get_Q_ref(dynamic_device) + q_ref = device_parameters[Q_ref_ix] # Get Reactive Controller parameters - T_fltr = PSY.get_T_fltr(reactive_power_control) - K_p = PSY.get_K_p(reactive_power_control) - K_i = PSY.get_K_i(reactive_power_control) - T_ft = PSY.get_T_ft(reactive_power_control) - T_fv = PSY.get_T_fv(reactive_power_control) - # V_frz not implemented yet - # V_frz = PSY.get_V_frz(reactive_power_control) - e_min, e_max = PSY.get_e_lim(reactive_power_control) - dbd1, dbd2 = PSY.get_dbd_pnts(reactive_power_control) - Q_min, Q_max = PSY.get_Q_lim(reactive_power_control) - Q_min_inner, Q_max_inner = PSY.get_Q_lim_inner(reactive_power_control) - V_min, V_max = PSY.get_V_lim(reactive_power_control) - K_qp = PSY.get_K_qp(reactive_power_control) - K_qi = PSY.get_K_qi(reactive_power_control) + local_ix_params = get_local_parameter_ix( + dynamic_device, + PSY.OuterControl{ + PSY.ActiveRenewableControllerAB, + PSY.ReactiveRenewableControllerAB, + }, + ) + outer_control = PSY.get_outer_control(dynamic_device) + active_power_control = PSY.get_active_power_control(outer_control) + internal_params = @view device_parameters[local_ix_params] + active_n_params = get_n_params(active_power_control) + reactive_n_params = get_n_params(reactive_power_control) + reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) + reactive_params = @view internal_params[reactive_ix_range_params] + T_fltr, + K_p, + K_i, + T_ft, + T_fv, + V_frz, # V_frz not implemented yet + R_c, + X_c, + K_c, + e_min, + e_max, + dbd1, + dbd2, + Q_min, + Q_max, + T_p, + Q_min_inner, + Q_max_inner, + V_min, + V_max, + K_qp, + K_qi = reactive_params #Define internal states for Reactive Control q_flt = reactive_controller_states[1] @@ -251,6 +319,7 @@ end function _mdl_ode_RE_reactive_controller_AB!( reactive_controller_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, reactive_controller_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, q_elec_out::ACCEPTED_REAL_TYPES, Vt_filt::ACCEPTED_REAL_TYPES, ::Val{0}, @@ -281,19 +350,44 @@ function _mdl_ode_RE_reactive_controller_AB!( L <: Union{Nothing, PSY.InverterLimiter}, } #Obtain external parameters - q_ref = get_Q_ref(dynamic_device) - + q_ref = device_parameters[Q_ref_ix] + outer_control = PSY.get_outer_control(dynamic_device) + active_power_control = PSY.get_active_power_control(outer_control) # Get Reactive Controller parameters - T_fltr = PSY.get_T_fltr(reactive_power_control) - K_p = PSY.get_K_p(reactive_power_control) - K_i = PSY.get_K_i(reactive_power_control) - T_ft = PSY.get_T_ft(reactive_power_control) - T_fv = PSY.get_T_fv(reactive_power_control) - # V_frz not implemented yet - # V_frz = PSY.get_V_frz(reactive_power_control) - e_min, e_max = PSY.get_e_lim(reactive_power_control) - dbd1, dbd2 = PSY.get_dbd_pnts(reactive_power_control) - Q_min, Q_max = PSY.get_Q_lim(reactive_power_control) + local_ix_params = get_local_parameter_ix( + dynamic_device, + PSY.OuterControl{ + PSY.ActiveRenewableControllerAB, + PSY.ReactiveRenewableControllerAB, + }, + ) + internal_params = @view device_parameters[local_ix_params] + active_n_params = get_n_params(active_power_control) + reactive_n_params = get_n_params(reactive_power_control) + reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) + reactive_params = @view internal_params[reactive_ix_range_params] + T_fltr, + K_p, + K_i, + T_ft, + T_fv, + V_frz, # V_frz not implemented yet + R_c, + X_c, + K_c, + e_min, + e_max, + dbd1, + dbd2, + Q_min, + Q_max, + T_p, + Q_min_inner, + Q_max_inner, + V_min, + V_max, + K_qp, + K_qi = reactive_params #Define internal states for Reactive Control q_flt = reactive_controller_states[1] @@ -328,6 +422,7 @@ end function _mdl_ode_RE_reactive_controller_AB!( reactive_controller_ode, reactive_controller_states, + device_parameters, q_elec_out, Vt_filt, ::Val{1}, @@ -358,32 +453,52 @@ function _mdl_ode_RE_reactive_controller_AB!( L <: Union{Nothing, PSY.InverterLimiter}, } #Obtain external parameters - V_ref = get_V_ref(dynamic_device) + V_ref = device_parameters[V_ref_ix] #Obtain regulated voltage (assumed to be terminal voltage) V_reg = sqrt(inner_vars[Vr_inv_var]^2 + inner_vars[Vi_inv_var]^2) I_R = inner_vars[Ir_inv_var] I_I = inner_vars[Ii_inv_var] - # Get Reactive Controller parameters - T_fltr = PSY.get_T_fltr(reactive_power_control) - K_p = PSY.get_K_p(reactive_power_control) - K_c = PSY.get_K_c(reactive_power_control) - R_c = PSY.get_R_c(reactive_power_control) - X_c = PSY.get_R_c(reactive_power_control) VC_Flag = PSY.get_VC_Flag(reactive_power_control) - K_i = PSY.get_K_i(reactive_power_control) - T_ft = PSY.get_T_ft(reactive_power_control) - T_fv = PSY.get_T_fv(reactive_power_control) - # V_frz not implemented yet - # V_frz = PSY.get_V_frz(reactive_power_control) - e_min, e_max = PSY.get_e_lim(reactive_power_control) - dbd1, dbd2 = PSY.get_dbd_pnts(reactive_power_control) - Q_min, Q_max = PSY.get_Q_lim(reactive_power_control) - Q_min_inner, Q_max_inner = PSY.get_Q_lim_inner(reactive_power_control) - V_min, V_max = PSY.get_V_lim(reactive_power_control) - K_qp = PSY.get_K_qp(reactive_power_control) - K_qi = PSY.get_K_qi(reactive_power_control) + + # Get Reactive Controller parameters + local_ix_params = get_local_parameter_ix( + dynamic_device, + PSY.OuterControl{ + PSY.ActiveRenewableControllerAB, + PSY.ReactiveRenewableControllerAB, + }, + ) + internal_params = @view device_parameters[local_ix_params] + outer_control = PSY.get_outer_control(dynamic_device) + active_power_control = PSY.get_active_power_control(outer_control) + active_n_params = get_n_params(active_power_control) + reactive_n_params = get_n_params(reactive_power_control) + reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) + reactive_params = @view internal_params[reactive_ix_range_params] + T_fltr, + K_p, + K_i, + T_ft, + T_fv, + V_frz, # V_frz not implemented yet + R_c, + X_c, + K_c, + e_min, + e_max, + dbd1, + dbd2, + Q_min, + Q_max, + T_p, + Q_min_inner, + Q_max_inner, + V_min, + V_max, + K_qp, + K_qi = reactive_params #Define internal states for Reactive Control V_cflt = reactive_controller_states[1] @@ -436,6 +551,7 @@ end function _mdl_ode_RE_reactive_controller_AB!( reactive_controller_ode, reactive_controller_states, + device_parameters, q_elec_out, Vt_filt, ::Val{1}, @@ -466,7 +582,7 @@ function _mdl_ode_RE_reactive_controller_AB!( L <: Union{Nothing, PSY.InverterLimiter}, } #Obtain external parameters - V_ref = get_V_ref(dynamic_device) + V_ref = device_parameters[V_ref_ix] #Obtain regulated voltage (assumed to be terminal voltage) V_reg = sqrt(inner_vars[Vr_inv_var]^2 + inner_vars[Vi_inv_var]^2) @@ -474,21 +590,43 @@ function _mdl_ode_RE_reactive_controller_AB!( I_I = inner_vars[Ii_inv_var] # Get Reactive Controller parameters - T_fltr = PSY.get_T_fltr(reactive_power_control) - K_p = PSY.get_K_p(reactive_power_control) - K_c = PSY.get_K_c(reactive_power_control) - R_c = PSY.get_R_c(reactive_power_control) - X_c = PSY.get_R_c(reactive_power_control) VC_Flag = PSY.get_VC_Flag(reactive_power_control) - K_i = PSY.get_K_i(reactive_power_control) - T_ft = PSY.get_T_ft(reactive_power_control) - T_fv = PSY.get_T_fv(reactive_power_control) - # V_frz not implemented yet - # V_frz = PSY.get_V_frz(reactive_power_control) - e_min, e_max = PSY.get_e_lim(reactive_power_control) - dbd1, dbd2 = PSY.get_dbd_pnts(reactive_power_control) - Q_min, Q_max = PSY.get_Q_lim(reactive_power_control) - V_min, V_max = PSY.get_V_lim(reactive_power_control) + local_ix_params = get_local_parameter_ix( + dynamic_device, + PSY.OuterControl{ + PSY.ActiveRenewableControllerAB, + PSY.ReactiveRenewableControllerAB, + }, + ) + internal_params = @view device_parameters[local_ix_params] + outer_control = PSY.get_outer_control(dynamic_device) + active_power_control = PSY.get_active_power_control(outer_control) + active_n_params = get_n_params(active_power_control) + reactive_n_params = get_n_params(reactive_power_control) + reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) + reactive_params = @view internal_params[reactive_ix_range_params] + T_fltr, + K_p, + K_i, + T_ft, + T_fv, + V_frz, # V_frz not implemented yet + R_c, + X_c, + K_c, + e_min, + e_max, + dbd1, + dbd2, + Q_min, + Q_max, + T_p, + Q_min_inner, + Q_max_inner, + V_min, + V_max, + K_qp, + K_qi = reactive_params #Define internal states for Reactive Control V_cflt = reactive_controller_states[1] @@ -535,6 +673,7 @@ end function mdl_outer_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -570,25 +709,20 @@ function mdl_outer_ode!( #Obtain inner variables for component ω_pll = inner_vars[ω_freq_estimator_var] - #Get Active Power Controller parameters - outer_control = PSY.get_outer_control(dynamic_device) - active_power_control = PSY.get_active_power_control(outer_control) - Ta = PSY.get_Ta(active_power_control) #VSM Inertia constant - kd = PSY.get_kd(active_power_control) #VSM damping constant - kω = PSY.get_kω(active_power_control) #Frequency droop gain - f0 = get_system_base_frequency(dynamic_device) - ωb = 2 * pi * f0 #Rated angular frequency + local_ix_params = get_local_parameter_ix( + dynamic_device, + PSY.OuterControl{PSY.VirtualInertia, PSY.ReactivePowerDroop}, + ) + internal_params = @view device_parameters[local_ix_params] + Ta, kd, kω, kq, ωf = internal_params - #Get Reactive Power Controller parameters - reactive_power_control = PSY.get_reactive_power_control(outer_control) - kq = PSY.get_kq(reactive_power_control) #Reactive power droop gain - ωf = PSY.get_ωf(reactive_power_control) #Reactive power filter cutoff frequency + q_ref = device_parameters[Q_ref_ix] + V_ref = device_parameters[V_ref_ix] + ω_ref = device_parameters[ω_ref_ix] + p_ref = device_parameters[P_ref_ix] - #Obtain external parameters - p_ref = get_P_ref(dynamic_device) - ω_ref = get_ω_ref(dynamic_device) - V_ref = get_V_ref(dynamic_device) - q_ref = get_Q_ref(dynamic_device) + f0 = get_system_base_frequency(dynamic_device) + ωb = 2 * pi * f0 #Rated angular frequency #Obtain indices for component w/r to device local_ix = get_local_state_ix( @@ -625,6 +759,7 @@ end function mdl_outer_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -671,10 +806,10 @@ function mdl_outer_ode!( ωf = PSY.get_ωf(reactive_power_control) #Reactive power filter cutoff frequency #Obtain external parameters - p_ref = get_P_ref(dynamic_device) - ω_ref = get_ω_ref(dynamic_device) - V_ref = get_V_ref(dynamic_device) - q_ref = get_Q_ref(dynamic_device) + p_ref = device_parameters[P_ref_ix] + ω_ref = device_parameters[ω_ref_ix] + V_ref = device_parameters[V_ref_ix] + q_ref = device_parameters[Q_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix( @@ -717,6 +852,7 @@ end function mdl_outer_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -762,9 +898,9 @@ function mdl_outer_ode!( k2 = PSY.get_k2(reactive_power_control) #Obtain external parameters - p_ref = get_P_ref(dynamic_device) - V_ref = get_V_ref(dynamic_device) - q_ref = get_Q_ref(dynamic_device) + p_ref = device_parameters[P_ref_ix] + V_ref = device_parameters[V_ref_ix] + q_ref = device_parameters[Q_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix( @@ -811,6 +947,7 @@ end function mdl_outer_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -861,8 +998,8 @@ function mdl_outer_ode!( ωf = PSY.get_ωf(reactive_power_control) #Reactive power filter cutoff frequency #Obtain external parameters - p_ref = get_P_ref(dynamic_device) - q_ref = get_Q_ref(dynamic_device) + p_ref = device_parameters[P_ref_ix] + q_ref = device_parameters[Q_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix( @@ -904,6 +1041,7 @@ end function mdl_outer_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -977,6 +1115,14 @@ function mdl_outer_ode!( PSY.ReactiveRenewableControllerAB, }, ) + local_ix_params = get_local_parameter_ix( + dynamic_device, + PSY.OuterControl{ + PSY.ActiveRenewableControllerAB, + PSY.ReactiveRenewableControllerAB, + }, + ) + internal_states = @view device_states[local_ix] internal_ode = @view output_ode[local_ix] active_n_states = PSY.get_n_states(active_power_control) @@ -992,6 +1138,7 @@ function mdl_outer_ode!( _mdl_ode_RE_active_controller_AB!( active_ode, active_states, + device_parameters, p_elec_out, ω_sys, Vt_filt, @@ -1005,6 +1152,7 @@ function mdl_outer_ode!( _mdl_ode_RE_reactive_controller_AB!( reactive_ode, reactive_states, + device_parameters, q_elec_out, Vt_filt, Val(Ref_Flag), diff --git a/src/models/load_models.jl b/src/models/load_models.jl index 1ad8a88cf..91df466bb 100644 --- a/src/models/load_models.jl +++ b/src/models/load_models.jl @@ -37,13 +37,16 @@ Ii_im = V_i * P0 * (V^(α - 2) / V0^α) - V_r * Q0 * (V^(β - 2)/ V0^β) """ function mdl_zip_load!( + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, current_i::AbstractArray{T}, wrapper::StaticLoadWrapper, ) where {T <: ACCEPTED_REAL_TYPES} - # Read power flow voltages + # Load device parameters + _, _, P_power, P_current, P_impedance, Q_power, Q_current, Q_impedance = + device_parameters #V0_mag_inv = 1.0 / get_V_ref(wrapper) V0_mag_inv = 1.0 / PSY.get_magnitude(PSY.get_bus(wrapper)) V0_mag_sq_inv = V0_mag_inv^2 @@ -52,13 +55,6 @@ function mdl_zip_load!( V_mag_inv = 1.0 / V_mag V_mag_sq_inv = V_mag_inv^2 - # Load device parameters - P_power = get_P_power(wrapper) - P_current = get_P_current(wrapper) - P_impedance = get_P_impedance(wrapper) - Q_power = get_Q_power(wrapper) - Q_current = get_Q_current(wrapper) - Q_impedance = get_Q_impedance(wrapper) exp_params = get_exp_params(wrapper) Ir_exp = zero(T) Ii_exp = zero(T) diff --git a/src/models/source_models.jl b/src/models/source_models.jl index a40342875..c9e673409 100644 --- a/src/models/source_models.jl +++ b/src/models/source_models.jl @@ -1,4 +1,5 @@ function mdl_source!( + device_parameters, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -6,11 +7,9 @@ function mdl_source!( static_device::StaticWrapper{PSY.Source}, ) where {T <: ACCEPTED_REAL_TYPES} #Load device parameters - V_R = get_V_ref(static_device) * cos(get_θ_ref(static_device)) - V_I = get_V_ref(static_device) * sin(get_θ_ref(static_device)) - # TODO: field forwarding - R_th = PSY.get_R_th(static_device.device) - X_th = PSY.get_X_th(static_device.device) + R_th, X_th, internal_voltage, internal_angle = device_parameters + V_R = internal_voltage * cos(internal_angle) + V_I = internal_voltage * sin(internal_angle) Zmag = R_th^2 + X_th^2 #update current diff --git a/src/models/system.jl b/src/models/system.jl index 116244cda..7abfb82ba 100644 --- a/src/models/system.jl +++ b/src/models/system.jl @@ -25,15 +25,16 @@ function (m::SystemModel{ResidualModel, C})( out::AbstractArray{T}, du::AbstractArray{U}, u::AbstractArray{V}, - p, + p::AbstractArray{W}, t, ) where { C <: Cache, T <: ACCEPTED_REAL_TYPES, U <: ACCEPTED_REAL_TYPES, V <: ACCEPTED_REAL_TYPES, + W <: ACCEPTED_REAL_TYPES, } - system_residual!(out, du, u, m.inputs, m.cache, t) + system_residual!(out, du, u, p, m.inputs, m.cache, t) return end @@ -41,10 +42,16 @@ function system_residual!( out::AbstractVector{T}, dx::AbstractVector{U}, x::AbstractVector{V}, + p::AbstractVector{W}, inputs::SimulationInputs, cache::Cache, t::Float64, -) where {T <: ACCEPTED_REAL_TYPES, U <: ACCEPTED_REAL_TYPES, V <: ACCEPTED_REAL_TYPES} +) where { + T <: ACCEPTED_REAL_TYPES, + U <: ACCEPTED_REAL_TYPES, + V <: ACCEPTED_REAL_TYPES, + W <: ACCEPTED_REAL_TYPES, +} update_global_vars!(cache, inputs, x) M = get_mass_matrix(inputs) @@ -67,10 +74,12 @@ function system_residual!( device_inner_vars = @view inner_vars[get_inner_vars_index(dynamic_device)] device_states = @view x[ix_range] bus_ix = get_bus_ix(dynamic_device) - + p_ix = get_p_range(dynamic_device) + device_parameters = view(p, p_ix) device!( device_states, device_ode_output, + device_parameters, voltage_r[bus_ix], voltage_i[bus_ix], view(current_r, bus_ix), @@ -86,7 +95,10 @@ function system_residual!( for static_load in get_static_loads(inputs) bus_ix = get_bus_ix(static_load) + p_ix = get_p_range(static_load) + device_parameters = view(p, p_ix) device!( + device_parameters, voltage_r[bus_ix], voltage_i[bus_ix], view(current_r, bus_ix), @@ -100,7 +112,10 @@ function system_residual!( for static_device in get_static_injectors(inputs) bus_ix = get_bus_ix(static_device) + p_ix = get_p_range(static_device) + device_parameters = view(p, p_ix) device!( + device_parameters, voltage_r[bus_ix], voltage_i[bus_ix], view(current_r, bus_ix), @@ -118,6 +133,8 @@ function system_residual!( dyn_branch = get_branch(dynamic_branch) # DynamicBranch branch = PSY.get_branch(dyn_branch) # Line or Transformer2W ix_range = get_ix_range(dynamic_branch) + p_ix = get_p_range(dynamic_branch) + branch_parameters = view(p, p_ix) branch_output_ode = @view branches_ode[get_ode_ouput_range(dynamic_branch)] branch_states = @view x[ix_range] bus_ix_from = get_bus_ix_from(dynamic_branch) @@ -125,6 +142,7 @@ function system_residual!( branch!( branch_states, branch_output_ode, + branch_parameters, #Get Voltage data voltage_r[bus_ix_from], voltage_i[bus_ix_from], @@ -155,6 +173,9 @@ function MassMatrixModel(inputs, ::Vector{Float64}, ::Type{Ctype}) where {Ctype return SystemModel{MassMatrixModel}(inputs, Ctype(system_mass_matrix!, inputs)) end +""" +Instantiate a MassMatrixModel for ForwardDiff calculations +""" function MassMatrixModel( inputs::SimulationInputs, x0_init::Vector{T}, @@ -171,19 +192,25 @@ end function (m::SystemModel{MassMatrixModel, C})( du::AbstractArray{T}, u::AbstractArray{U}, - p, + p::AbstractArray{V}, t, -) where {C <: Cache, U <: ACCEPTED_REAL_TYPES, T <: ACCEPTED_REAL_TYPES} - system_mass_matrix!(du, u, m.inputs, m.cache, t) +) where { + C <: Cache, + U <: ACCEPTED_REAL_TYPES, + T <: ACCEPTED_REAL_TYPES, + V <: ACCEPTED_REAL_TYPES, +} + system_mass_matrix!(du, u, p, m.inputs, m.cache, t) end function system_mass_matrix!( - dx::Vector{T}, - x::Vector{V}, + dx::AbstractArray{T}, + x::AbstractArray{V}, + p::AbstractArray{U}, inputs::SimulationInputs, cache::Cache, t, -) where {T <: ACCEPTED_REAL_TYPES, V <: ACCEPTED_REAL_TYPES} +) where {T <: ACCEPTED_REAL_TYPES, U <: ACCEPTED_REAL_TYPES, V <: ACCEPTED_REAL_TYPES} update_global_vars!(cache, inputs, x) # Global quantities @@ -205,10 +232,12 @@ function system_mass_matrix!( device_inner_vars = @view inner_vars[get_inner_vars_index(dynamic_device)] device_states = @view x[ix_range] bus_ix = get_bus_ix(dynamic_device) - + p_ix = get_p_range(dynamic_device) + device_parameters = view(p, p_ix) device!( device_states, device_ode_output, + device_parameters, voltage_r[bus_ix], voltage_i[bus_ix], view(current_r, bus_ix), @@ -223,7 +252,10 @@ function system_mass_matrix!( for static_load in get_static_loads(inputs) bus_ix = get_bus_ix(static_load) + p_ix = get_p_range(static_load) + device_parameters = view(p, p_ix) device!( + device_parameters, voltage_r[bus_ix], voltage_i[bus_ix], view(current_r, bus_ix), @@ -237,7 +269,10 @@ function system_mass_matrix!( for static_device in get_static_injectors(inputs) bus_ix = get_bus_ix(static_device) + p_ix = get_p_range(static_device) + device_parameters = view(p, p_ix) device!( + device_parameters, voltage_r[bus_ix], voltage_i[bus_ix], view(current_r, bus_ix), @@ -255,6 +290,8 @@ function system_mass_matrix!( dyn_branch = get_branch(dynamic_branch) # DynamicBranch branch = PSY.get_branch(dyn_branch) # Line or Transformer2W ix_range = get_ix_range(dynamic_branch) + p_ix = get_p_range(dynamic_branch) + branch_parameters = view(p, p_ix) branch_output_ode = @view branches_ode[get_ode_ouput_range(dynamic_branch)] branch_states = @view x[ix_range] bus_ix_from = get_bus_ix_from(dynamic_branch) @@ -262,6 +299,7 @@ function system_mass_matrix!( branch!( branch_states, branch_output_ode, + branch_parameters, #Get Voltage data voltage_r[bus_ix_from], voltage_i[bus_ix_from], diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl new file mode 100644 index 000000000..f978c2d95 --- /dev/null +++ b/src/utils/parameters.jl @@ -0,0 +1,967 @@ + +get_params( + d::DynamicWrapper{T}, +) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} = + vcat(get_params(get_static_device(d)), get_params(get_dynamic_device(d))) +get_params(d::DynamicWrapper) = get_params(get_dynamic_device(d)) +get_params(d::StaticWrapper) = get_params(get_device(d)) +get_n_params(x::BranchWrapper) = get_n_params(get_branch(x)) +get_params(x::BranchWrapper) = get_params(PSY.get_branch(get_branch(x))) +get_n_params(x::PSY.DynamicBranch) = get_n_params(PSY.get_branch(x)) +get_n_params(x::PSY.Line) = 2 +get_params(x::PSY.Line) = [PSY.get_r(x), PSY.get_x(x)] + +function get_params(d::StaticLoadWrapper) + loads = get_loads(d) + bus = PSY.get_bus(d) + V_ref = PSY.get_magnitude(bus) + Θ_ref = PSY.get_angle(bus) + sys_base_power = get_system_base_power(d) + P_power = 0.0 + P_current = 0.0 + P_impedance = 0.0 + Q_power = 0.0 + Q_current = 0.0 + Q_impedance = 0.0 + for ld in loads + base_power_conversion = PSY.get_base_power(ld) / sys_base_power + if isa(ld, PSY.PowerLoad) + P_power += PSY.get_active_power(ld) * base_power_conversion + Q_power += PSY.get_reactive_power(ld) * base_power_conversion + elseif isa(ld, PSY.StandardLoad) + P_impedance += PSY.get_impedance_active_power(ld) * base_power_conversion + Q_impedance += PSY.get_impedance_reactive_power(ld) * base_power_conversion + P_current += PSY.get_current_active_power(ld) * base_power_conversion + Q_current += PSY.get_current_reactive_power(ld) * base_power_conversion + P_power += PSY.get_constant_active_power(ld) * base_power_conversion + Q_power += PSY.get_constant_reactive_power(ld) * base_power_conversion + end + end + + return [V_ref, Θ_ref, P_power, P_current, P_impedance, Q_power, Q_current, Q_impedance] +end + +# TODO - temporary for Dynamic components that have not yet been modified to use parameters. +# Allows the +get_n_params(x::PSY.DynamicComponent) = 0 +get_params(::PSY.DynamicComponent) = Float64[] +get_params_symbol(::PSY.DynamicComponent) = Symbol[] +get_n_params(x::PSY.ActivePowerControl) = 0 +get_params(::PSY.ActivePowerControl) = Float64[] +get_params_symbol(::PSY.ActivePowerControl) = Symbol[] +get_n_params(x::PSY.ReactivePowerControl) = 0 +get_params(::PSY.ReactivePowerControl) = Float64[] +get_params_symbol(::PSY.ReactivePowerControl) = Symbol[] + +get_n_params(g::PSY.DynamicInverter) = + 3 + get_n_params(PSY.get_converter(g)) + + get_n_params(PSY.get_outer_control(g)) + get_n_params(PSY.get_inner_control(g)) + + get_n_params(PSY.get_dc_source(g)) + get_n_params(PSY.get_freq_estimator(g)) + + get_n_params(PSY.get_filter(g)) + +#INVERTERS +function get_params(g::PSY.DynamicInverter) + refs = [ + PSY.get_V_ref(g), + PSY.get_ω_ref(g), + PSY.get_P_ref(g), + ] + vcat( + refs, + get_params(PSY.get_converter(g)), + get_params(PSY.get_outer_control(g)), + get_params(PSY.get_inner_control(g)), + get_params(PSY.get_dc_source(g)), + get_params(PSY.get_freq_estimator(g)), + get_params(PSY.get_filter(g)), + ) +end +get_params_symbol(g::PSY.DynamicInverter) = vcat( + [:V_ref, :ω_ref, :P_ref], + get_params_symbol(PSY.get_converter(g)), + get_params_symbol(PSY.get_outer_control(g)), + get_params_symbol(PSY.get_inner_control(g)), + get_params_symbol(PSY.get_dc_source(g)), + get_params_symbol(PSY.get_freq_estimator(g)), + get_params_symbol(PSY.get_filter(g)), +) + +#FILTERS +get_n_params(x::PSY.LCLFilter) = 5 +get_params(x::PSY.LCLFilter) = + [PSY.get_lf(x), PSY.get_rf(x), PSY.get_cf(x), PSY.get_lg(x), PSY.get_rg(x)] +get_params_symbol(::PSY.LCLFilter) = [:lf, :rf, :cf, :lg, :rg] + +get_n_params(x::PSY.RLFilter) = 2 +get_params(x::PSY.RLFilter) = [PSY.get_rf(x), PSY.get_lf(x)] +get_params_symbol(::PSY.RLFilter) = [:rf, :lf] +#OUTER CONTROL +get_n_params(x::PSY.OuterControl) = + get_n_params(PSY.get_active_power_control(x)) + + get_n_params(PSY.get_reactive_power_control(x)) +get_params(x::PSY.OuterControl) = vcat( + get_params(PSY.get_active_power_control(x)), + get_params(PSY.get_reactive_power_control(x)), +) +get_params_symbol(x::PSY.OuterControl) = vcat( + get_params_symbol(PSY.get_active_power_control(x)), + get_params_symbol(PSY.get_reactive_power_control(x)), +) +#ACTIVE POWER CONTROL +get_n_params(::PSY.VirtualInertia) = 3 +get_params(x::PSY.VirtualInertia) = [PSY.get_Ta(x), PSY.get_kd(x), PSY.get_kω(x)] +get_params_symbol(::PSY.VirtualInertia) = [:Ta, :kd, :kω] + +get_n_params(::PSY.ActiveRenewableControllerAB) = 17 +get_params(x::PSY.ActiveRenewableControllerAB) = + [PSY.get_K_pg(x), + PSY.get_K_ig(x), + PSY.get_T_p(x), + PSY.get_fdbd_pnts(x)[1], + PSY.get_fdbd_pnts(x)[2], + PSY.get_fe_lim(x)[1], + PSY.get_fe_lim(x)[2], + PSY.get_P_lim(x)[1], + PSY.get_P_lim(x)[2], + PSY.get_T_g(x), + PSY.get_D_dn(x), + PSY.get_D_up(x), + PSY.get_dP_lim(x)[1], + PSY.get_dP_lim(x)[2], + PSY.get_P_lim_inner(x)[1], + PSY.get_P_lim_inner(x)[2], + PSY.get_T_pord(x)] +get_params_symbol(::PSY.ActiveRenewableControllerAB) = [:K_pg, + :K_ig, + :T_p_ap, #modified to make unique + :fdbd1, + :fdbd2, + :fe_min, + :fe_max, + :P_min, + :P_max, + :T_g_ap, #modified to make unique + :D_dn, + :D_up, + :dP_min, + :dP_max, + :P_min_inner, + :P_max_inner, + :T_pord] + +get_n_params(::PSY.ReactiveRenewableControllerAB) = 22 +get_params(x::PSY.ReactiveRenewableControllerAB) = [PSY.get_T_fltr(x), + PSY.get_K_p(x), + PSY.get_K_i(x), + PSY.get_T_ft(x), + PSY.get_T_fv(x), + PSY.get_V_frz(x), + PSY.get_R_c(x), + PSY.get_X_c(x), + PSY.get_K_c(x), + PSY.get_e_lim(x)[1], + PSY.get_e_lim(x)[2], + PSY.get_dbd_pnts(x)[1], + PSY.get_dbd_pnts(x)[2], + PSY.get_Q_lim(x)[1], + PSY.get_Q_lim(x)[2], + PSY.get_T_p(x), + PSY.get_Q_lim_inner(x)[1], + PSY.get_Q_lim_inner(x)[2], + PSY.get_V_lim(x)[1], + PSY.get_V_lim(x)[2], + PSY.get_K_qp(x), + PSY.get_K_qi(x)] +get_params_symbol(::PSY.ReactiveRenewableControllerAB) = [:T_fltr, + :K_p, + :K_i, + :T_ft, + :T_fv, + :V_frz, + :R_c, + :X_c, + :K_c, + :e_min, + :e_max, + :dbd_pnts1, + :dbd_pnts2, + :Q_min, + :Q_max, + :T_p, + :Q_min_inner, + :Q_max_inner, + :V_min, + :V_max, + :K_qp, + :K_qi] + +#REACTIVE POWER CONTROL +get_n_params(::PSY.ReactivePowerDroop) = 2 +get_params(x::PSY.ReactivePowerDroop) = [PSY.get_kq(x), PSY.get_ωf(x)] +get_params_symbol(x::PSY.ReactivePowerDroop) = [:kq, :ωf] +#INNER CONTROL +get_n_params(::PSY.VoltageModeControl) = 10 +get_params(x::PSY.VoltageModeControl) = + [PSY.get_kpv(x), PSY.get_kiv(x), PSY.get_kffv(x), PSY.get_rv(x), PSY.get_lv(x), + PSY.get_kpc(x), PSY.get_kic(x), PSY.get_kffi(x), PSY.get_ωad(x), PSY.get_kad(x)] +get_params_symbol(x::PSY.VoltageModeControl) = + [:kpv, :kiv, :kffv, :rv, :lv, :kpc, :kic, :kffi, :ωad, :kad] + +get_n_params(::PSY.RECurrentControlB) = 13 +get_params(x::PSY.RECurrentControlB) = + [ + PSY.get_Vdip_lim(x)[1], + PSY.get_Vdip_lim(x)[2], + PSY.get_T_rv(x), + PSY.get_dbd_pnts(x)[1], + PSY.get_dbd_pnts(x)[2], + PSY.get_K_qv(x), + PSY.get_Iqinj_lim(x)[1], + PSY.get_Iqinj_lim(x)[2], + PSY.get_V_ref0(x), + PSY.get_K_vp(x), + PSY.get_K_vi(x), + PSY.get_T_iq(x), + PSY.get_I_max(x)] +get_params_symbol(x::PSY.RECurrentControlB) = + [:Vdip_min, + :Vdip_max, + :T_rv, + :dbd_pnts_1, + :dbd_pnts_2, + :K_qv, + :Iqinj_min, + :Iqinj_max, + :V_ref0, + :K_vp, + :K_vi, + :T_iq, + :I_max] + +#DC SOURCE +get_n_params(::PSY.FixedDCSource) = 1 +get_params(x::PSY.FixedDCSource) = [PSY.get_voltage(x)] +get_params_symbol(x::PSY.FixedDCSource) = [:voltage] +#FREQ ESTIMATOR +get_n_params(::PSY.KauraPLL) = 3 +get_params(x::PSY.KauraPLL) = [PSY.get_ω_lp(x), PSY.get_kp_pll(x), PSY.get_ki_pll(x)] +get_params_symbol(::PSY.KauraPLL) = [:ω_lp, :kp_pll, :ki_pll] +get_n_params(::PSY.FixedFrequency) = 1 +get_params(x::PSY.FixedFrequency) = [PSY.get_frequency(x)] +get_params_symbol(::PSY.FixedFrequency) = [:frequency] +#CONVERTER +get_n_params(::PSY.AverageConverter) = 0 +get_params(x::PSY.AverageConverter) = Float64[] +get_params_symbol(::PSY.AverageConverter) = Symbol[] +get_n_params(x::PSY.RenewableEnergyConverterTypeA) = 17 +get_params(x::PSY.RenewableEnergyConverterTypeA) = [PSY.get_T_g(x), + PSY.get_Rrpwr(x), + PSY.get_Brkpt(x), + PSY.get_Zerox(x), + PSY.get_Lvpl1(x), + PSY.get_Vo_lim(x), + PSY.get_Lv_pnts(x)[1], + PSY.get_Lv_pnts(x)[2], + PSY.get_Io_lim(x), + PSY.get_T_fltr(x), + PSY.get_K_hv(x), + PSY.get_Iqr_lims(x)[1], + PSY.get_Iqr_lims(x)[2], + PSY.get_Accel(x), + PSY.get_Q_ref(x), + PSY.get_R_source(x), + PSY.get_X_source(x)] +get_params_symbol(::PSY.RenewableEnergyConverterTypeA) = [:T_g, + :Rrpwr, + :Brkpt, + :Zerox, + :Lvpl1, + :Vo_lim, + :Lv_pnt0, + :Lv_pnt1, + :Io_lim, + :T_fltr_cnv, #modified to make unique + :K_hv, + :Iqr_min, + :Iqr_max, + :Accel, + :Q_ref_cnv, #modified to make unique + :R_source, + :X_source] + +#GENERATORS +get_n_params(g::PSY.DynamicGenerator) = + 3 + + get_n_params(PSY.get_machine(g)) + get_n_params(PSY.get_shaft(g)) + + get_n_params(PSY.get_avr(g)) + get_n_params(PSY.get_prime_mover(g)) + + get_n_params(PSY.get_pss(g)) +function get_params(g::PSY.DynamicGenerator) + refs = [ + PSY.get_V_ref(g), + PSY.get_ω_ref(g), + PSY.get_P_ref(g), + ] + vcat( + refs, + get_params(PSY.get_machine(g)), + get_params(PSY.get_shaft(g)), + get_params(PSY.get_avr(g)), + get_params(PSY.get_prime_mover(g)), + get_params(PSY.get_pss(g)), + ) +end +get_params_symbol(g::PSY.DynamicGenerator) = vcat( + [:V_ref, :ω_ref, :P_ref], + get_params_symbol(PSY.get_machine(g)), + get_params_symbol(PSY.get_shaft(g)), + get_params_symbol(PSY.get_avr(g)), + get_params_symbol(PSY.get_prime_mover(g)), + get_params_symbol(PSY.get_pss(g)), +) + +#MACHINES +get_n_params(::PSY.BaseMachine) = 3 +get_params(x::PSY.BaseMachine) = [PSY.get_R(x), PSY.get_Xd_p(x), PSY.get_eq_p(x)] +get_params_symbol(::PSY.BaseMachine) = [:R, :Xd_p, :eq_p] +get_n_params(::PSY.OneDOneQMachine) = 7 +get_params(x::PSY.OneDOneQMachine) = [ + PSY.get_R(x), + PSY.get_Xd(x), + PSY.get_Xq(x), + PSY.get_Xd_p(x), + PSY.get_Xq_p(x), + PSY.get_Td0_p(x), + PSY.get_Tq0_p(x), +] +get_params_symbol(x::PSY.OneDOneQMachine) = [:R, :Xd, :Xq, :Xd_p, :Xq_p, :Td0_p, :Tq0_p] +get_n_params(::PSY.MarconatoMachine) = 14 +get_params(x::PSY.MarconatoMachine) = + [PSY.get_R(x), PSY.get_Xd(x), PSY.get_Xq(x), PSY.get_Xd_p(x), PSY.get_Xq_p(x), + PSY.get_Xd_pp(x), PSY.get_Xq_pp(x), + PSY.get_Td0_p(x), PSY.get_Tq0_p(x), PSY.get_Td0_pp(x), PSY.get_Tq0_pp(x), + PSY.get_T_AA(x), PSY.get_γd(x), PSY.get_γq(x)] +get_params_symbol(x::PSY.MarconatoMachine) = [ + :R, + :Xd, + :Xq, + :Xd_p, + :Xq_p, + :Xd_pp, + :Xq_pp, + :Td0_p, + :Tq0_p, + :Td0_pp, + :Tq0_pp, + :T_AA, + :γd, + :γq, +] +get_n_params(::PSY.AndersonFouadMachine) = 11 +get_params(x::PSY.AndersonFouadMachine) = [ + PSY.get_R(x), + PSY.get_Xd(x), + PSY.get_Xq(x), + PSY.get_Xd_p(x), + PSY.get_Xq_p(x), + PSY.get_Xd_pp(x), + PSY.get_Xq_pp(x), + PSY.get_Td0_p(x), + PSY.get_Tq0_p(x), + PSY.get_Td0_pp(x), + PSY.get_Tq0_pp(x)] + +get_params_symbol(x::PSY.AndersonFouadMachine) = [:R, + :Xd, + :Xq, + :Xd_p, + :Xq_p, + :Xd_pp, + :Xq_pp, + :Td0_p, + :Tq0_p, + :Td0_pp, + :Tq0_pp] + +#NOTE: Saturation not considered as paramters +get_n_params( + x::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, +) = 16 +get_params( + x::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, +) = [ + PSY.get_R(x), + PSY.get_Td0_p(x), + PSY.get_Td0_pp(x), + PSY.get_Tq0_p(x), + PSY.get_Tq0_pp(x), + PSY.get_Xd(x), + PSY.get_Xq(x), + PSY.get_Xd_p(x), + PSY.get_Xq_p(x), + PSY.get_Xd_pp(x), + PSY.get_Xl(x), + PSY.get_γ_d1(x), + PSY.get_γ_q1(x), + PSY.get_γ_d2(x), + PSY.get_γ_q2(x), + PSY.get_γ_qd(x), +] +get_params_symbol( + ::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, +) = [ + :R, + :Td0_p, + :Td0_pp, + :Tq0_p, + :Tq0_pp, + :Xd, + :Xq, + :Xd_p, + :Xq_p, + :Xd_pp, + :Xl, + :γ_d1, + :γ_q1, + :γ_d2, + :γ_q2, + :γ_qd, +] +get_n_params( + ::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, +) = 12 +get_params( + x::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, +) = [ + PSY.get_R(x), + PSY.get_Td0_p(x), + PSY.get_Td0_pp(x), + PSY.get_Tq0_pp(x), + PSY.get_Xd(x), + PSY.get_Xq(x), + PSY.get_Xd_p(x), + PSY.get_Xd_pp(x), + PSY.get_Xl(x), + PSY.get_γ_d1(x), + PSY.get_γ_q1(x), + PSY.get_γ_d2(x), +] +get_params_symbol( + ::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, +) = [ + :R, + :Td0_p, + :Td0_pp, + :Tq0_pp, + :Xd, + :Xq, + :Xd_p, + :Xd_pp, + :Xl, + :γ_d1, + :γ_q1, + :γ_d2, +] + +#SHAFTS +get_n_params(::PSY.SingleMass) = 2 +get_params(x::PSY.SingleMass) = [PSY.get_H(x), PSY.get_D(x)] +get_params_symbol(::PSY.SingleMass) = [:H, :D] +get_n_params(::PSY.FiveMassShaft) = 18 +get_params(x::PSY.FiveMassShaft) = [ + PSY.get_H(x), + PSY.get_H_hp(x), + PSY.get_H_ip(x), + PSY.get_H_lp(x), + PSY.get_H_ex(x), + PSY.get_D(x), + PSY.get_D_hp(x), + PSY.get_D_ip(x), + PSY.get_D_lp(x), + PSY.get_D_ex(x), + PSY.get_D_12(x), + PSY.get_D_23(x), + PSY.get_D_34(x), + PSY.get_D_45(x), + PSY.get_K_hp(x), + PSY.get_K_ip(x), + PSY.get_K_lp(x), + PSY.get_K_ex(x), +] + +get_params_symbol(::PSY.FiveMassShaft) = [ + :H, + :H_hp, + :H_ip, + :H_lp, + :H_ex, + :D, + :D_hp, + :D_ip, + :D_lp, + :D_ex, + :D_12, + :D_23, + :D_34, + :D_45, + :K_hp, + :K_ip, + :K_lp, + :K_ex] + +#AVRS +get_n_params(::PSY.AVRFixed) = 0 +get_params(x::PSY.AVRFixed) = Float64[] +get_params_symbol(::PSY.AVRFixed) = Symbol[] +get_n_params(::PSY.AVRSimple) = 1 +get_params(x::PSY.AVRSimple) = [PSY.get_Kv(x)] +get_params_symbol(::PSY.AVRSimple) = [:Kv] +get_n_params(::PSY.AVRTypeI) = 9 +get_params(x::PSY.AVRTypeI) = [ + PSY.get_Ka(x), + PSY.get_Ke(x), + PSY.get_Kf(x), + PSY.get_Ta(x), + PSY.get_Te(x), + PSY.get_Tf(x), + PSY.get_Tr(x), + PSY.get_Ae(x), + PSY.get_Be(x), +] +get_params_symbol(::PSY.AVRTypeI) = [:Ka, :Ke, :Kf, :Ta, :Te, :Tf, :Tr, :Ae, :Be] +get_n_params(::PSY.SEXS) = 6 +get_params(x::PSY.SEXS) = [ + PSY.get_Ta_Tb(x), + PSY.get_Tb(x), + PSY.get_K(x), + PSY.get_Te(x), + PSY.get_V_lim(x)[1], + PSY.get_V_lim(x)[2], +] +get_params_symbol(::PSY.SEXS) = Symbol[:Ta_Tb, :Tb, :K, :Te, :V_min_avr, :V_max_avr] +get_n_params(::PSY.AVRTypeII) = 11 +get_params(x::PSY.AVRTypeII) = + [PSY.get_K0(x), + PSY.get_T1(x), + PSY.get_T2(x), + PSY.get_T3(x), + PSY.get_T4(x), + PSY.get_Te(x), + PSY.get_Tr(x), + PSY.get_Va_lim(x)[1], + PSY.get_Va_lim(x)[2], + PSY.get_Ae(x), + PSY.get_Be(x)] +get_params_symbol(::PSY.AVRTypeII) = + [:K0, + :T1, + :T2, + :T3, + :T4, + :Te, + :Tr, + :Va_min, + :Va_max, + :Ae, + :Be] +get_n_params(::PSY.ESAC1A) = 15 +get_params(x::PSY.ESAC1A) = [ + PSY.get_Tr(x), + PSY.get_Tb(x), + PSY.get_Tc(x), + PSY.get_Ka(x), + PSY.get_Ta(x), + PSY.get_Va_lim(x)[1], + PSY.get_Va_lim(x)[2], + PSY.get_Te(x), + PSY.get_Kf(x), + PSY.get_Tf(x), + PSY.get_Kc(x), + PSY.get_Kd(x), + PSY.get_Ke(x), + PSY.get_Vr_lim(x)[1], + PSY.get_Vr_lim(x)[2]] +get_params_symbol(::PSY.ESAC1A) = [:Tr, + :Tb, + :Tc, + :Ka, + :Ta, + :Va_min, + :Va_max, + :Te, + :Kf, + :Tf, + :Kc, + :Kd, + :Ke, + :Vr_min, + :Vr_max] +get_n_params(::PSY.EXST1) = 12 +get_params(x::PSY.EXST1) = [PSY.get_Tr(x), + PSY.get_Vi_lim(x)[1], + PSY.get_Vi_lim(x)[2], + PSY.get_Tc(x), + PSY.get_Tb(x), + PSY.get_Ka(x), + PSY.get_Ta(x), + PSY.get_Vr_lim(x)[1], + PSY.get_Vr_lim(x)[2], + PSY.get_Kc(x), + PSY.get_Kf(x), + PSY.get_Tf(x)] +get_params_symbol(::PSY.EXST1) = [ + :Tr_avr, #modified to make unique + :Vi_min, + :Vi_max, + :Tc, + :Tb, + :Ka, + :Ta, + :Vr_min, + :Vr_max, + :Kc, + :Kf, + :Tf_avr, #modified to make unique +] + +get_n_params(::PSY.EXAC1) = 13 +get_params(x::PSY.EXAC1) = [ + PSY.get_Tr(x), + PSY.get_Tb(x), + PSY.get_Tc(x), + PSY.get_Ka(x), + PSY.get_Ta(x), + PSY.get_Vr_lim(x)[1], + PSY.get_Vr_lim(x)[2], + PSY.get_Te(x), + PSY.get_Kf(x), + PSY.get_Tf(x), + PSY.get_Kc(x), + PSY.get_Kd(x), + PSY.get_Ke(x)] + +get_params_symbol(::PSY.EXAC1) = [ + :Tr_avr, #modified to make unique + :Tb, + :Tc, + :Ka, + :Ta, + :Vr_min, + :Vr_max, + :Te, + :Kf, + :Tf_avr, #modified to make unique + :Kc, + :Kd, + :Ke] + +#PRIME MOVERS +get_n_params(::PSY.TGFixed) = 1 +get_params(x::PSY.TGFixed) = [PSY.get_efficiency(x)] +get_params_symbol(::PSY.TGFixed) = [:efficiency] +get_n_params(::PSY.TGTypeII) = 3 +get_params(x::PSY.TGTypeII) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_T2(x)] +get_params_symbol(::PSY.TGTypeII) = [:R_tg, :T1, :T2] +get_n_params(::PSY.GasTG) = 9 +get_params(x::PSY.GasTG) = [ + PSY.get_R(x), + PSY.get_T1(x), + PSY.get_T2(x), + PSY.get_T3(x), + PSY.get_AT(x), + PSY.get_Kt(x), + PSY.get_V_lim(x)[1], + PSY.get_V_lim(x)[2], + PSY.get_D_turb(x), +] +get_params_symbol(::PSY.GasTG) = [:R_tg, :T1, :T2, :T3, :AT, :Kt, :V_min, :V_max, :D_turb] +get_n_params(::PSY.TGTypeI) = 8 +get_params(x::PSY.TGTypeI) = [PSY.get_R(x), + PSY.get_Ts(x), + PSY.get_Tc(x), + PSY.get_T3(x), + PSY.get_T4(x), + PSY.get_T5(x), + PSY.get_valve_position_limits(x)[1], + PSY.get_valve_position_limits(x)[2], +] + +get_params_symbol(::PSY.TGTypeI) = [:R_tg, + :Ts, + :Tc, + :T3_tg, #modified to make unique + :T4_tg, #modified to make unique + :T5_tg, #modified to make unique + :valve_position_min, + :valve_position_max, +] +get_n_params(::PSY.SteamTurbineGov1) = 7 +get_params(x::PSY.SteamTurbineGov1) = [PSY.get_R(x), + PSY.get_T1(x), + PSY.get_valve_position_limits(x)[1], + PSY.get_valve_position_limits(x)[2], + PSY.get_T2(x), + PSY.get_T3(x), + PSY.get_D_T(x)] +get_params_symbol(::PSY.SteamTurbineGov1) = [:R_tg, + :T1_tg, #modified to make unique + :valve_position_min, + :valve_position_max, + :T2_tg, #modified to make unique + :T3_tg, #modified to make unique + :D_T] +get_params_symbol(::PSY.TGTypeI) = [:R_tg, + :Ts, + :Tc, + :T3_tg, #modified to make unique + :T4_tg, #modified to make unique + :T5_tg, #modified to make unique + :valve_position_min, + :valve_position_max, +] +get_n_params(::PSY.HydroTurbineGov) = 12 +get_params(x::PSY.HydroTurbineGov) = [PSY.get_R(x), + PSY.get_r(x), + PSY.get_Tr(x), + PSY.get_Tf(x), + PSY.get_Tg(x), + PSY.get_VELM(x), + PSY.get_gate_position_limits(x)[1], + PSY.get_gate_position_limits(x)[2], + PSY.get_Tw(x), + PSY.get_At(x), + PSY.get_D_T(x), + PSY.get_q_nl(x)] +get_params_symbol(::PSY.HydroTurbineGov) = [ + :R_tg, #modified to make unique + :r, + :Tr, + :Tf, + :Tg, + :VELM, + :G_min, + :G_max, + :Tw, + :At, + :D_T, + :q_nl] + +#PSS +get_n_params(::PSY.PSSFixed) = 1 +get_params(x::PSY.PSSFixed) = [PSY.get_V_pss(x)] +get_params_symbol(::PSY.PSSFixed) = [:V_pss] + +get_n_params(::PSY.STAB1) = 7 +get_params(x::PSY.STAB1) = [PSY.get_KT(x), + PSY.get_T(x), + PSY.get_T1T3(x), + PSY.get_T3(x), + PSY.get_T2T4(x), + PSY.get_T4(x), + PSY.get_H_lim(x)] +get_params_symbol(::PSY.STAB1) = + [:KT, + :T, + :T1T3, + :T3, + :T2T4, + :T4, + :H_lim] + +#STATIC INJECTION +get_n_params(::PSY.StaticInjection) = 1 +get_params(x::PSY.StaticInjection) = [PSY.get_reactive_power(x)] +get_params_symbol(::PSY.StaticInjection) = [:Q_ref] + +get_n_params(::PSY.StandardLoad) = 1 +get_params(x::PSY.StandardLoad) = [PF.get_total_q(x)] +get_params_symbol(::PSY.StandardLoad) = [:Q_ref] +#SOURCE +get_n_params(::PSY.Source) = 4 +get_params(x::PSY.Source) = [ + PSY.get_R_th(x), + PSY.get_X_th(x), + PSY.get_internal_voltage(x), + PSY.get_internal_angle(x), +] +#Parameters not implemented for PVS - requires change in PSY Struct to have information required to construct and deconstruct parameter vector +get_n_params(x::PSY.PeriodicVariableSource) = 4 +get_params(x::PSY.PeriodicVariableSource) = Float64[0.0, 0.0, 0.0, 0.0] + +#DYNAMIC LOADS +get_n_params(::PSY.ActiveConstantPowerLoad) = 18 +get_params(x::PSY.ActiveConstantPowerLoad) = + [ + 0.0, + 0.0, + 0.0, + 0.0, + PSY.get_r_load(x), + PSY.get_c_dc(x), + PSY.get_rf(x), + PSY.get_lf(x), + PSY.get_cf(x), + PSY.get_rg(x), + PSY.get_lg(x), + PSY.get_kp_pll(x), + PSY.get_ki_pll(x), + PSY.get_kpv(x), + PSY.get_kiv(x), + PSY.get_kpc(x), + PSY.get_kic(x), + PSY.get_base_power(x)] +get_params_symbol(::PSY.ActiveConstantPowerLoad) = + [ + :Q_ref, + :V_ref, + :ω_ref, + :P_ref, + :r_load, + :c_dc, + :rf, + :lf, + :cf, + :rg, + :lg, + :kp_pll, + :ki_pll, + :kpv, + :kiv, + :kpc, + :kic, + :base_power] + +get_n_params(::PSY.SingleCageInductionMachine) = 18 +get_params(x::PSY.SingleCageInductionMachine) = [ + 0.0,#refs unused + 0.0,#refs unused + 0.0, #refs unused + 0.0, #refs unused + PSY.get_R_s(x), + PSY.get_R_r(x), + PSY.get_X_ls(x), + PSY.get_X_lr(x), + PSY.get_X_m(x), + PSY.get_H(x), + PSY.get_A(x), + PSY.get_B(x), + PSY.get_base_power(x), + PSY.get_C(x), + PSY.get_τ_ref(x), + PSY.get_B_shunt(x), + PSY.get_X_ad(x), + PSY.get_X_aq(x)] +get_params_symbol(::PSY.SingleCageInductionMachine) = [ + :Q_ref, + :V_ref, + :ω_ref, + :P_ref, + :R_s, + :R_r, + :X_ls, + :X_lr, + :X_m, + :H, + :A, + :B, + :base_power, + :C, + :τ_ref, + :B_shunt, + :X_ad, + :X_aq] +get_n_params(::PSY.SimplifiedSingleCageInductionMachine) = 19 +get_params(x::PSY.SimplifiedSingleCageInductionMachine) = [ + 0.0,#refs unused + 0.0,#refs unused + 0.0, #refs unused + 0.0, #refs unused + PSY.get_R_s(x), + PSY.get_R_r(x), + PSY.get_X_ls(x), + PSY.get_X_lr(x), + PSY.get_X_m(x), + PSY.get_H(x), + PSY.get_A(x), + PSY.get_B(x), + PSY.get_base_power(x), + PSY.get_C(x), + PSY.get_τ_ref(x), + PSY.get_B_shunt(x), + PSY.get_X_ss(x), + PSY.get_X_rr(x), + PSY.get_X_p(x)] +get_params_symbol(::PSY.SimplifiedSingleCageInductionMachine) = [ + :Q_ref, + :V_ref, + :ω_ref, + :P_ref, + :R_s, + :R_r, + :X_ls, + :X_lr, + :X_m, + :H, + :A, + :B, + :base_power, + :C, + :τ_ref, + :B_shunt, + :X_ss, + :X_rr, + :X_p] + +get_n_params(x::PSY.AggregateDistributedGenerationA) = 33 +get_params(x::PSY.AggregateDistributedGenerationA) = [PSY.get_Q_ref(x), + PSY.get_V_ref(x), + PSY.get_ω_ref(x), + PSY.get_P_ref(x), + PSY.get_T_rv(x), + PSY.get_Trf(x), + PSY.get_dbd_pnts(x)[1], + PSY.get_dbd_pnts(x)[2], + PSY.get_K_qv(x), + PSY.get_Tp(x), + PSY.get_T_iq(x), + PSY.get_D_dn(x), + PSY.get_D_up(x), + PSY.get_fdbd_pnts(x)[1], + PSY.get_fdbd_pnts(x)[2], + PSY.get_fe_lim(x)[1], + PSY.get_fe_lim(x)[2], + PSY.get_P_lim(x)[1], + PSY.get_P_lim(x)[2], + PSY.get_dP_lim(x)[1], + PSY.get_dP_lim(x)[2], + PSY.get_Tpord(x), + PSY.get_Kpg(x), + PSY.get_Kig(x), + PSY.get_I_max(x), + PSY.get_Tg(x), + PSY.get_rrpwr(x), + PSY.get_Tv(x), + PSY.get_Vpr(x), + PSY.get_Iq_lim(x)[1], + PSY.get_Iq_lim(x)[2], + PSY.get_base_power(x), + PSY.get_Pfa_ref(x)] + +get_n_params(x::PSY.CSVGN1) = 17 +get_params(x::PSY.CSVGN1) = [ + 0.0, + 0.0, + 0.0, + 0.0, + PSY.get_K(x), + PSY.get_T1(x), + PSY.get_T2(x), + PSY.get_T3(x), + PSY.get_T4(x), + PSY.get_T5(x), + PSY.get_Rmin(x), + PSY.get_Vmax(x), + PSY.get_Vmin(x), + PSY.get_CBase(x), + PSY.get_base_power(x), + PSY.get_R_th(x), + PSY.get_X_th(x)] diff --git a/test/test_base.jl b/test/test_base.jl index 0758da6ba..441e76b28 100644 --- a/test/test_base.jl +++ b/test/test_base.jl @@ -458,15 +458,15 @@ end inputs = PSID.SimulationInputs(ResidualModel, threebus_sys, ConstantFrequency()) integrator_for_test = MockIntegrator(inputs) - cref_affect_f = PSID.get_affect(inputs, threebus_sys, cref) ωref_affect_f = PSID.get_affect(inputs, threebus_sys, ωref) - cref_affect_f(integrator_for_test) ωref_affect_f(integrator_for_test) + p_ix1 = PSID.get_p_range(inputs.dynamic_injectors[1]) + p_ix2 = PSID.get_p_range(inputs.dynamic_injectors[2]) - @test PSID.get_P_ref(inputs.dynamic_injectors[1]) == 10.0 - @test PSID.get_ω_ref(inputs.dynamic_injectors[2]) == 0.9 + @test integrator_for_test.p[p_ix1][PSID.P_ref_ix] == 10.0 + @test integrator_for_test.p[p_ix2][PSID.ω_ref_ix] == 0.9 inputs = PSID.SimulationInputs(ResidualModel, threebus_sys, ConstantFrequency()) integrator_for_test = MockIntegrator(inputs) @@ -516,11 +516,13 @@ end lref_affect_f(integrator_for_test) zip_load1 = first(filter(x -> PSY.get_name(x) == "BUS 1", inputs.static_loads)) - @test PSID.get_P_impedance(zip_load1) == 10.0 + p_ix1 = PSID.get_p_range(zip_load1) + @test integrator_for_test.p[p_ix1][5] == 10.0 ltrip_affect_f(integrator_for_test) zip_load2 = first(filter(x -> PSY.get_name(x) == "BUS 2", inputs.static_loads)) - @test PSID.get_P_impedance(zip_load2) == 0.0 - @test PSID.get_Q_impedance(zip_load2) == 0.0 + p_ix2 = PSID.get_p_range(zip_load2) + @test integrator_for_test.p[p_ix2][5] == 0.0 + @test integrator_for_test.p[p_ix2][8] == 0.0 end @testset "Global Index" begin @@ -781,6 +783,7 @@ end 1, 1:6, 1:6, + 1:6, 1:9, 100.0, 60.0, diff --git a/test/test_case22_SteamTurbineGov1.jl b/test/test_case22_SteamTurbineGov1.jl index fbb953c9a..77feda043 100644 --- a/test/test_case22_SteamTurbineGov1.jl +++ b/test/test_case22_SteamTurbineGov1.jl @@ -12,7 +12,7 @@ raw_file = joinpath(TEST_FILES_DIR, "benchmarks/psse/TGOV1/ThreeBusMulti.raw") dyr_file = joinpath(TEST_FILES_DIR, "benchmarks/psse/TGOV1/ThreeBus_TGOV1.dyr") csv_file = joinpath(TEST_FILES_DIR, "benchmarks/psse/TGOV1/TEST_TGOV1.csv") -@testset "Test 21 SteamTurbineGov1 ResidualModel" begin +@testset "Test 22 SteamTurbineGov1 ResidualModel" begin path = mktempdir() try sys = System(raw_file, dyr_file) @@ -72,7 +72,7 @@ csv_file = joinpath(TEST_FILES_DIR, "benchmarks/psse/TGOV1/TEST_TGOV1.csv") end end -@testset "Test 21 SteamTurbineGov1 MassMatrixModel" begin +@testset "Test 22 SteamTurbineGov1 MassMatrixModel" begin path = (joinpath(pwd(), "test-psse-tgov1")) !isdir(path) && mkdir(path) try diff --git a/test/utils/mock_structs.jl b/test/utils/mock_structs.jl index 435fceb46..e26217d5f 100644 --- a/test/utils/mock_structs.jl +++ b/test/utils/mock_structs.jl @@ -8,6 +8,6 @@ function MockIntegrator(inputs) return MockIntegrator( zeros(PSID.get_variable_count(inputs)), zeros(PSID.get_variable_count(inputs)), - inputs, + PSID.get_parameters(inputs), ) end From 80bfa14d57ef76561fdaf12eda01e3c31a0f7ac4 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sat, 30 Mar 2024 17:53:42 -0400 Subject: [PATCH 02/76] make compatible with delay changes --- src/base/jacobian.jl | 5 +++-- src/base/simulation.jl | 3 ++- .../generator_components/init_tg.jl | 2 +- src/models/device.jl | 20 +++++++++++++++++-- src/models/generator_models/tg_models.jl | 3 ++- src/models/system.jl | 2 +- src/utils/parameters.jl | 9 --------- 7 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/base/jacobian.jl b/src/base/jacobian.jl index 23ebd75ec..24b71e804 100644 --- a/src/base/jacobian.jl +++ b/src/base/jacobian.jl @@ -169,7 +169,8 @@ end function JacobianFunctionWrapper( m!::SystemModel{MassMatrixModel, HasDelays}, - x0_guess::Vector{Float64}; + x0_guess::Vector{Float64}, + p::Vector{Float64}; # Improve the heuristic to do sparsity detection sparse_retrieve_loop::Int = 0, #max(3, length(x0_guess) ÷ 100), ) @@ -178,7 +179,7 @@ function JacobianFunctionWrapper( Jf = (Jv, x, h, t) -> begin @debug "Evaluating Jacobian Function" - m_ = (residual, x) -> m!(residual, x, h, nothing, t) + m_ = (residual, x) -> m!(residual, x, h, p, t) jconfig = ForwardDiff.JacobianConfig(m_, similar(x0), x0, ForwardDiff.Chunk(x0)) ForwardDiff.jacobian!(Jv, m_, zeros(n), x, jconfig) diff --git a/src/base/simulation.jl b/src/base/simulation.jl index 9defbebfa..20351d740 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -397,6 +397,7 @@ function _get_diffeq_problem( ) simulation_inputs = get_simulation_inputs(sim) h = get_history_function(sim) + p = get_parameters(simulation_inputs) sim.problem = SciMLBase.DDEProblem( SciMLBase.DDEFunction{true}( model; @@ -407,7 +408,7 @@ function _get_diffeq_problem( sim.x0_init, h, get_tspan(sim), - simulation_inputs; + p; constant_lags = filter!(x -> x != 0, unique(simulation_inputs.delays)), ) sim.status = BUILT diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index 010a78dce..d60599ff8 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -186,7 +186,7 @@ function initialize_tg!( #Get mechanical torque to SyncMach τm0 = inner_vars[τm_var] PSY.set_P_ref!(tg, τm0) - set_P_ref(dynamic_device, τm0) + device_parameters[P_ref_ix] = τm0 #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] diff --git a/src/models/device.jl b/src/models/device.jl index e5f8ba5d4..0ccb902f0 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -74,7 +74,15 @@ function device!( ) #Obtain ODEs for AVR - mdl_avr_ode!(device_states, output_ode, device_parameters, inner_vars, dynamic_device, h, t) + mdl_avr_ode!( + device_states, + output_ode, + device_parameters, + inner_vars, + dynamic_device, + h, + t, + ) #Obtain ODEs for Machine mdl_machine_ode!( @@ -250,7 +258,15 @@ function device!( ) #Obtain inner controller ODEs and modulation commands - mdl_inner_ode!(device_states, output_ode, device_parameters, inner_vars, dynamic_device, h, t) + mdl_inner_ode!( + device_states, + output_ode, + device_parameters, + inner_vars, + dynamic_device, + h, + t, + ) #Obtain converter relations mdl_converter_ode!( diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index 3e8aed3cd..241ea02b1 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -333,6 +333,7 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, + device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.DEGOV, P}}, @@ -341,7 +342,7 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - P_ref = get_P_ref(device) + P_ref = device_parameters[P_ref_ix] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.DEGOV) diff --git a/src/models/system.jl b/src/models/system.jl index b00e217dd..ba321722f 100644 --- a/src/models/system.jl +++ b/src/models/system.jl @@ -231,7 +231,7 @@ function (m::SystemModel{MassMatrixModel, NoDelays, C})( p, t, ) where {C <: Cache, U <: ACCEPTED_REAL_TYPES, T <: ACCEPTED_REAL_TYPES} - system_mass_matrix!(du, u, nothing, m.inputs, m.cache, t) + system_mass_matrix!(du, u, nothing, p, m.inputs, m.cache, t) end function (m::SystemModel{MassMatrixModel, HasDelays, C})( diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index f978c2d95..4c97a9edb 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -709,15 +709,6 @@ get_params_symbol(::PSY.SteamTurbineGov1) = [:R_tg, :T2_tg, #modified to make unique :T3_tg, #modified to make unique :D_T] -get_params_symbol(::PSY.TGTypeI) = [:R_tg, - :Ts, - :Tc, - :T3_tg, #modified to make unique - :T4_tg, #modified to make unique - :T5_tg, #modified to make unique - :valve_position_min, - :valve_position_max, -] get_n_params(::PSY.HydroTurbineGov) = 12 get_params(x::PSY.HydroTurbineGov) = [PSY.get_R(x), PSY.get_r(x), From 0f99dd42a6ac76a62360d3120a5a72ff843bdb3a Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 11 Apr 2024 15:45:36 -0400 Subject: [PATCH 03/76] simulation flow upgrades (re-use inputs and initial conditions) --- src/base/definitions.jl | 22 +- src/base/jacobian.jl | 4 +- src/base/nlsolve_wrapper.jl | 36 ++- src/base/perturbations.jl | 6 +- src/base/simulation.jl | 106 +++---- src/base/simulation_initialization.jl | 119 ++++++-- src/base/simulation_inputs.jl | 361 ++++++++++++++++------- src/base/small_signal.jl | 6 +- src/models/system.jl | 8 +- src/post_processing/post_proc_common.jl | 2 +- src/post_processing/post_proc_results.jl | 8 +- src/utils/print.jl | 4 +- test/test_base.jl | 155 +++++++--- test/test_case34_exp_load.jl | 4 +- test/test_case37_InductionMotor.jl | 8 +- test/test_case38_SimplifiedIndMotor.jl | 8 +- test/test_case56_powerload.jl | 4 +- test/utils/get_results.jl | 8 +- 18 files changed, 604 insertions(+), 265 deletions(-) diff --git a/src/base/definitions.jl b/src/base/definitions.jl index 869dd0edb..654b76001 100644 --- a/src/base/definitions.jl +++ b/src/base/definitions.jl @@ -220,7 +220,7 @@ const DIFFEQ_SOLVE_KWARGS = [ """ Defines the status of the simulation object """ -@enum BUILD_STATUS begin +@enum STATUS begin BUILT = 0 BUILD_IN_PROGRESS = 1 BUILD_INCOMPLETE = 2 @@ -231,6 +231,26 @@ Defines the status of the simulation object SIMULATION_FAILED = 7 end +""" +Defines the level of building simulation inputs +""" +@enum BUILD_INPUTS_LEVEL begin + BUILD_ONE = 1 + BUILD_TWO = 2 + BUILD_THREE = 3 + BUILD_NONE = 4 +end + +""" +Defines the level of initializing simulation +""" +@enum INITIALIZE_LEVEL begin + POWERFLOW_AND_DEVICES = 0 + DEVICES_ONLY = 1 + FLAT_START = 2 + INITIALIZED = 3 +end + const BUILD_TIMER = TimerOutputs.TimerOutput() const ACCEPTED_REAL_TYPES = Union{Float64, ForwardDiff.Dual} diff --git a/src/base/jacobian.jl b/src/base/jacobian.jl index 24b71e804..a6c6eaa21 100644 --- a/src/base/jacobian.jl +++ b/src/base/jacobian.jl @@ -245,9 +245,9 @@ function get_jacobian( ) where {T <: SimulationModel} # Deepcopy avoid system modifications simulation_system = deepcopy(system) - inputs = SimulationInputs(T, simulation_system, ReferenceBus()) + inputs = SimulationInputs(T, simulation_system, ReferenceBus(), nothing, Val(BUILD_ONE)) p = get_parameters(inputs) - x0_init = get_flat_start(inputs) + x0_init = _get_flat_start(inputs) set_operating_point!(x0_init, inputs, system) return get_jacobian(T, inputs, x0_init, p, sparse_retrieve_loop) end diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index 0a8f7ada8..ae5ef3f69 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -119,7 +119,7 @@ function _check_residual( if sum_residual > tolerance state_map = make_global_state_map(inputs) for (k, val) in state_map - inputs.global_state_map[k] = val + get_global_state_map(inputs)[k] = val end gen_name = "" state = "" @@ -136,6 +136,7 @@ function _check_residual( Generator = $gen_name, state = $state. Residual error is too large to continue") else + bus_count = get_bus_count(inputs) bus_no = ix > bus_count ? ix - bus_count : ix component = ix > bus_count ? "imag" : "real" error("The initial residual in the state located at $ix has a value of $val. @@ -150,15 +151,11 @@ function refine_initial_condition!( sim::Simulation, model::SystemModel, jacobian::JacobianFunctionWrapper, + ::Val{POWERFLOW_AND_DEVICES}, ) @assert sim.status != BUILD_INCOMPLETE - - if sim.status == SIMULATION_INITIALIZED - @info "Simulation already initialized. Refinement not executed" - return - end converged = false - initial_guess = get_initial_conditions(sim) + initial_guess = get_x0(sim) inputs = get_simulation_inputs(sim) parameters = get_parameters(inputs) bus_range = get_bus_range(inputs) @@ -205,6 +202,29 @@ function refine_initial_condition!( if maximum(pf_diff) > MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE @warn "The resulting voltages in the initial conditions differ from the power flow results" end - return end + +function refine_initial_condition!( + sim::Simulation, + model::SystemModel, + jacobian::JacobianFunctionWrapper, + ::Val{DEVICES_ONLY}, +) + refine_initial_condition!(sim, model, jacobian, Val(POWERFLOW_AND_DEVICES)) +end + +function refine_initial_condition!( + sim::Simulation, + model::SystemModel, + jacobian::JacobianFunctionWrapper, + ::Val{FLAT_START}, +) +end +function refine_initial_condition!( + sim::Simulation, + model::SystemModel, + jacobian::JacobianFunctionWrapper, + ::Val{INITIALIZED}, +) +end diff --git a/src/base/perturbations.jl b/src/base/perturbations.jl index 05abba6ff..cff5d4aca 100644 --- a/src/base/perturbations.jl +++ b/src/base/perturbations.jl @@ -328,8 +328,8 @@ function ybus_update!( return end -function ybus_update!(integrator_params, branch::PSY.ACBranch, mult::Float64) - ybus_update!(integrator_params.ybus_rectangular, branch, integrator_params.lookup, mult) +function ybus_update!(inputs, branch::PSY.ACBranch, mult::Float64) + ybus_update!(get_ybus(inputs), branch, get_lookup(inputs), mult) return end @@ -372,7 +372,7 @@ function get_affect(inputs::SimulationInputs, ::PSY.System, pert::NetworkSwitch) # TODO: This code can be more performant using SparseMatrix methods for (i, v) in enumerate(pert.ybus_rectangular) @debug "Changing Ybus network" - inputs.ybus_rectangular[i] = v + get_ybus(inputs)[i] = v end return end diff --git a/src/base/simulation.jl b/src/base/simulation.jl index 20351d740..b03815b03 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -1,15 +1,18 @@ mutable struct Simulation{T <: SimulationModel} - status::BUILD_STATUS + status::STATUS problem::Union{Nothing, SciMLBase.DEProblem} tspan::NTuple{2, Float64} sys::PSY.System perturbations::Vector{<:Perturbation} + initialize_level::INITIALIZE_LEVEL + x0::Vector{Float64} x0_init::Vector{Float64} - initialized::Bool tstops::Vector{Float64} callbacks::Vector simulation_folder::String + build_inputs_level::BUILD_INPUTS_LEVEL inputs::Union{Nothing, SimulationInputs} + inputs_init::Union{Nothing, SimulationInputs} results::Union{Nothing, SimulationResults} console_level::Base.CoreLogging.LogLevel file_level::Base.CoreLogging.LogLevel @@ -19,7 +22,8 @@ end get_system(sim::Simulation) = sim.sys get_simulation_inputs(sim::Simulation) = sim.inputs -get_initial_conditions(sim::Simulation) = sim.x0_init +get_x0(sim::Simulation) = sim.x0 +get_x0_init(sim::Simulation) = sim.x0_init get_tspan(sim::Simulation) = sim.tspan function Simulation( @@ -35,18 +39,30 @@ function Simulation( frequency_reference, ) where {T <: SimulationModel} PSY.set_units_base_system!(sys, "DEVICE_BASE") - + if initialize_simulation && !isempty(initial_conditions) + @warn "initial_conditions were provided with initialize_simulation. User's initial_conditions will be overwritten." + init_level = POWERFLOW_AND_DEVICES + elseif initialize_simulation + init_level = POWERFLOW_AND_DEVICES + elseif !initialize_simulation && isempty(initial_conditions) + init_level = FLAT_START + else + init_level = INITIALIZED + end return Simulation{T}( BUILD_INCOMPLETE, nothing, tspan, sys, perturbations, + init_level, + initial_conditions, initial_conditions, - !initialize_simulation, Vector{Float64}(), Vector{SciMLBase.AbstractDiscreteCallback}(), simulation_folder, + BUILD_ONE, + nothing, nothing, nothing, console_level, @@ -194,9 +210,7 @@ end function reset!(sim::Simulation{T}) where {T <: SimulationModel} @info "Rebuilding the simulation after reset" - sim.inputs = SimulationInputs(T, get_system(sim), sim.frequency_reference) sim.status = BUILD_INCOMPLETE - sim.initialized = false build!(sim) @info "Simulation reset to status $(sim.status)" return @@ -219,7 +233,14 @@ end function _build_inputs!(sim::Simulation{T}) where {T <: SimulationModel} simulation_system = get_system(sim) - sim.inputs = SimulationInputs(T, simulation_system, sim.frequency_reference) + sim.inputs = SimulationInputs( + T, + simulation_system, + sim.frequency_reference, + sim.inputs_init, + Val(sim.build_inputs_level), + ) + sim.inputs_init = deepcopy(sim.inputs) @debug "Simulation Inputs Created" return end @@ -232,53 +253,14 @@ function _get_flat_start(inputs::SimulationInputs) return initial_conditions end -function _initialize_state_space(sim::Simulation{T}) where {T <: SimulationModel} - simulation_inputs = get_simulation_inputs(sim) - x0_init = sim.x0_init - if isempty(x0_init) && sim.initialized - @warn "Initial Conditions set to flat start" - sim.x0_init = _get_flat_start(simulation_inputs) - elseif isempty(x0_init) && !sim.initialized - sim.x0_init = _get_flat_start(simulation_inputs) - elseif !isempty(x0_init) && sim.initialized - if length(sim.x0_init) != get_variable_count(simulation_inputs) - throw( - IS.ConflictingInputsError( - "The size of the provided initial state space does not match the model's state space.", - ), - ) - end - elseif !isempty(x0_init) && !sim.initialized - @warn "initial_conditions were provided with initialize_simulation. User's initial_conditions will be overwritten." - if length(sim.x0_init) != get_variable_count(simulation_inputs) - sim.x0_init = _get_flat_start(simulation_inputs) - end - else - @assert false - end - return -end - function _pre_initialize_simulation!(sim::Simulation) - _initialize_state_space(sim) - if sim.initialized != true - @info("Pre-Initializing Simulation States") - sim.initialized = precalculate_initial_conditions!(sim) - if !sim.initialized - error( - "The simulation failed to find an adequate initial guess for the initialization. Check the intialization routine.", - ) - end - else - @warn("Using existing initial conditions value for simulation initialization") - sim.status = SIMULATION_INITIALIZED - end + _initialize_state_space(sim, Val(sim.initialize_level)) return end function _get_jacobian(sim::Simulation{ResidualModel}) inputs = get_simulation_inputs(sim) - x0_init = get_initial_conditions(sim) + x0_init = get_x0(sim) parameters = get_parameters(inputs) return JacobianFunctionWrapper( ResidualModel(inputs, x0_init, JacobianCache), @@ -290,7 +272,7 @@ end function _get_jacobian(sim::Simulation{MassMatrixModel}) inputs = get_simulation_inputs(sim) - x0_init = get_initial_conditions(sim) + x0_init = get_x0(sim) parameters = get_parameters(inputs) return JacobianFunctionWrapper( MassMatrixModel(inputs, x0_init, JacobianCache), @@ -339,7 +321,8 @@ function _get_diffeq_problem( model::SystemModel{ResidualModel, NoDelays}, jacobian::JacobianFunctionWrapper, ) - x0 = get_initial_conditions(sim) + x0 = get_x0(sim) + sim.x0_init = deepcopy(x0) dx0 = zeros(length(x0)) simulation_inputs = get_simulation_inputs(sim) p = get_parameters(simulation_inputs) @@ -365,6 +348,8 @@ function _get_diffeq_problem( model::SystemModel{MassMatrixModel, NoDelays}, jacobian::JacobianFunctionWrapper, ) + x0 = get_x0(sim) + sim.x0_init = deepcopy(x0) simulation_inputs = get_simulation_inputs(sim) p = get_parameters(simulation_inputs) sim.problem = SciMLBase.ODEProblem( @@ -376,7 +361,7 @@ function _get_diffeq_problem( # Necessary to avoid unnecessary calculations in Rosenbrock methods tgrad = (dT, u, p, t) -> dT .= false, ), - sim.x0_init, + x0, get_tspan(sim), p; ) @@ -385,7 +370,7 @@ function _get_diffeq_problem( end function get_history_function(simulation_inputs::Simulation{MassMatrixModel}) - x0 = get_initial_conditions(simulation_inputs) + x0 = get_x0(simulation_inputs) h(p, t; idxs = nothing) = typeof(idxs) <: Number ? x0[idxs] : x0 return h end @@ -395,6 +380,8 @@ function _get_diffeq_problem( model::SystemModel{MassMatrixModel, HasDelays}, jacobian::JacobianFunctionWrapper, ) + x0 = get_x0(sim) + sim.x0_init = deepcopy(x0) simulation_inputs = get_simulation_inputs(sim) h = get_history_function(sim) p = get_parameters(simulation_inputs) @@ -405,11 +392,11 @@ function _get_diffeq_problem( jac = jacobian, jac_prototype = jacobian.Jv, ), - sim.x0_init, + x0, h, get_tspan(sim), p; - constant_lags = filter!(x -> x != 0, unique(simulation_inputs.delays)), + constant_lags = filter!(x -> x != 0, unique(get_delays(simulation_inputs))), ) sim.status = BUILT @@ -455,10 +442,15 @@ function _build!(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} jacobian = _get_jacobian(sim) end TimerOutputs.@timeit BUILD_TIMER "Make Model Function" begin - model = T(simulation_inputs, get_initial_conditions(sim), SimCache) + model = T(simulation_inputs, get_x0(sim), SimCache) end TimerOutputs.@timeit BUILD_TIMER "Initial Condition NLsolve refinement" begin - refine_initial_condition!(sim, model, jacobian) + refine_initial_condition!( + sim, + model, + jacobian, + Val(sim.initialize_level), + ) end TimerOutputs.@timeit BUILD_TIMER "Build Perturbations" begin _build_perturbations!(sim) diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index fbc4ff205..619544067 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -1,11 +1,3 @@ -function get_flat_start(inputs::SimulationInputs) - bus_count = get_bus_count(inputs) - var_count = get_variable_count(inputs) - initial_conditions = zeros(var_count) - initial_conditions[1:bus_count] .= 1.0 - return initial_conditions -end - function power_flow_solution!( initial_guess::Vector{Float64}, sys::PSY.System, @@ -149,35 +141,114 @@ end # Default implementation for both models. This implementation is to future proof if there is # a divergence between the required build methods -function _calculate_initial_guess!(sim::Simulation) +function _calculate_initial_guess!(sim::Simulation, ::Val{POWERFLOW_AND_DEVICES}) + @info("Pre-Initializing Simulation States") inputs = get_simulation_inputs(sim) @assert sim.status == BUILD_INCOMPLETE while sim.status == BUILD_INCOMPLETE @debug "Start state intialization routine" TimerOutputs.@timeit BUILD_TIMER "Power Flow solution" begin - sim.status = power_flow_solution!(sim.x0_init, get_system(sim), inputs) + sim.status = power_flow_solution!(sim.x0, get_system(sim), inputs) end TimerOutputs.@timeit BUILD_TIMER "Initialize Static Injectors" begin sim.status = initialize_static_injection!(inputs) end TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Injectors" begin - sim.status = initialize_dynamic_injection!(sim.x0_init, inputs, get_system(sim)) + sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) end if has_dyn_lines(inputs) TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Branches" begin - sim.status = initialize_dynamic_branches!(sim.x0_init, inputs) + sim.status = initialize_dynamic_branches!(sim.x0, inputs) end else @debug "No Dynamic Branches in the system" end - sim.status = check_valid_values(sim.x0_init, inputs) + sim.status = check_valid_values(sim.x0, inputs) end return end -function precalculate_initial_conditions!(sim::Simulation) - _calculate_initial_guess!(sim) - return sim.status != BUILD_FAILED +function _initialize_state_space( + sim::Simulation{T}, + ::Val{POWERFLOW_AND_DEVICES}, +) where {T <: SimulationModel} + inputs = get_simulation_inputs(sim) + sim.x0 = _get_flat_start(inputs) + @info("Pre-Initializing Simulation States") + @assert sim.status == BUILD_INCOMPLETE + while sim.status == BUILD_INCOMPLETE + @debug "Start state intialization routine" + TimerOutputs.@timeit BUILD_TIMER "Power Flow solution" begin + sim.status = power_flow_solution!(sim.x0, get_system(sim), inputs) + end + TimerOutputs.@timeit BUILD_TIMER "Initialize Static Injectors" begin + sim.status = initialize_static_injection!(inputs) + end + TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Injectors" begin + sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) + end + if has_dyn_lines(inputs) + TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Branches" begin + sim.status = initialize_dynamic_branches!(sim.x0, inputs) + end + else + @debug "No Dynamic Branches in the system" + end + sim.status = check_valid_values(sim.x0, inputs) + end +end + +function _initialize_state_space( + sim::Simulation{T}, + ::Val{DEVICES_ONLY}, +) where {T <: SimulationModel} + @info("Pre-Initializing Simulation States") + inputs = get_simulation_inputs(sim) + @assert sim.status == BUILD_INCOMPLETE + while sim.status == BUILD_INCOMPLETE + @debug "Start state intialization routine" + TimerOutputs.@timeit BUILD_TIMER "Initialize Static Injectors" begin + sim.status = initialize_static_injection!(inputs) + end + TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Injectors" begin + sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) + end + if has_dyn_lines(inputs) + TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Branches" begin + sim.status = initialize_dynamic_branches!(sim.x0, inputs) + end + else + @debug "No Dynamic Branches in the system" + end + sim.status = check_valid_values(sim.x0, inputs) + end +end + +function _initialize_state_space( + sim::Simulation{T}, + ::Val{FLAT_START}, +) where {T <: SimulationModel} + simulation_inputs = get_simulation_inputs(sim) + sim.x0 = _get_flat_start(simulation_inputs) +end + +function _initialize_state_space( + sim::Simulation{T}, + ::Val{INITIALIZED}, +) where {T <: SimulationModel} + simulation_inputs = get_simulation_inputs(sim) + @assert sim.status == BUILD_INCOMPLETE + if length(sim.x0) != get_variable_count(simulation_inputs) + throw( + IS.ConflictingInputsError( + "The size of the provided initial state space does not match the model's state space.", + ), + ) + end + @warn("Using existing initial conditions value for simulation initialization") + sim.x0 = deepcopy(sim.x0_init) + sim.status = SIMULATION_INITIALIZED + return end """ @@ -194,15 +265,15 @@ function read_initial_conditions(sim::Simulation) for bus in PSY.get_components(PSY.Bus, system) bus_n = PSY.get_number(bus) bus_ix = get_lookup(simulation_inputs)[bus_n] - V_R[bus_n] = get_initial_conditions(sim)[bus_ix] - V_I[bus_n] = get_initial_conditions(sim)[bus_ix + bus_size] + V_R[bus_n] = get_x0(sim)[bus_ix] + V_I[bus_n] = get_x0(sim)[bus_ix + bus_size] Vm[bus_n] = sqrt( - get_initial_conditions(sim)[bus_ix]^2 + - get_initial_conditions(sim)[bus_ix + bus_size]^2, + get_x0(sim)[bus_ix]^2 + + get_x0(sim)[bus_ix + bus_size]^2, ) θ[bus_n] = atan( - get_initial_conditions(sim)[bus_ix + bus_size], - get_initial_conditions(sim)[bus_ix], + get_x0(sim)[bus_ix + bus_size], + get_x0(sim)[bus_ix], ) end results = Dict{String, Any}("V_R" => V_R, "V_I" => V_I, "Vm" => Vm, "θ" => θ) @@ -212,7 +283,7 @@ function read_initial_conditions(sim::Simulation) global_index = get_global_index(device) x0_device = Dict{Symbol, Float64}() for s in states - x0_device[s] = get_initial_conditions(sim)[global_index[s]] + x0_device[s] = get_x0(sim)[global_index[s]] end results[name] = x0_device end @@ -224,7 +295,7 @@ function read_initial_conditions(sim::Simulation) global_index = get_global_index(br) x0_br = Dict{Symbol, Float64}() for s in states - x0_br[s] = get_initial_conditions(sim)[global_index[s]] + x0_br[s] = get_x0(sim)[global_index[s]] end printed_name = "Line " * name results[printed_name] = x0_br diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index add205509..43bc16f3f 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -1,4 +1,7 @@ -mutable struct SimulationInputs +""" +LevelOneInputs are constant unless a device or model is changed within the simulation. +""" +mutable struct LevelOneInputs dynamic_injectors::Vector{DynamicWrapper{<:PSY.DynamicInjection}} static_injectors::Vector static_loads::Vector @@ -8,132 +11,274 @@ mutable struct SimulationInputs variable_count::Int inner_vars_count::Int bus_count::Int + parameter_count::Int ode_range::UnitRange{Int} - ybus_rectangular::SparseArrays.SparseMatrixCSC{Float64, Int} dyn_lines::Bool - total_shunts::SparseArrays.SparseMatrixCSC{Float64, Int} lookup::Dict{Int, Int} - DAE_vector::Vector{Bool} - mass_matrix::LinearAlgebra.Diagonal{Float64} global_vars_update_pointers::Dict{Int, Int} global_state_map::MAPPING_DICT global_inner_var_map::Dict{String, Dict} +end + +""" +LevelTwoInputs are constant unless a network parameter is changed. +""" +mutable struct LevelTwoInputs + ybus_rectangular::SparseArrays.SparseMatrixCSC{Float64, Int} + total_shunts::SparseArrays.SparseMatrixCSC{Float64, Int} +end + +""" +LevelTwoInputs are constant unless any parameter is changed. +""" +mutable struct LevelThreeInputs + DAE_vector::Vector{Bool} + mass_matrix::LinearAlgebra.Diagonal{Float64} parameters::Vector{Float64} delays::Vector +end - function SimulationInputs( - sys::PSY.System, - ::T, - ) where {T <: Union{ConstantFrequency, ReferenceBus}} - n_buses = get_n_buses(sys) - Ybus, lookup = _get_ybus(sys) - state_count = 2 * n_buses + 1 - parameter_count = 1 - TimerOutputs.@timeit BUILD_TIMER "Wrap Branches" begin - wrapped_branches, state_count, parameter_count = - _wrap_dynamic_branches(sys, lookup, state_count, parameter_count) - has_dyn_lines = !isempty(wrapped_branches) - end - n_branch_states = state_count - (2 * n_buses + 1) - injection_start = state_count - - TimerOutputs.@timeit BUILD_TIMER "Wrap Dynamic Injectors" begin - wrapped_injectors, state_count, parameter_count = - _wrap_dynamic_injector_data(sys, lookup, state_count, parameter_count) - delays = get_system_delays(sys) - n_vars = state_count - 1 - end +mutable struct SimulationInputs + level_one_inputs::LevelOneInputs + level_two_inputs::LevelTwoInputs + level_three_inputs::LevelThreeInputs +end - TimerOutputs.@timeit BUILD_TIMER "Wrap Static Injectors" begin - wrapped_loads, parameter_count = _wrap_loads(sys, lookup, parameter_count) - wrapped_static_injectors, parameter_count = - _wrap_static_injectors(sys, lookup, parameter_count) - end +function LevelOneInputs(sys, ::Any, inputs_init, ::Any) + return inputs_init.level_one_inputs +end - TimerOutputs.@timeit BUILD_TIMER "Build initial parameters" begin - initial_parameters = zeros(parameter_count) - _update_initial_parameters!(initial_parameters, wrapped_branches) - _update_initial_parameters!(initial_parameters, wrapped_injectors) - _update_initial_parameters!(initial_parameters, wrapped_loads) - _update_initial_parameters!(initial_parameters, wrapped_static_injectors) - end +function LevelOneInputs( + sys, + ::Type{T}, + inputs_init, + ::Val{BUILD_ONE}, +) where {T <: Union{ConstantFrequency, ReferenceBus}} + n_buses = get_n_buses(sys) + _, lookup = _get_ybus(sys) + state_count = 2 * n_buses + 1 + parameter_count = 1 + TimerOutputs.@timeit BUILD_TIMER "Wrap Branches" begin + wrapped_branches, state_count, parameter_count = + _wrap_dynamic_branches(sys, lookup, state_count, parameter_count) + has_dyn_lines = !isempty(wrapped_branches) + end + n_branch_states = state_count - (2 * n_buses + 1) + injection_start = state_count - TimerOutputs.@timeit BUILD_TIMER "Calculate MM, DAE_vector, Total Shunts" begin - mass_matrix = _make_mass_matrix(wrapped_injectors, n_vars, n_buses) - DAE_vector = _make_DAE_vector(mass_matrix, n_vars, n_buses) - total_shunts = _make_total_shunts(wrapped_branches, n_buses) + TimerOutputs.@timeit BUILD_TIMER "Wrap Dynamic Injectors" begin + wrapped_injectors, state_count, parameter_count = + _wrap_dynamic_injector_data(sys, lookup, state_count, parameter_count) + n_vars = state_count - 1 + end + + TimerOutputs.@timeit BUILD_TIMER "Wrap Static Injectors" begin + wrapped_loads, parameter_count = _wrap_loads(sys, lookup, parameter_count) + wrapped_static_injectors, parameter_count = + _wrap_static_injectors(sys, lookup, parameter_count) + n_parameters = parameter_count - 1 + end + global_vars = + _make_global_variable_index(wrapped_injectors, wrapped_static_injectors, T) + + inner_vars_count = 0 + for i in length(wrapped_injectors):-1:1 + if length(wrapped_injectors[i].inner_vars_index) > 0 + inner_vars_count = wrapped_injectors[i].inner_vars_index[end] + break end + end - _adjust_states!( - DAE_vector, - mass_matrix, - total_shunts, - n_buses, - PSY.get_frequency(sys), - ) + return LevelOneInputs( + wrapped_injectors, + wrapped_static_injectors, + wrapped_loads, + wrapped_branches, + n_vars - 2 * n_buses - n_branch_states, + n_branch_states, + n_vars, + inner_vars_count, + n_buses, + n_parameters, + injection_start:n_vars, + has_dyn_lines, + lookup, + global_vars, + MAPPING_DICT(), + Dict{String, Dict}(), + ) +end - global_vars = - _make_global_variable_index(wrapped_injectors, wrapped_static_injectors, T) +function LevelTwoInputs(sys, level_one_inputs, inputs_init, ::Any) + return inputs_init.level_two_inputs +end - inner_vars_count = 0 - for i in length(wrapped_injectors):-1:1 - if length(wrapped_injectors[i].inner_vars_index) > 0 - inner_vars_count = wrapped_injectors[i].inner_vars_index[end] - break - end - end +function LevelTwoInputs(sys, level_one_inputs, inputs_init, ::Val{BUILD_TWO}) + LevelTwoInputs(sys, level_one_inputs, inputs_init, Val(BUILD_ONE)) +end - if !isempty(delays) - @info "System has delays. Use the correct solver for delay differential equations." - end +function LevelTwoInputs(sys, level_one_inputs, inputs_init, ::Val{BUILD_ONE}) + Ybus, _ = _get_ybus(sys) + wrapped_branches = get_dynamic_branches(level_one_inputs) + n_buses = get_bus_count(level_one_inputs) + total_shunts = _make_total_shunts(wrapped_branches, n_buses) + return LevelTwoInputs( + Ybus, + total_shunts, + ) +end +function LevelThreeInputs( + sys, + level_one_inputs::LevelOneInputs, + level_two_inputs::LevelTwoInputs, + inputs_init, + ::Val{BUILD_NONE}, +) + return inputs_init.level_three_inputs +end - new( - wrapped_injectors, - wrapped_static_injectors, - wrapped_loads, - wrapped_branches, - n_vars - 2 * n_buses - n_branch_states, - n_branch_states, - n_vars, - inner_vars_count, - n_buses, - injection_start:n_vars, - Ybus, - has_dyn_lines, - total_shunts, - lookup, - DAE_vector, - mass_matrix, - global_vars, - MAPPING_DICT(), - Dict{String, Dict}(), - initial_parameters, - delays, - ) +function LevelThreeInputs( + sys, + level_one_inputs::LevelOneInputs, + level_two_inputs::LevelTwoInputs, + inputs_init, + ::Val{BUILD_THREE}, +) + LevelThreeInputs(sys, level_one_inputs, level_two_inputs, inputs_init, Val(BUILD_ONE)) +end + +function LevelThreeInputs( + sys, + level_one_inputs::LevelOneInputs, + level_two_inputs::LevelTwoInputs, + inputs_init, + ::Val{BUILD_TWO}, +) + LevelThreeInputs(sys, level_one_inputs, level_two_inputs, inputs_init, Val(BUILD_ONE)) +end + +function LevelThreeInputs( + sys, + level_one_inputs::LevelOneInputs, + level_two_inputs::LevelTwoInputs, + inputs_init, + ::Val{BUILD_ONE}, +) + TimerOutputs.@timeit BUILD_TIMER "Build initial parameters" begin + parameter_count = get_parameter_count(level_one_inputs) + wrapped_branches = get_dynamic_branches(level_one_inputs) + wrapped_injectors = get_dynamic_injectors(level_one_inputs) + wrapped_loads = get_static_loads(level_one_inputs) + wrapped_static_injectors = get_static_injectors(level_one_inputs) + + initial_parameters = zeros(parameter_count) + _update_initial_parameters!(initial_parameters, wrapped_branches) + _update_initial_parameters!(initial_parameters, wrapped_injectors) + _update_initial_parameters!(initial_parameters, wrapped_loads) + _update_initial_parameters!(initial_parameters, wrapped_static_injectors) + end + n_vars = get_variable_count(level_one_inputs) + n_buses = get_bus_count(level_one_inputs) + wrapped_injectors = get_dynamic_injectors(level_one_inputs) + mass_matrix = _make_mass_matrix(wrapped_injectors, n_vars, n_buses) + DAE_vector = _make_DAE_vector(mass_matrix, n_vars, n_buses) + total_shunts = get_total_shunts(level_two_inputs) + _adjust_states!( + DAE_vector, + mass_matrix, + total_shunts, + n_buses, + PSY.get_frequency(sys), + ) + + delays = get_system_delays(sys) + if !isempty(delays) + @info "System has delays. Use the correct solver for delay differential equations." end + + return LevelThreeInputs( + DAE_vector, + mass_matrix, + initial_parameters, + delays, + ) end -get_dynamic_injectors(inputs::SimulationInputs) = inputs.dynamic_injectors -get_dynamic_branches(inputs::SimulationInputs) = inputs.dynamic_branches -get_static_injectors(inputs::SimulationInputs) = inputs.static_injectors -get_static_loads(inputs::SimulationInputs) = inputs.static_loads -get_ybus(inputs::SimulationInputs) = inputs.ybus_rectangular -get_total_shunts(inputs::SimulationInputs) = inputs.total_shunts -get_lookup(inputs::SimulationInputs) = inputs.lookup -get_DAE_vector(inputs::SimulationInputs) = inputs.DAE_vector -get_mass_matrix(inputs::SimulationInputs) = inputs.mass_matrix -has_dyn_lines(inputs::SimulationInputs) = inputs.dyn_lines +function SimulationInputs( + sys::PSY.System, + ::T, + simulation_inputs_init::Union{Nothing, SimulationInputs}, + build_level, +) where {T <: Union{ConstantFrequency, ReferenceBus}} + level_one_inputs = LevelOneInputs(sys, T, simulation_inputs_init, build_level) + level_two_inputs = + LevelTwoInputs(sys, level_one_inputs, simulation_inputs_init, build_level) + level_three_inputs = LevelThreeInputs( + sys, + level_one_inputs, + level_two_inputs, + simulation_inputs_init, + build_level, + ) + + return SimulationInputs( + level_one_inputs, + level_two_inputs, + level_three_inputs, + ) +end +#LEVEL ONE INPUTS +get_dynamic_injectors(inputs::SimulationInputs) = inputs.level_one_inputs.dynamic_injectors +get_dynamic_injectors(inputs::LevelOneInputs) = inputs.dynamic_injectors +get_dynamic_branches(inputs::SimulationInputs) = inputs.level_one_inputs.dynamic_branches +get_dynamic_branches(inputs::LevelOneInputs) = inputs.dynamic_branches +get_static_injectors(inputs::SimulationInputs) = inputs.level_one_inputs.static_injectors +get_static_injectors(inputs::LevelOneInputs) = inputs.static_injectors +get_static_loads(inputs::SimulationInputs) = inputs.level_one_inputs.static_loads +get_static_loads(inputs::LevelOneInputs) = inputs.static_loads +get_lookup(inputs::SimulationInputs) = inputs.level_one_inputs.lookup +get_lookup(inputs::LevelOneInputs) = inputs.lookup +has_dyn_lines(inputs::SimulationInputs) = inputs.level_one_inputs.dyn_lines +has_dyn_lines(inputs::LevelOneInputs) = inputs.dyn_lines get_global_vars_update_pointers(inputs::SimulationInputs) = + inputs.level_one_inputs.global_vars_update_pointers +get_global_vars_update_pointers(inputs::LevelOneInputs) = inputs.global_vars_update_pointers - -get_injection_n_states(inputs::SimulationInputs) = inputs.injection_n_states -get_branches_n_states(inputs::SimulationInputs) = inputs.branches_n_states -get_variable_count(inputs::SimulationInputs) = inputs.variable_count -get_inner_vars_count(inputs::SimulationInputs) = inputs.inner_vars_count -get_ode_ouput_range(inputs::SimulationInputs) = inputs.ode_range -get_bus_count(inputs::SimulationInputs) = inputs.bus_count -get_bus_range(inputs::SimulationInputs) = 1:(2 * inputs.bus_count) -get_parameters(inputs::SimulationInputs) = inputs.parameters +get_global_state_map(inputs::SimulationInputs) = inputs.level_one_inputs.global_state_map +get_global_state_map(inputs::LevelOneInputs) = inputs.global_state_map +get_injection_n_states(inputs::SimulationInputs) = + inputs.level_one_inputs.injection_n_states +get_injection_n_states(inputs::LevelOneInputs) = inputs.injection_n_states +get_branches_n_states(inputs::SimulationInputs) = inputs.level_one_inputs.branches_n_states +get_branches_n_states(inputs::LevelOneInputs) = inputs.branches_n_states +get_variable_count(inputs::SimulationInputs) = inputs.level_one_inputs.variable_count +get_variable_count(inputs::LevelOneInputs) = inputs.variable_count +get_inner_vars_count(inputs::SimulationInputs) = inputs.level_one_inputs.inner_vars_count +get_inner_vars_count(inputs::LevelOneInputs) = inputs.inner_vars_count +get_ode_ouput_range(inputs::SimulationInputs) = inputs.level_one_inputs.ode_range +get_ode_ouput_range(inputs::LevelOneInputs) = inputs.ode_range +get_bus_count(inputs::SimulationInputs) = inputs.level_one_inputs.bus_count +get_bus_count(inputs::LevelOneInputs) = inputs.bus_count +get_parameter_count(inputs::SimulationInputs) = inputs.level_one_inputs.parameter_count +get_parameter_count(inputs::LevelOneInputs) = inputs.parameter_count +get_bus_range(inputs::SimulationInputs) = 1:(2 * inputs.level_one_inputs.bus_count) +get_bus_range(inputs::LevelOneInputs) = 1:(2 * inputs.bus_count) + +#LEVEL TWO INPUTS +get_ybus(inputs::SimulationInputs) = inputs.level_two_inputs.ybus_rectangular +get_ybus(inputs::LevelTwoInputs) = inputs.ybus_rectangular +get_total_shunts(inputs::SimulationInputs) = inputs.level_two_inputs.total_shunts +get_total_shunts(inputs::LevelTwoInputs) = inputs.total_shunts + +#LEVEL THREE INPUTS +get_DAE_vector(inputs::SimulationInputs) = inputs.level_three_inputs.DAE_vector +get_DAE_vector(inputs::LevelThreeInputs) = inputs.DAE_vector +get_mass_matrix(inputs::SimulationInputs) = inputs.level_three_inputs.mass_matrix +get_mass_matrix(inputs::LevelThreeInputs) = inputs.mass_matrix +get_parameters(inputs::SimulationInputs) = inputs.level_three_inputs.parameters +get_parameters(inputs::LevelThreeInputs) = inputs.parameters +get_delays(inputs::SimulationInputs) = inputs.level_three_inputs.delays +get_delays(inputs::LevelThreeInputs) = inputs.delays # Utility function not to be used for performance sensitive operations function get_voltage_buses_ix(inputs::SimulationInputs) @@ -154,8 +299,10 @@ function SimulationInputs( ::Type{MassMatrixModel}, sys::PSY.System, frequency_reference::Union{ConstantFrequency, ReferenceBus}, + simulation_inputs_init, + build_level, ) - return SimulationInputs(sys, frequency_reference) + return SimulationInputs(sys, frequency_reference, simulation_inputs_init, build_level) end """ @@ -165,8 +312,10 @@ function SimulationInputs( ::Type{ResidualModel}, sys::PSY.System, frequency_reference::Union{ConstantFrequency, ReferenceBus}, + simulation_inputs_init, + build_level, ) - return SimulationInputs(sys, frequency_reference) + return SimulationInputs(sys, frequency_reference, simulation_inputs_init, build_level) end function _update_initial_parameters!(initial_parameters, wrapped_devices) diff --git a/src/base/small_signal.jl b/src/base/small_signal.jl index 01f50dd3c..80716ba53 100644 --- a/src/base/small_signal.jl +++ b/src/base/small_signal.jl @@ -170,10 +170,10 @@ Returns the Small Signal Output object that contains the eigenvalues and partici """ function small_signal_analysis(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} inputs = get_simulation_inputs(sim) - if !(isempty(inputs.delays)) + if !(isempty(get_delays(inputs))) return error("Small signal analysis not compatible with system model with delays") end - x_eval = get(kwargs, :operating_point, get_initial_conditions(sim)) + x_eval = get(kwargs, :operating_point, get_x0(sim)) p = get_parameters(inputs) return _small_signal_analysis(T, inputs, x_eval, p, sim.multimachine) end @@ -182,7 +182,7 @@ function small_signal_analysis(::Type{T}, system::PSY.System) where {T <: Simula simulation_system = deepcopy(system) inputs = SimulationInputs(T, simulation_system, ReferenceBus) p = get_parameters(inputs) - x0_init = get_flat_start(inputs) + x0_init = _get_flat_start(inputs) set_operating_point!(x0_init, inputs, system) return _small_signal_analysis(T, inputs, x0_init, p) end diff --git a/src/models/system.jl b/src/models/system.jl index ba321722f..3d88082ae 100644 --- a/src/models/system.jl +++ b/src/models/system.jl @@ -11,7 +11,7 @@ function ResidualModel( T, ForwardDiff.pickchunksize(length(x0_init)), } - if isempty(inputs.delays) + if isempty(get_delays(inputs)) return SystemModel{ResidualModel, NoDelays}( inputs, Ctype{U}(system_residual!, inputs), @@ -27,7 +27,7 @@ end Instantiate an ResidualModel for ODE inputs. """ function ResidualModel(inputs, ::Vector{Float64}, ::Type{Ctype}) where {Ctype <: SimCache} - if isempty(inputs.delays) + if isempty(get_delays(inputs)) return SystemModel{ResidualModel, NoDelays}(inputs, Ctype(system_residual!, inputs)) else error( @@ -186,7 +186,7 @@ end Instantiate a MassMatrixModel for ODE inputs. """ function MassMatrixModel(inputs, ::Vector{Float64}, ::Type{Ctype}) where {Ctype <: SimCache} - if isempty(inputs.delays) + if isempty(get_delays(inputs)) return SystemModel{MassMatrixModel, NoDelays}( inputs, Ctype(system_mass_matrix!, inputs), @@ -212,7 +212,7 @@ function MassMatrixModel( T, ForwardDiff.pickchunksize(length(x0_init)), } - if isempty(inputs.delays) + if isempty(get_delays(inputs)) return SystemModel{MassMatrixModel, NoDelays}( inputs, Ctype{U}(system_mass_matrix!, inputs), diff --git a/src/post_processing/post_proc_common.jl b/src/post_processing/post_proc_common.jl index 60aefaf49..04a3493b4 100644 --- a/src/post_processing/post_proc_common.jl +++ b/src/post_processing/post_proc_common.jl @@ -1,5 +1,5 @@ function make_global_state_map(inputs::SimulationInputs) - dic = inputs.global_state_map + dic = get_global_state_map(inputs) if !isempty(dic) return dic end diff --git a/src/post_processing/post_proc_results.jl b/src/post_processing/post_proc_results.jl index 534acdf42..bfcf41c94 100644 --- a/src/post_processing/post_proc_results.jl +++ b/src/post_processing/post_proc_results.jl @@ -22,8 +22,8 @@ function show_states_initial_value(sim::Simulation) println("====================") bus_n = PSY.get_number(bus) bus_ix = PSID.get_lookup(sim.inputs)[bus_n] - V_R = sim.x0_init[bus_ix] - V_I = sim.x0_init[bus_ix + bus_size] + V_R = sim.x0[bus_ix] + V_I = sim.x0[bus_ix + bus_size] Vm = sqrt(V_R^2 + V_I^2) θ = angle(V_R + V_I * 1im) print("Vm ", round(Vm; digits = 4), "\n") @@ -39,7 +39,7 @@ function show_states_initial_value(sim::Simulation) println("====================") global_index = global_state_map[name] for s in states - print(s, " ", round(sim.x0_init[global_index[s]]; digits = 4), "\n") + print(s, " ", round(sim.x0[global_index[s]]; digits = 4), "\n") end println("====================") end @@ -56,7 +56,7 @@ function show_states_initial_value(sim::Simulation) global_index = global_state_map[name] x0_br = Dict{Symbol, Float64}() for (i, s) in enumerate(states) - print(s, " ", round(sim.x0_init[global_index[s]]; digits = 5), "\n") + print(s, " ", round(sim.x0[global_index[s]]; digits = 5), "\n") end println("====================") end diff --git a/src/utils/print.jl b/src/utils/print.jl index f67b02a45..3bcd96d19 100644 --- a/src/utils/print.jl +++ b/src/utils/print.jl @@ -63,7 +63,7 @@ function show_simulation_table( ) where {T <: SimulationModel} header = ["Property", "Value"] val_multimachine = sim.multimachine ? "Yes" : "No" - val_initialized = sim.initialized ? "Yes" : "No" + val_initialized = (sim.initialize_level == INITIALIZED) ? "Yes" : "No" val_model = T == ResidualModel ? "Residual Model" : "Mass Matrix Model" table = [ "Status" sim.status @@ -71,7 +71,7 @@ function show_simulation_table( "Initialized?" val_initialized "Multimachine system?" val_multimachine "Time Span" string(sim.tspan) - "Number of States" string(length(sim.x0_init)) + "Number of States" string(length(sim.x0)) "Number of Perturbations" string(length(sim.perturbations)) ] PrettyTables.pretty_table( diff --git a/test/test_base.jl b/test/test_base.jl index fe595ca76..28bafe9ad 100644 --- a/test/test_base.jl +++ b/test/test_base.jl @@ -200,7 +200,7 @@ end sim_inputs = sim.inputs DAE_vector = PSID.get_DAE_vector(sim_inputs) @test all(DAE_vector) - @test all(LinearAlgebra.diag(sim_inputs.mass_matrix) .> 0) + @test all(LinearAlgebra.diag(PSID.PSID.get_mass_matrix(sim_inputs)) .> 0) total_shunts = PSID.get_total_shunts(sim_inputs) # Total shunts matrix follows same pattern as the rectangular Ybus for v in LinearAlgebra.diag(total_shunts[1:3, 4:end]) @@ -211,7 +211,7 @@ end @test v < 0 end - for entry in LinearAlgebra.diag(sim_inputs.mass_matrix) + for entry in LinearAlgebra.diag(PSID.get_mass_matrix(sim_inputs)) @test entry > 0 end voltage_buses_ix = PSID.get_voltage_buses_ix(sim_inputs) @@ -234,9 +234,9 @@ end @test sum(.!DAE_vector) == 6 for (ix, entry) in enumerate(DAE_vector) if !entry - @test LinearAlgebra.diag(sim_inputs.mass_matrix)[ix] == 0 + @test LinearAlgebra.diag(PSID.get_mass_matrix(sim_inputs))[ix] == 0 elseif entry - @test LinearAlgebra.diag(sim_inputs.mass_matrix)[ix] > 0 + @test LinearAlgebra.diag(PSID.get_mass_matrix(sim_inputs))[ix] > 0 else @test false end @@ -271,7 +271,7 @@ end initial_conditions = x0_test, console_level = Logging.Error, ) - @test LinearAlgebra.norm(sim.x0_init - x0_test) <= 1e-6 + @test LinearAlgebra.norm(sim.x0 - x0_test) <= 1e-6 #Initialize System normally sim_normal = Simulation( ResidualModel, @@ -282,7 +282,7 @@ end console_level = Logging.Error, ) #Save states without generator at bus 2 - x0 = sim_normal.x0_init + x0 = sim_normal.x0 x0_no_gen = vcat(x0[1:6], x0[13:end]) #Make Generator 2 unavailable and transform bus into PQ bus gen = PSY.get_component(ThermalStandard, sys, "generator-102-1") @@ -299,7 +299,7 @@ end initial_conditions = x0_no_gen, console_level = Logging.Error, ) - @test LinearAlgebra.norm(sim_trip_gen.x0_init - x0_no_gen) <= 1e-6 + @test LinearAlgebra.norm(sim_trip_gen.x0 - x0_no_gen) <= 1e-6 #Create Simulation without Gen 2 at steady state sim_normal_no_gen = Simulation( ResidualModel, @@ -309,7 +309,7 @@ end BranchTrip(1.0, Line, "BUS 1-BUS 2-i_1"); console_level = Logging.Error, ) - @test length(sim_normal_no_gen.x0_init) == 17 + @test length(sim_normal_no_gen.x0) == 17 #Ignore Initial Conditions without passing initialize_simulation = false sim_ignore_init = Simulation( ResidualModel, @@ -319,7 +319,7 @@ end initial_conditions = x0_no_gen, console_level = Logging.Error, ) - @test LinearAlgebra.norm(sim_ignore_init.x0_init - sim_normal_no_gen.x0_init) <= 1e-6 + @test LinearAlgebra.norm(sim_ignore_init.x0 - sim_normal_no_gen.x0) <= 1e-6 #Pass wrong vector size x0_wrong = zeros(20) # @test_logs (:error, "Build failed") match_mode = :any Simulation( @@ -342,7 +342,7 @@ end ) x0_flat = zeros(17) x0_flat[1:3] .= 1.0 - @test LinearAlgebra.norm(sim_flat.x0_init - x0_flat) <= 1e-6 + @test LinearAlgebra.norm(sim_flat.x0 - x0_flat) <= 1e-6 end @testset "Test Network Kirchoff Calculation" begin @@ -356,7 +356,13 @@ end V_i = voltages[3:end] ybus_ = PNM.Ybus(omib_sys).data I_balance_ybus = -1 * ybus_ * (V_r + V_i .* 1im) - inputs = PSID.SimulationInputs(ResidualModel, omib_sys, ConstantFrequency()) + inputs = PSID.SimulationInputs( + ResidualModel, + omib_sys, + ConstantFrequency(), + nothing, + Val(PSID.BUILD_ONE), + ) I_balance_sim = zeros(4) PSID.network_model(inputs, I_balance_sim, voltages) for i in 1:2 @@ -384,15 +390,20 @@ end end ybus_original = PNM.Ybus(threebus_sys) - - inputs = PSID.SimulationInputs(ResidualModel, threebus_sys, ConstantFrequency()) + inputs = PSID.SimulationInputs( + ResidualModel, + threebus_sys, + ConstantFrequency(), + nothing, + Val(PSID.BUILD_ONE), + ) for i in 1:3, j in 1:3 complex_ybus = ybus_original.data[i, j] - @test inputs.ybus_rectangular[i, j] == real(complex_ybus) - @test inputs.ybus_rectangular[i + 3, j + 3] == real(complex_ybus) - @test inputs.ybus_rectangular[i + 3, j] == -imag(complex_ybus) - @test inputs.ybus_rectangular[i, j + 3] == imag(complex_ybus) + @test PSID.get_ybus(inputs)[i, j] == real(complex_ybus) + @test PSID.get_ybus(inputs)[i + 3, j + 3] == real(complex_ybus) + @test PSID.get_ybus(inputs)[i + 3, j] == -imag(complex_ybus) + @test PSID.get_ybus(inputs)[i, j + 3] == imag(complex_ybus) end br = get_component(Line, threebus_sys, "BUS 1-BUS 3-i_1") @@ -405,14 +416,14 @@ end # floating point than the inversion of a single float for i in 1:3, j in 1:3 complex_ybus = ybus_line_trip.data[i, j] - @test isapprox(inputs.ybus_rectangular[i, j], real(complex_ybus), atol = 1e-10) + @test isapprox(PSID.get_ybus(inputs)[i, j], real(complex_ybus), atol = 1e-10) @test isapprox( - inputs.ybus_rectangular[i + 3, j + 3], + PSID.get_ybus(inputs)[i + 3, j + 3], real(complex_ybus), atol = 1e-10, ) - @test isapprox(inputs.ybus_rectangular[i + 3, j], -imag(complex_ybus), atol = 1e-10) - @test isapprox(inputs.ybus_rectangular[i, j + 3], imag(complex_ybus), atol = 1e-10) + @test isapprox(PSID.get_ybus(inputs)[i + 3, j], -imag(complex_ybus), atol = 1e-10) + @test isapprox(PSID.get_ybus(inputs)[i, j + 3], imag(complex_ybus), atol = 1e-10) end threebus_sys = System(three_bus_file_dir; runchecks = false) @@ -455,20 +466,30 @@ end cref = ControlReferenceChange(1.0, mach, :P_ref, 10.0) ωref = ControlReferenceChange(1.0, inv, :ω_ref, 0.9) - - inputs = PSID.SimulationInputs(ResidualModel, threebus_sys, ConstantFrequency()) + inputs = PSID.SimulationInputs( + ResidualModel, + threebus_sys, + ConstantFrequency(), + nothing, + Val(PSID.BUILD_ONE), + ) integrator_for_test = MockIntegrator(inputs) cref_affect_f = PSID.get_affect(inputs, threebus_sys, cref) ωref_affect_f = PSID.get_affect(inputs, threebus_sys, ωref) cref_affect_f(integrator_for_test) ωref_affect_f(integrator_for_test) - p_ix1 = PSID.get_p_range(inputs.dynamic_injectors[1]) - p_ix2 = PSID.get_p_range(inputs.dynamic_injectors[2]) + p_ix1 = PSID.get_p_range(PSID.get_dynamic_injectors(inputs)[1]) + p_ix2 = PSID.get_p_range(PSID.get_dynamic_injectors(inputs)[2]) @test integrator_for_test.p[p_ix1][PSID.P_ref_ix] == 10.0 @test integrator_for_test.p[p_ix2][PSID.ω_ref_ix] == 0.9 - - inputs = PSID.SimulationInputs(ResidualModel, threebus_sys, ConstantFrequency()) + inputs = PSID.SimulationInputs( + ResidualModel, + threebus_sys, + ConstantFrequency(), + nothing, + Val(PSID.BUILD_ONE), + ) integrator_for_test = MockIntegrator(inputs) mach_trip = PSID.GeneratorTrip(1.0, mach) @@ -480,8 +501,8 @@ end mtrip_affect_f(integrator_for_test) itrip_affect_f(integrator_for_test) - @test PSID.get_connection_status(inputs.dynamic_injectors[1]) == 0.0 - @test PSID.get_connection_status(inputs.dynamic_injectors[2]) == 0.0 + @test PSID.get_connection_status(PSID.get_dynamic_injectors(inputs)[1]) == 0.0 + @test PSID.get_connection_status(PSID.get_dynamic_injectors(inputs)[2]) == 0.0 end @testset "Test Load perturbations callback affects" begin @@ -507,19 +528,26 @@ end load_val = LoadChange(1.0, load_1, :P_ref, 10.0) load_trip = LoadTrip(1.0, load_2) - - inputs = PSID.SimulationInputs(ResidualModel, threebus_sys, ConstantFrequency()) + inputs = PSID.SimulationInputs( + ResidualModel, + threebus_sys, + ConstantFrequency(), + nothing, + Val(PSID.BUILD_ONE), + ) integrator_for_test = MockIntegrator(inputs) lref_affect_f = PSID.get_affect(inputs, threebus_sys, load_val) ltrip_affect_f = PSID.get_affect(inputs, threebus_sys, load_trip) lref_affect_f(integrator_for_test) - zip_load1 = first(filter(x -> PSY.get_name(x) == "BUS 1", inputs.static_loads)) + zip_load1 = + first(filter(x -> PSY.get_name(x) == "BUS 1", PSID.get_static_loads(inputs))) p_ix1 = PSID.get_p_range(zip_load1) @test integrator_for_test.p[p_ix1][5] == 10.0 ltrip_affect_f(integrator_for_test) - zip_load2 = first(filter(x -> PSY.get_name(x) == "BUS 2", inputs.static_loads)) + zip_load2 = + first(filter(x -> PSY.get_name(x) == "BUS 2", PSID.get_static_loads(inputs))) p_ix2 = PSID.get_p_range(zip_load2) @test integrator_for_test.p[p_ix2][5] == 0.0 @test integrator_for_test.p[p_ix2][8] == 0.0 @@ -616,7 +644,7 @@ end # (0.0, 20.0), # # Not initialized to speed up the test # initialize_simulation = false, - # frequency_reference = ConstantFrequency(), #time span + # frequency_reference = ConstantFrequency(), Val(PSID.BUILD_ONE)), #time span # ) end @@ -793,3 +821,62 @@ end 60.0, ) end + +@testset "Test Build and Initialize Levels" begin + path = mktempdir() + try + #Compute Y_bus after fault + fault_branch = deepcopy(collect(get_components(Branch, omib_sys))[1]) + fault_branch.r = 0.00 + fault_branch.x = 0.1 + Ybus_fault = + PNM.Ybus([fault_branch], collect(get_components(ACBus, omib_sys)))[:, :] + + Ybus_change = NetworkSwitch( + 1.0, #change at t = 1.0 + Ybus_fault, + ) #New YBus + # Define Simulation Problem + sim = Simulation!( + ResidualModel, + omib_sys, #system + path, + (0.0, 20.0), #time span + Ybus_change; + console_level = Logging.Error, + ) + @test execute!(sim, IDA(); dtmax = 0.005, saveat = 0.005) == + PSID.SIMULATION_FINALIZED + results_original = read_results(sim) + series_original = + get_state_series(results_original, ("generator-102-1", :δ); dt = 0.01) + for build_level in + [PSID.BUILD_ONE, PSID.BUILD_TWO, PSID.BUILD_THREE, PSID.BUILD_NONE] + sim.build_inputs_level = build_level + @test execute!(sim, IDA(); dtmax = 0.005, saveat = 0.005) == + PSID.SIMULATION_FINALIZED + results = read_results(sim) + series = get_state_series(results, ("generator-102-1", :δ); dt = 0.01) + @test series == series_original + end + sim.build_inputs_level = PSID.BUILD_ONE + for initialize_level in + [PSID.POWERFLOW_AND_DEVICES, PSID.INITIALIZED, PSID.DEVICES_ONLY] + sim.initialize_level = initialize_level + @test execute!(sim, IDA(); dtmax = 0.005, saveat = 0.005) == + PSID.SIMULATION_FINALIZED + results = read_results(sim) + series = get_state_series(results, ("generator-102-1", :δ); dt = 0.01) + #Will not be identical for PSID.DEVICES_ONLY, the other two should be + if initialize_level == PSID.DEVICES_ONLY + @test sum(abs.(series[2] .- series_original[2])) < + PSID.STRICT_NLSOLVE_F_TOLERANCE + else + @test series == series_original + end + end + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end diff --git a/test/test_case34_exp_load.jl b/test/test_case34_exp_load.jl index 7a263c501..8e1dc1b81 100644 --- a/test/test_case34_exp_load.jl +++ b/test/test_case34_exp_load.jl @@ -56,7 +56,7 @@ end ) # Test Initial Conditions - @test LinearAlgebra.norm(sim_power.x0_init - sim_exp.x0_init) < 1e-4 + @test LinearAlgebra.norm(sim_power.x0 - sim_exp.x0) < 1e-4 # Test Small Signal ss_power = small_signal_analysis(sim_power) @@ -114,7 +114,7 @@ end ) # Test Initial Conditions - @test LinearAlgebra.norm(sim_power.x0_init - sim_exp.x0_init) < 1e-4 + @test LinearAlgebra.norm(sim_power.x0 - sim_exp.x0) < 1e-4 # Test Small Signal ss_power = small_signal_analysis(sim_power) diff --git a/test/test_case37_InductionMotor.jl b/test/test_case37_InductionMotor.jl index 3c086de81..34078dfe1 100644 --- a/test/test_case37_InductionMotor.jl +++ b/test/test_case37_InductionMotor.jl @@ -34,8 +34,8 @@ dyr_file = joinpath(TEST_FILES_DIR, "data_tests/TVC_System_motor.dyr") sim = Simulation(ResidualModel, sys, path, time_span, perturbation_trip) # Test initial voltages between two systems are equivalent - voltages_P = sim_P.x0_init[1:8] - voltages_motor = sim.x0_init[1:8] + voltages_P = sim_P.x0[1:8] + voltages_motor = sim.x0[1:8] @test LinearAlgebra.norm(voltages_P - voltages_motor) < 1e-4 # Test Initial Condition @@ -87,8 +87,8 @@ end sim = Simulation(MassMatrixModel, sys, path, time_span, perturbation_trip) # Test initial voltages between two systems are equivalent - voltages_P = sim_P.x0_init[1:8] - voltages_motor = sim.x0_init[1:8] + voltages_P = sim_P.x0[1:8] + voltages_motor = sim.x0[1:8] @test LinearAlgebra.norm(voltages_P - voltages_motor) < 1e-4 # Test Initial Condition diff --git a/test/test_case38_SimplifiedIndMotor.jl b/test/test_case38_SimplifiedIndMotor.jl index 5066c8fe5..57b1d25c8 100644 --- a/test/test_case38_SimplifiedIndMotor.jl +++ b/test/test_case38_SimplifiedIndMotor.jl @@ -34,8 +34,8 @@ dyr_file = joinpath(TEST_FILES_DIR, "data_tests/TVC_System_motor.dyr") sim = Simulation(ResidualModel, sys, path, time_span, perturbation_trip) # Test initial voltages between two systems are equivalent - voltages_P = sim_P.x0_init[1:8] - voltages_motor = sim.x0_init[1:8] + voltages_P = sim_P.x0[1:8] + voltages_motor = sim.x0[1:8] @test LinearAlgebra.norm(voltages_P - voltages_motor) < 1e-4 # Test Initial Condition @@ -87,8 +87,8 @@ end sim = Simulation(MassMatrixModel, sys, path, time_span, perturbation_trip) # Test initial voltages between two systems are equivalent - voltages_P = sim_P.x0_init[1:8] - voltages_motor = sim.x0_init[1:8] + voltages_P = sim_P.x0[1:8] + voltages_motor = sim.x0[1:8] @test LinearAlgebra.norm(voltages_P - voltages_motor) < 1e-4 # Test Initial Condition diff --git a/test/test_case56_powerload.jl b/test/test_case56_powerload.jl index 3485f9592..ad9e2a145 100644 --- a/test/test_case56_powerload.jl +++ b/test/test_case56_powerload.jl @@ -57,7 +57,7 @@ end ) # Test Initial Conditions - @test LinearAlgebra.norm(sim_power.x0_init - sim_standard.x0_init) < 1e-4 + @test LinearAlgebra.norm(sim_power.x0 - sim_standard.x0) < 1e-4 # Test Small Signal ss_power = small_signal_analysis(sim_power) @@ -116,7 +116,7 @@ end ) # Test Initial Conditions - @test LinearAlgebra.norm(sim_power.x0_init - sim_standard.x0_init) < 1e-4 + @test LinearAlgebra.norm(sim_power.x0 - sim_standard.x0) < 1e-4 # Test Small Signal ss_power = small_signal_analysis(sim_power) diff --git a/test/utils/get_results.jl b/test/utils/get_results.jl index b49352e82..864ee1323 100644 --- a/test/utils/get_results.jl +++ b/test/utils/get_results.jl @@ -8,8 +8,8 @@ function get_init_values_for_comparison(sim::Simulation) for bus in PSY.get_components(PSY.Bus, system) bus_n = PSY.get_number(bus) bus_ix = PSID.get_lookup(sim.inputs)[bus_n] - V_R[bus_ix] = sim.x0_init[bus_ix] - V_I[bus_ix] = sim.x0_init[bus_ix + bus_size] + V_R[bus_ix] = sim.x0[bus_ix] + V_I[bus_ix] = sim.x0[bus_ix + bus_size] Vm[bus_ix] = sqrt(V_R[bus_ix]^2 + V_I[bus_ix]^2) θ[bus_ix] = angle(V_R[bus_ix] + V_I[bus_ix] * 1im) end @@ -21,7 +21,7 @@ function get_init_values_for_comparison(sim::Simulation) global_index = PSID.get_global_index(device) x0_device = Vector{Float64}(undef, length(states)) for (i, s) in enumerate(states) - x0_device[i] = sim.x0_init[global_index[s]] + x0_device[i] = sim.x0[global_index[s]] end results[name] = x0_device end @@ -31,7 +31,7 @@ function get_init_values_for_comparison(sim::Simulation) global_index = PSID.get_global_index(br) x0_br = Vector{Float64}(undef, length(states)) for (i, s) in enumerate(states) - x0_br[i] = sim.x0_init[global_index[s]] + x0_br[i] = sim.x0[global_index[s]] end printed_name = "Line " * name results[printed_name] = x0_br From c7986b47d27dba5216c6c6a823998f3ab8ef9eee Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 16 Apr 2024 13:39:43 -0400 Subject: [PATCH 04/76] fix (simplify) simulation inputs flow --- src/base/definitions.jl | 10 -- src/base/jacobian.jl | 2 +- src/base/simulation.jl | 16 ++- src/base/simulation_inputs.jl | 238 +++++++--------------------------- test/test_base.jl | 20 +-- 5 files changed, 63 insertions(+), 223 deletions(-) diff --git a/src/base/definitions.jl b/src/base/definitions.jl index 654b76001..e72214413 100644 --- a/src/base/definitions.jl +++ b/src/base/definitions.jl @@ -231,16 +231,6 @@ Defines the status of the simulation object SIMULATION_FAILED = 7 end -""" -Defines the level of building simulation inputs -""" -@enum BUILD_INPUTS_LEVEL begin - BUILD_ONE = 1 - BUILD_TWO = 2 - BUILD_THREE = 3 - BUILD_NONE = 4 -end - """ Defines the level of initializing simulation """ diff --git a/src/base/jacobian.jl b/src/base/jacobian.jl index a6c6eaa21..d0460ccf5 100644 --- a/src/base/jacobian.jl +++ b/src/base/jacobian.jl @@ -245,7 +245,7 @@ function get_jacobian( ) where {T <: SimulationModel} # Deepcopy avoid system modifications simulation_system = deepcopy(system) - inputs = SimulationInputs(T, simulation_system, ReferenceBus(), nothing, Val(BUILD_ONE)) + inputs = SimulationInputs(T, simulation_system, ReferenceBus()) p = get_parameters(inputs) x0_init = _get_flat_start(inputs) set_operating_point!(x0_init, inputs, system) diff --git a/src/base/simulation.jl b/src/base/simulation.jl index b03815b03..2cec48e34 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -10,7 +10,7 @@ mutable struct Simulation{T <: SimulationModel} tstops::Vector{Float64} callbacks::Vector simulation_folder::String - build_inputs_level::BUILD_INPUTS_LEVEL + build_inputs::Bool inputs::Union{Nothing, SimulationInputs} inputs_init::Union{Nothing, SimulationInputs} results::Union{Nothing, SimulationResults} @@ -61,7 +61,7 @@ function Simulation( Vector{Float64}(), Vector{SciMLBase.AbstractDiscreteCallback}(), simulation_folder, - BUILD_ONE, + true, nothing, nothing, nothing, @@ -231,20 +231,24 @@ function configure_logging(sim::Simulation, file_mode; kwargs...) ) end -function _build_inputs!(sim::Simulation{T}) where {T <: SimulationModel} +function _build_inputs!(sim::Simulation{T}, ::Val{true}) where {T <: SimulationModel} simulation_system = get_system(sim) sim.inputs = SimulationInputs( T, simulation_system, sim.frequency_reference, - sim.inputs_init, - Val(sim.build_inputs_level), ) sim.inputs_init = deepcopy(sim.inputs) @debug "Simulation Inputs Created" return end +function _build_inputs!(sim::Simulation{T}, ::Val{false}) where {T <: SimulationModel} + sim.inputs = deepcopy(sim.inputs_init) + @debug "Simulation Inputs Copied" + return +end + function _get_flat_start(inputs::SimulationInputs) bus_count = get_bus_count(inputs) var_count = get_variable_count(inputs) @@ -428,7 +432,7 @@ function _build!(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} end end TimerOutputs.@timeit BUILD_TIMER "Build Simulation Inputs" begin - _build_inputs!(sim) + _build_inputs!(sim, Val(sim.build_inputs)) sim.multimachine = get_global_vars_update_pointers(sim.inputs)[GLOBAL_VAR_SYS_FREQ_INDEX] != 0 diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index 43bc16f3f..2a15e0260 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -1,7 +1,4 @@ -""" -LevelOneInputs are constant unless a device or model is changed within the simulation. -""" -mutable struct LevelOneInputs +mutable struct SimulationInputs dynamic_injectors::Vector{DynamicWrapper{<:PSY.DynamicInjection}} static_injectors::Vector static_loads::Vector @@ -18,41 +15,17 @@ mutable struct LevelOneInputs global_vars_update_pointers::Dict{Int, Int} global_state_map::MAPPING_DICT global_inner_var_map::Dict{String, Dict} -end - -""" -LevelTwoInputs are constant unless a network parameter is changed. -""" -mutable struct LevelTwoInputs ybus_rectangular::SparseArrays.SparseMatrixCSC{Float64, Int} total_shunts::SparseArrays.SparseMatrixCSC{Float64, Int} -end - -""" -LevelTwoInputs are constant unless any parameter is changed. -""" -mutable struct LevelThreeInputs DAE_vector::Vector{Bool} mass_matrix::LinearAlgebra.Diagonal{Float64} parameters::Vector{Float64} delays::Vector end -mutable struct SimulationInputs - level_one_inputs::LevelOneInputs - level_two_inputs::LevelTwoInputs - level_three_inputs::LevelThreeInputs -end - -function LevelOneInputs(sys, ::Any, inputs_init, ::Any) - return inputs_init.level_one_inputs -end - -function LevelOneInputs( - sys, - ::Type{T}, - inputs_init, - ::Val{BUILD_ONE}, +function SimulationInputs( + sys::PSY.System, + ::T, ) where {T <: Union{ConstantFrequency, ReferenceBus}} n_buses = get_n_buses(sys) _, lookup = _get_ybus(sys) @@ -88,101 +61,18 @@ function LevelOneInputs( break end end - - return LevelOneInputs( - wrapped_injectors, - wrapped_static_injectors, - wrapped_loads, - wrapped_branches, - n_vars - 2 * n_buses - n_branch_states, - n_branch_states, - n_vars, - inner_vars_count, - n_buses, - n_parameters, - injection_start:n_vars, - has_dyn_lines, - lookup, - global_vars, - MAPPING_DICT(), - Dict{String, Dict}(), - ) -end - -function LevelTwoInputs(sys, level_one_inputs, inputs_init, ::Any) - return inputs_init.level_two_inputs -end - -function LevelTwoInputs(sys, level_one_inputs, inputs_init, ::Val{BUILD_TWO}) - LevelTwoInputs(sys, level_one_inputs, inputs_init, Val(BUILD_ONE)) -end - -function LevelTwoInputs(sys, level_one_inputs, inputs_init, ::Val{BUILD_ONE}) Ybus, _ = _get_ybus(sys) - wrapped_branches = get_dynamic_branches(level_one_inputs) - n_buses = get_bus_count(level_one_inputs) total_shunts = _make_total_shunts(wrapped_branches, n_buses) - return LevelTwoInputs( - Ybus, - total_shunts, - ) -end -function LevelThreeInputs( - sys, - level_one_inputs::LevelOneInputs, - level_two_inputs::LevelTwoInputs, - inputs_init, - ::Val{BUILD_NONE}, -) - return inputs_init.level_three_inputs -end - -function LevelThreeInputs( - sys, - level_one_inputs::LevelOneInputs, - level_two_inputs::LevelTwoInputs, - inputs_init, - ::Val{BUILD_THREE}, -) - LevelThreeInputs(sys, level_one_inputs, level_two_inputs, inputs_init, Val(BUILD_ONE)) -end - -function LevelThreeInputs( - sys, - level_one_inputs::LevelOneInputs, - level_two_inputs::LevelTwoInputs, - inputs_init, - ::Val{BUILD_TWO}, -) - LevelThreeInputs(sys, level_one_inputs, level_two_inputs, inputs_init, Val(BUILD_ONE)) -end - -function LevelThreeInputs( - sys, - level_one_inputs::LevelOneInputs, - level_two_inputs::LevelTwoInputs, - inputs_init, - ::Val{BUILD_ONE}, -) TimerOutputs.@timeit BUILD_TIMER "Build initial parameters" begin - parameter_count = get_parameter_count(level_one_inputs) - wrapped_branches = get_dynamic_branches(level_one_inputs) - wrapped_injectors = get_dynamic_injectors(level_one_inputs) - wrapped_loads = get_static_loads(level_one_inputs) - wrapped_static_injectors = get_static_injectors(level_one_inputs) - + parameter_count = n_parameters initial_parameters = zeros(parameter_count) _update_initial_parameters!(initial_parameters, wrapped_branches) _update_initial_parameters!(initial_parameters, wrapped_injectors) _update_initial_parameters!(initial_parameters, wrapped_loads) _update_initial_parameters!(initial_parameters, wrapped_static_injectors) end - n_vars = get_variable_count(level_one_inputs) - n_buses = get_bus_count(level_one_inputs) - wrapped_injectors = get_dynamic_injectors(level_one_inputs) mass_matrix = _make_mass_matrix(wrapped_injectors, n_vars, n_buses) DAE_vector = _make_DAE_vector(mass_matrix, n_vars, n_buses) - total_shunts = get_total_shunts(level_two_inputs) _adjust_states!( DAE_vector, mass_matrix, @@ -196,89 +86,59 @@ function LevelThreeInputs( @info "System has delays. Use the correct solver for delay differential equations." end - return LevelThreeInputs( + return SimulationInputs( + wrapped_injectors, + wrapped_static_injectors, + wrapped_loads, + wrapped_branches, + n_vars - 2 * n_buses - n_branch_states, + n_branch_states, + n_vars, + inner_vars_count, + n_buses, + n_parameters, + injection_start:n_vars, + has_dyn_lines, + lookup, + global_vars, + MAPPING_DICT(), + Dict{String, Dict}(), + Ybus, + total_shunts, DAE_vector, mass_matrix, initial_parameters, delays, ) end - -function SimulationInputs( - sys::PSY.System, - ::T, - simulation_inputs_init::Union{Nothing, SimulationInputs}, - build_level, -) where {T <: Union{ConstantFrequency, ReferenceBus}} - level_one_inputs = LevelOneInputs(sys, T, simulation_inputs_init, build_level) - level_two_inputs = - LevelTwoInputs(sys, level_one_inputs, simulation_inputs_init, build_level) - level_three_inputs = LevelThreeInputs( - sys, - level_one_inputs, - level_two_inputs, - simulation_inputs_init, - build_level, - ) - - return SimulationInputs( - level_one_inputs, - level_two_inputs, - level_three_inputs, - ) -end #LEVEL ONE INPUTS -get_dynamic_injectors(inputs::SimulationInputs) = inputs.level_one_inputs.dynamic_injectors -get_dynamic_injectors(inputs::LevelOneInputs) = inputs.dynamic_injectors -get_dynamic_branches(inputs::SimulationInputs) = inputs.level_one_inputs.dynamic_branches -get_dynamic_branches(inputs::LevelOneInputs) = inputs.dynamic_branches -get_static_injectors(inputs::SimulationInputs) = inputs.level_one_inputs.static_injectors -get_static_injectors(inputs::LevelOneInputs) = inputs.static_injectors -get_static_loads(inputs::SimulationInputs) = inputs.level_one_inputs.static_loads -get_static_loads(inputs::LevelOneInputs) = inputs.static_loads -get_lookup(inputs::SimulationInputs) = inputs.level_one_inputs.lookup -get_lookup(inputs::LevelOneInputs) = inputs.lookup -has_dyn_lines(inputs::SimulationInputs) = inputs.level_one_inputs.dyn_lines -has_dyn_lines(inputs::LevelOneInputs) = inputs.dyn_lines +get_dynamic_injectors(inputs::SimulationInputs) = inputs.dynamic_injectors +get_dynamic_branches(inputs::SimulationInputs) = inputs.dynamic_branches +get_static_injectors(inputs::SimulationInputs) = inputs.static_injectors +get_static_loads(inputs::SimulationInputs) = inputs.static_loads +get_lookup(inputs::SimulationInputs) = inputs.lookup +has_dyn_lines(inputs::SimulationInputs) = inputs.dyn_lines get_global_vars_update_pointers(inputs::SimulationInputs) = - inputs.level_one_inputs.global_vars_update_pointers -get_global_vars_update_pointers(inputs::LevelOneInputs) = inputs.global_vars_update_pointers -get_global_state_map(inputs::SimulationInputs) = inputs.level_one_inputs.global_state_map -get_global_state_map(inputs::LevelOneInputs) = inputs.global_state_map -get_injection_n_states(inputs::SimulationInputs) = - inputs.level_one_inputs.injection_n_states -get_injection_n_states(inputs::LevelOneInputs) = inputs.injection_n_states -get_branches_n_states(inputs::SimulationInputs) = inputs.level_one_inputs.branches_n_states -get_branches_n_states(inputs::LevelOneInputs) = inputs.branches_n_states -get_variable_count(inputs::SimulationInputs) = inputs.level_one_inputs.variable_count -get_variable_count(inputs::LevelOneInputs) = inputs.variable_count -get_inner_vars_count(inputs::SimulationInputs) = inputs.level_one_inputs.inner_vars_count -get_inner_vars_count(inputs::LevelOneInputs) = inputs.inner_vars_count -get_ode_ouput_range(inputs::SimulationInputs) = inputs.level_one_inputs.ode_range -get_ode_ouput_range(inputs::LevelOneInputs) = inputs.ode_range -get_bus_count(inputs::SimulationInputs) = inputs.level_one_inputs.bus_count -get_bus_count(inputs::LevelOneInputs) = inputs.bus_count -get_parameter_count(inputs::SimulationInputs) = inputs.level_one_inputs.parameter_count -get_parameter_count(inputs::LevelOneInputs) = inputs.parameter_count -get_bus_range(inputs::SimulationInputs) = 1:(2 * inputs.level_one_inputs.bus_count) -get_bus_range(inputs::LevelOneInputs) = 1:(2 * inputs.bus_count) +get_global_state_map(inputs::SimulationInputs) = inputs.global_state_map +get_injection_n_states(inputs::SimulationInputs) = inputs.injection_n_states +get_branches_n_states(inputs::SimulationInputs) = inputs.branches_n_states +get_variable_count(inputs::SimulationInputs) = inputs.variable_count +get_inner_vars_count(inputs::SimulationInputs) = inputs.inner_vars_count +get_ode_ouput_range(inputs::SimulationInputs) = inputs.ode_range +get_bus_count(inputs::SimulationInputs) = inputs.bus_count +get_parameter_count(inputs::SimulationInputs) = inputs.parameter_count +get_bus_range(inputs::SimulationInputs) = 1:(2 * inputs.bus_count) #LEVEL TWO INPUTS -get_ybus(inputs::SimulationInputs) = inputs.level_two_inputs.ybus_rectangular -get_ybus(inputs::LevelTwoInputs) = inputs.ybus_rectangular -get_total_shunts(inputs::SimulationInputs) = inputs.level_two_inputs.total_shunts -get_total_shunts(inputs::LevelTwoInputs) = inputs.total_shunts +get_ybus(inputs::SimulationInputs) = inputs.ybus_rectangular +get_total_shunts(inputs::SimulationInputs) = inputs.total_shunts #LEVEL THREE INPUTS -get_DAE_vector(inputs::SimulationInputs) = inputs.level_three_inputs.DAE_vector -get_DAE_vector(inputs::LevelThreeInputs) = inputs.DAE_vector -get_mass_matrix(inputs::SimulationInputs) = inputs.level_three_inputs.mass_matrix -get_mass_matrix(inputs::LevelThreeInputs) = inputs.mass_matrix -get_parameters(inputs::SimulationInputs) = inputs.level_three_inputs.parameters -get_parameters(inputs::LevelThreeInputs) = inputs.parameters -get_delays(inputs::SimulationInputs) = inputs.level_three_inputs.delays -get_delays(inputs::LevelThreeInputs) = inputs.delays +get_DAE_vector(inputs::SimulationInputs) = inputs.DAE_vector +get_mass_matrix(inputs::SimulationInputs) = inputs.mass_matrix +get_parameters(inputs::SimulationInputs) = inputs.parameters +get_delays(inputs::SimulationInputs) = inputs.delays # Utility function not to be used for performance sensitive operations function get_voltage_buses_ix(inputs::SimulationInputs) @@ -299,10 +159,8 @@ function SimulationInputs( ::Type{MassMatrixModel}, sys::PSY.System, frequency_reference::Union{ConstantFrequency, ReferenceBus}, - simulation_inputs_init, - build_level, ) - return SimulationInputs(sys, frequency_reference, simulation_inputs_init, build_level) + return SimulationInputs(sys, frequency_reference) end """ @@ -312,10 +170,8 @@ function SimulationInputs( ::Type{ResidualModel}, sys::PSY.System, frequency_reference::Union{ConstantFrequency, ReferenceBus}, - simulation_inputs_init, - build_level, ) - return SimulationInputs(sys, frequency_reference, simulation_inputs_init, build_level) + return SimulationInputs(sys, frequency_reference) end function _update_initial_parameters!(initial_parameters, wrapped_devices) diff --git a/test/test_base.jl b/test/test_base.jl index 28bafe9ad..923c3b1c3 100644 --- a/test/test_base.jl +++ b/test/test_base.jl @@ -360,8 +360,6 @@ end ResidualModel, omib_sys, ConstantFrequency(), - nothing, - Val(PSID.BUILD_ONE), ) I_balance_sim = zeros(4) PSID.network_model(inputs, I_balance_sim, voltages) @@ -394,8 +392,6 @@ end ResidualModel, threebus_sys, ConstantFrequency(), - nothing, - Val(PSID.BUILD_ONE), ) for i in 1:3, j in 1:3 @@ -470,8 +466,6 @@ end ResidualModel, threebus_sys, ConstantFrequency(), - nothing, - Val(PSID.BUILD_ONE), ) integrator_for_test = MockIntegrator(inputs) cref_affect_f = PSID.get_affect(inputs, threebus_sys, cref) @@ -487,8 +481,6 @@ end ResidualModel, threebus_sys, ConstantFrequency(), - nothing, - Val(PSID.BUILD_ONE), ) integrator_for_test = MockIntegrator(inputs) @@ -532,8 +524,6 @@ end ResidualModel, threebus_sys, ConstantFrequency(), - nothing, - Val(PSID.BUILD_ONE), ) integrator_for_test = MockIntegrator(inputs) @@ -644,7 +634,7 @@ end # (0.0, 20.0), # # Not initialized to speed up the test # initialize_simulation = false, - # frequency_reference = ConstantFrequency(), Val(PSID.BUILD_ONE)), #time span + # frequency_reference = ConstantFrequency()), #time span # ) end @@ -850,16 +840,16 @@ end results_original = read_results(sim) series_original = get_state_series(results_original, ("generator-102-1", :δ); dt = 0.01) - for build_level in - [PSID.BUILD_ONE, PSID.BUILD_TWO, PSID.BUILD_THREE, PSID.BUILD_NONE] - sim.build_inputs_level = build_level + for build_inputs in + [true, false] + sim.build_inputs = build_inputs @test execute!(sim, IDA(); dtmax = 0.005, saveat = 0.005) == PSID.SIMULATION_FINALIZED results = read_results(sim) series = get_state_series(results, ("generator-102-1", :δ); dt = 0.01) @test series == series_original end - sim.build_inputs_level = PSID.BUILD_ONE + sim.build_inputs = true for initialize_level in [PSID.POWERFLOW_AND_DEVICES, PSID.INITIALIZED, PSID.DEVICES_ONLY] sim.initialize_level = initialize_level From 291f4c7e8b7ea1df19edaea794dd45f5ec923328 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 17 Apr 2024 11:01:36 -0400 Subject: [PATCH 05/76] append type to parameters of DynamicComponents --- src/utils/parameters.jl | 524 +++++++++++++++++++++------------------- 1 file changed, 281 insertions(+), 243 deletions(-) diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index 4c97a9edb..6497aa57d 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -3,6 +3,10 @@ get_params( d::DynamicWrapper{T}, ) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} = vcat(get_params(get_static_device(d)), get_params(get_dynamic_device(d))) +get_params_symbol( + d::DynamicWrapper{T}, +) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} = + vcat(:Q_ref, get_params_symbol(get_dynamic_device(d))) get_params(d::DynamicWrapper) = get_params(get_dynamic_device(d)) get_params(d::StaticWrapper) = get_params(get_device(d)) get_n_params(x::BranchWrapper) = get_n_params(get_branch(x)) @@ -90,11 +94,12 @@ get_params_symbol(g::PSY.DynamicInverter) = vcat( get_n_params(x::PSY.LCLFilter) = 5 get_params(x::PSY.LCLFilter) = [PSY.get_lf(x), PSY.get_rf(x), PSY.get_cf(x), PSY.get_lg(x), PSY.get_rg(x)] -get_params_symbol(::PSY.LCLFilter) = [:lf, :rf, :cf, :lg, :rg] +get_params_symbol(::PSY.LCLFilter) = + [:lf_Filter, :rf_Filter, :cf_Filter, :lg_Filter, :rg_Filter] get_n_params(x::PSY.RLFilter) = 2 get_params(x::PSY.RLFilter) = [PSY.get_rf(x), PSY.get_lf(x)] -get_params_symbol(::PSY.RLFilter) = [:rf, :lf] +get_params_symbol(::PSY.RLFilter) = [:rf_Filter, :lf_Filter] #OUTER CONTROL get_n_params(x::PSY.OuterControl) = get_n_params(PSY.get_active_power_control(x)) + @@ -110,7 +115,8 @@ get_params_symbol(x::PSY.OuterControl) = vcat( #ACTIVE POWER CONTROL get_n_params(::PSY.VirtualInertia) = 3 get_params(x::PSY.VirtualInertia) = [PSY.get_Ta(x), PSY.get_kd(x), PSY.get_kω(x)] -get_params_symbol(::PSY.VirtualInertia) = [:Ta, :kd, :kω] +get_params_symbol(::PSY.VirtualInertia) = + [:Ta_OuterControl, :kd_OuterControl, :kω_OuterControl] get_n_params(::PSY.ActiveRenewableControllerAB) = 17 get_params(x::PSY.ActiveRenewableControllerAB) = @@ -131,23 +137,23 @@ get_params(x::PSY.ActiveRenewableControllerAB) = PSY.get_P_lim_inner(x)[1], PSY.get_P_lim_inner(x)[2], PSY.get_T_pord(x)] -get_params_symbol(::PSY.ActiveRenewableControllerAB) = [:K_pg, - :K_ig, - :T_p_ap, #modified to make unique - :fdbd1, - :fdbd2, - :fe_min, - :fe_max, - :P_min, - :P_max, - :T_g_ap, #modified to make unique - :D_dn, - :D_up, - :dP_min, - :dP_max, - :P_min_inner, - :P_max_inner, - :T_pord] +get_params_symbol(::PSY.ActiveRenewableControllerAB) = [:K_pg_OuterControl, + :K_ig_OuterControl, + :T_p_ap_OuterControl, #modified to make unique + :fdbd1_OuterControl, + :fdbd2_OuterControl, + :fe_min_OuterControl, + :fe_max_OuterControl, + :P_min_OuterControl, + :P_max_OuterControl, + :T_g_ap_OuterControl, #modified to make unique + :D_dn_OuterControl, + :D_up_OuterControl, + :dP_min_OuterControl, + :dP_max_OuterControl, + :P_min_inner_OuterControl, + :P_max_inner_OuterControl, + :T_pord_OuterControl] get_n_params(::PSY.ReactiveRenewableControllerAB) = 22 get_params(x::PSY.ReactiveRenewableControllerAB) = [PSY.get_T_fltr(x), @@ -172,40 +178,51 @@ get_params(x::PSY.ReactiveRenewableControllerAB) = [PSY.get_T_fltr(x), PSY.get_V_lim(x)[2], PSY.get_K_qp(x), PSY.get_K_qi(x)] -get_params_symbol(::PSY.ReactiveRenewableControllerAB) = [:T_fltr, - :K_p, - :K_i, - :T_ft, - :T_fv, - :V_frz, - :R_c, - :X_c, - :K_c, - :e_min, - :e_max, - :dbd_pnts1, - :dbd_pnts2, - :Q_min, - :Q_max, - :T_p, - :Q_min_inner, - :Q_max_inner, - :V_min, - :V_max, - :K_qp, - :K_qi] +get_params_symbol(::PSY.ReactiveRenewableControllerAB) = [:T_fltr_OuterControl, + :K_p_OuterControl, + :K_i_OuterControl, + :T_ft_OuterControl, + :T_fv_OuterControl, + :V_frz_OuterControl, + :R_c_OuterControl, + :X_c_OuterControl, + :K_c_OuterControl, + :e_min_OuterControl, + :e_max_OuterControl, + :dbd_pnts1_OuterControl, + :dbd_pnts2_OuterControl, + :Q_min_OuterControl, + :Q_max_OuterControl, + :T_p_OuterControl, + :Q_min_inner_OuterControl, + :Q_max_inner_OuterControl, + :V_min_OuterControl, + :V_max_OuterControl, + :K_qp_OuterControl, + :K_qi_OuterControl] #REACTIVE POWER CONTROL get_n_params(::PSY.ReactivePowerDroop) = 2 get_params(x::PSY.ReactivePowerDroop) = [PSY.get_kq(x), PSY.get_ωf(x)] -get_params_symbol(x::PSY.ReactivePowerDroop) = [:kq, :ωf] +get_params_symbol(x::PSY.ReactivePowerDroop) = [:kq_OuterControl, :ωf_OuterControl] #INNER CONTROL get_n_params(::PSY.VoltageModeControl) = 10 get_params(x::PSY.VoltageModeControl) = [PSY.get_kpv(x), PSY.get_kiv(x), PSY.get_kffv(x), PSY.get_rv(x), PSY.get_lv(x), PSY.get_kpc(x), PSY.get_kic(x), PSY.get_kffi(x), PSY.get_ωad(x), PSY.get_kad(x)] get_params_symbol(x::PSY.VoltageModeControl) = - [:kpv, :kiv, :kffv, :rv, :lv, :kpc, :kic, :kffi, :ωad, :kad] + [ + :kpv_OuterControl, + :kiv_OuterControl, + :kffv_OuterControl, + :rv_OuterControl, + :lv_OuterControl, + :kpc_OuterControl, + :kic_OuterControl, + :kffi_OuterControl, + :ωad_OuterControl, + :kad_OuterControl, + ] get_n_params(::PSY.RECurrentControlB) = 13 get_params(x::PSY.RECurrentControlB) = @@ -224,31 +241,32 @@ get_params(x::PSY.RECurrentControlB) = PSY.get_T_iq(x), PSY.get_I_max(x)] get_params_symbol(x::PSY.RECurrentControlB) = - [:Vdip_min, - :Vdip_max, - :T_rv, - :dbd_pnts_1, - :dbd_pnts_2, - :K_qv, - :Iqinj_min, - :Iqinj_max, - :V_ref0, - :K_vp, - :K_vi, - :T_iq, - :I_max] + [:Vdip_min_OuterControl, + :Vdip_max_OuterControl, + :T_rv_OuterControl, + :dbd_pnts_1_OuterControl, + :dbd_pnts_2_OuterControl, + :K_qv_OuterControl, + :Iqinj_min_OuterControl, + :Iqinj_max_OuterControl, + :V_ref0_OuterControl, + :K_vp_OuterControl, + :K_vi_OuterControl, + :T_iq_OuterControl, + :I_max_OuterControl] #DC SOURCE get_n_params(::PSY.FixedDCSource) = 1 get_params(x::PSY.FixedDCSource) = [PSY.get_voltage(x)] -get_params_symbol(x::PSY.FixedDCSource) = [:voltage] +get_params_symbol(x::PSY.FixedDCSource) = [:voltage_DCSource] #FREQ ESTIMATOR get_n_params(::PSY.KauraPLL) = 3 get_params(x::PSY.KauraPLL) = [PSY.get_ω_lp(x), PSY.get_kp_pll(x), PSY.get_ki_pll(x)] -get_params_symbol(::PSY.KauraPLL) = [:ω_lp, :kp_pll, :ki_pll] +get_params_symbol(::PSY.KauraPLL) = + [:ω_lp_FrequencyEstimator, :kp_pll_FrequencyEstimator, :ki_pll_FrequencyEstimator] get_n_params(::PSY.FixedFrequency) = 1 get_params(x::PSY.FixedFrequency) = [PSY.get_frequency(x)] -get_params_symbol(::PSY.FixedFrequency) = [:frequency] +get_params_symbol(::PSY.FixedFrequency) = [:frequency_FrequencyEstimator] #CONVERTER get_n_params(::PSY.AverageConverter) = 0 get_params(x::PSY.AverageConverter) = Float64[] @@ -271,23 +289,23 @@ get_params(x::PSY.RenewableEnergyConverterTypeA) = [PSY.get_T_g(x), PSY.get_Q_ref(x), PSY.get_R_source(x), PSY.get_X_source(x)] -get_params_symbol(::PSY.RenewableEnergyConverterTypeA) = [:T_g, - :Rrpwr, - :Brkpt, - :Zerox, - :Lvpl1, - :Vo_lim, - :Lv_pnt0, - :Lv_pnt1, - :Io_lim, - :T_fltr_cnv, #modified to make unique - :K_hv, - :Iqr_min, - :Iqr_max, - :Accel, - :Q_ref_cnv, #modified to make unique - :R_source, - :X_source] +get_params_symbol(::PSY.RenewableEnergyConverterTypeA) = [:T_g_Converter, + :Rrpwr_Converter, + :Brkpt_Converter, + :Zerox_Converter, + :Lvpl1_Converter, + :Vo_lim_Converter, + :Lv_pnt0_Converter, + :Lv_pnt1_Converter, + :Io_lim_Converter, + :T_fltr_cnv_Converter, #modified to make unique + :K_hv_Converter, + :Iqr_min_Converter, + :Iqr_max_Converter, + :Accel_Converter, + :Q_ref_cnv_Converter, #modified to make unique + :R_source_Converter, + :X_source_Converter] #GENERATORS get_n_params(g::PSY.DynamicGenerator) = @@ -322,7 +340,7 @@ get_params_symbol(g::PSY.DynamicGenerator) = vcat( #MACHINES get_n_params(::PSY.BaseMachine) = 3 get_params(x::PSY.BaseMachine) = [PSY.get_R(x), PSY.get_Xd_p(x), PSY.get_eq_p(x)] -get_params_symbol(::PSY.BaseMachine) = [:R, :Xd_p, :eq_p] +get_params_symbol(::PSY.BaseMachine) = [:R_Machine, :Xd_p_Machine, :eq_p_Machine] get_n_params(::PSY.OneDOneQMachine) = 7 get_params(x::PSY.OneDOneQMachine) = [ PSY.get_R(x), @@ -333,7 +351,15 @@ get_params(x::PSY.OneDOneQMachine) = [ PSY.get_Td0_p(x), PSY.get_Tq0_p(x), ] -get_params_symbol(x::PSY.OneDOneQMachine) = [:R, :Xd, :Xq, :Xd_p, :Xq_p, :Td0_p, :Tq0_p] +get_params_symbol(x::PSY.OneDOneQMachine) = [ + :R_Machine, + :Xd_Machine, + :Xq_Machine, + :Xd_p_Machine, + :Xq_p_Machine, + :Td0_p_Machine, + :Tq0_p_Machine, +] get_n_params(::PSY.MarconatoMachine) = 14 get_params(x::PSY.MarconatoMachine) = [PSY.get_R(x), PSY.get_Xd(x), PSY.get_Xq(x), PSY.get_Xd_p(x), PSY.get_Xq_p(x), @@ -341,20 +367,20 @@ get_params(x::PSY.MarconatoMachine) = PSY.get_Td0_p(x), PSY.get_Tq0_p(x), PSY.get_Td0_pp(x), PSY.get_Tq0_pp(x), PSY.get_T_AA(x), PSY.get_γd(x), PSY.get_γq(x)] get_params_symbol(x::PSY.MarconatoMachine) = [ - :R, - :Xd, - :Xq, - :Xd_p, - :Xq_p, - :Xd_pp, - :Xq_pp, - :Td0_p, - :Tq0_p, - :Td0_pp, - :Tq0_pp, - :T_AA, - :γd, - :γq, + :R_Machine, + :Xd_Machine, + :Xq_Machine, + :Xd_p_Machine, + :Xq_p_Machine, + :Xd_pp_Machine, + :Xq_pp_Machine, + :Td0_p_Machine, + :Tq0_p_Machine, + :Td0_pp_Machine, + :Tq0_pp_Machine, + :T_AA_Machine, + :γd_Machine, + :γq_Machine, ] get_n_params(::PSY.AndersonFouadMachine) = 11 get_params(x::PSY.AndersonFouadMachine) = [ @@ -370,17 +396,17 @@ get_params(x::PSY.AndersonFouadMachine) = [ PSY.get_Td0_pp(x), PSY.get_Tq0_pp(x)] -get_params_symbol(x::PSY.AndersonFouadMachine) = [:R, - :Xd, - :Xq, - :Xd_p, - :Xq_p, - :Xd_pp, - :Xq_pp, - :Td0_p, - :Tq0_p, - :Td0_pp, - :Tq0_pp] +get_params_symbol(x::PSY.AndersonFouadMachine) = [:R_Machine, + :Xd_Machine, + :Xq_Machine, + :Xd_p_Machine, + :Xq_p_Machine, + :Xd_pp_Machine, + :Xq_pp_Machine, + :Td0_p_Machine, + :Tq0_p_Machine, + :Td0_pp_Machine, + :Tq0_pp_Machine] #NOTE: Saturation not considered as paramters get_n_params( @@ -409,22 +435,22 @@ get_params( get_params_symbol( ::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, ) = [ - :R, - :Td0_p, - :Td0_pp, - :Tq0_p, - :Tq0_pp, - :Xd, - :Xq, - :Xd_p, - :Xq_p, - :Xd_pp, - :Xl, - :γ_d1, - :γ_q1, - :γ_d2, - :γ_q2, - :γ_qd, + :R_Machine, + :Td0_p_Machine, + :Td0_pp_Machine, + :Tq0_p_Machine, + :Tq0_pp_Machine, + :Xd_Machine, + :Xq_Machine, + :Xd_p_Machine, + :Xq_p_Machine, + :Xd_pp_Machine, + :Xl_Machine, + :γ_d1_Machine, + :γ_q1_Machine, + :γ_d2_Machine, + :γ_q2_Machine, + :γ_qd_Machine, ] get_n_params( ::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, @@ -448,24 +474,24 @@ get_params( get_params_symbol( ::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, ) = [ - :R, - :Td0_p, - :Td0_pp, - :Tq0_pp, - :Xd, - :Xq, - :Xd_p, - :Xd_pp, - :Xl, - :γ_d1, - :γ_q1, - :γ_d2, + :R_Machine, + :Td0_p_Machine, + :Td0_pp_Machine, + :Tq0_pp_Machine, + :Xd_Machine, + :Xq_Machine, + :Xd_p_Machine, + :Xd_pp_Machine, + :Xl_Machine, + :γ_d1_Machine, + :γ_q1_Machine, + :γ_d2_Machine, ] #SHAFTS get_n_params(::PSY.SingleMass) = 2 get_params(x::PSY.SingleMass) = [PSY.get_H(x), PSY.get_D(x)] -get_params_symbol(::PSY.SingleMass) = [:H, :D] +get_params_symbol(::PSY.SingleMass) = [:H_Shaft, :D_Shaft] get_n_params(::PSY.FiveMassShaft) = 18 get_params(x::PSY.FiveMassShaft) = [ PSY.get_H(x), @@ -489,24 +515,24 @@ get_params(x::PSY.FiveMassShaft) = [ ] get_params_symbol(::PSY.FiveMassShaft) = [ - :H, - :H_hp, - :H_ip, - :H_lp, - :H_ex, - :D, - :D_hp, - :D_ip, - :D_lp, - :D_ex, - :D_12, - :D_23, - :D_34, - :D_45, - :K_hp, - :K_ip, - :K_lp, - :K_ex] + :H_Shaft, + :H_hp_Shaft, + :H_ip_Shaft, + :H_lp_Shaft, + :H_ex_Shaft, + :D_Shaft, + :D_hp_Shaft, + :D_ip_Shaft, + :D_lp_Shaft, + :D_ex_Shaft, + :D_12_Shaft, + :D_23_Shaft, + :D_34_Shaft, + :D_45_Shaft, + :K_hp_Shaft, + :K_ip_Shaft, + :K_lp_Shaft, + :K_ex_Shaft] #AVRS get_n_params(::PSY.AVRFixed) = 0 @@ -514,7 +540,7 @@ get_params(x::PSY.AVRFixed) = Float64[] get_params_symbol(::PSY.AVRFixed) = Symbol[] get_n_params(::PSY.AVRSimple) = 1 get_params(x::PSY.AVRSimple) = [PSY.get_Kv(x)] -get_params_symbol(::PSY.AVRSimple) = [:Kv] +get_params_symbol(::PSY.AVRSimple) = [:Kv_AVR] get_n_params(::PSY.AVRTypeI) = 9 get_params(x::PSY.AVRTypeI) = [ PSY.get_Ka(x), @@ -527,7 +553,8 @@ get_params(x::PSY.AVRTypeI) = [ PSY.get_Ae(x), PSY.get_Be(x), ] -get_params_symbol(::PSY.AVRTypeI) = [:Ka, :Ke, :Kf, :Ta, :Te, :Tf, :Tr, :Ae, :Be] +get_params_symbol(::PSY.AVRTypeI) = + [:Ka_AVR, :Ke_AVR, :Kf_AVR, :Ta_AVR, :Te_AVR, :Tf_AVR, :Tr_AVR, :Ae_AVR, :Be_AVR] get_n_params(::PSY.SEXS) = 6 get_params(x::PSY.SEXS) = [ PSY.get_Ta_Tb(x), @@ -537,7 +564,8 @@ get_params(x::PSY.SEXS) = [ PSY.get_V_lim(x)[1], PSY.get_V_lim(x)[2], ] -get_params_symbol(::PSY.SEXS) = Symbol[:Ta_Tb, :Tb, :K, :Te, :V_min_avr, :V_max_avr] +get_params_symbol(::PSY.SEXS) = + Symbol[:Ta_Tb_AVR, :Tb_AVR, :K_AVR, :Te_AVR, :V_min_AVR, :V_max_AVR] get_n_params(::PSY.AVRTypeII) = 11 get_params(x::PSY.AVRTypeII) = [PSY.get_K0(x), @@ -552,17 +580,17 @@ get_params(x::PSY.AVRTypeII) = PSY.get_Ae(x), PSY.get_Be(x)] get_params_symbol(::PSY.AVRTypeII) = - [:K0, - :T1, - :T2, - :T3, - :T4, - :Te, - :Tr, - :Va_min, - :Va_max, - :Ae, - :Be] + [:K0_AVR, + :T1_AVR, + :T2_AVR, + :T3_AVR, + :T4_AVR, + :Te_AVR, + :Tr_AVR, + :Va_min_AVR, + :Va_max_AVR, + :Ae_AVR, + :Be_AVR] get_n_params(::PSY.ESAC1A) = 15 get_params(x::PSY.ESAC1A) = [ PSY.get_Tr(x), @@ -581,20 +609,20 @@ get_params(x::PSY.ESAC1A) = [ PSY.get_Vr_lim(x)[1], PSY.get_Vr_lim(x)[2]] get_params_symbol(::PSY.ESAC1A) = [:Tr, - :Tb, - :Tc, - :Ka, - :Ta, - :Va_min, - :Va_max, - :Te, - :Kf, - :Tf, - :Kc, - :Kd, - :Ke, - :Vr_min, - :Vr_max] + :Tb_AVR, + :Tc_AVR, + :Ka_AVR, + :Ta_AVR, + :Va_min_AVR, + :Va_max_AVR, + :Te_AVR, + :Kf_AVR, + :Tf_AVR, + :Kc_AVR, + :Kd_AVR, + :Ke_AVR, + :Vr_min_AVR, + :Vr_max_AVR] get_n_params(::PSY.EXST1) = 12 get_params(x::PSY.EXST1) = [PSY.get_Tr(x), PSY.get_Vi_lim(x)[1], @@ -609,18 +637,18 @@ get_params(x::PSY.EXST1) = [PSY.get_Tr(x), PSY.get_Kf(x), PSY.get_Tf(x)] get_params_symbol(::PSY.EXST1) = [ - :Tr_avr, #modified to make unique - :Vi_min, - :Vi_max, - :Tc, - :Tb, - :Ka, - :Ta, - :Vr_min, - :Vr_max, - :Kc, - :Kf, - :Tf_avr, #modified to make unique + :Tr_AVR, + :Vi_min_AVR, + :Vi_max_AVR, + :Tc_AVR, + :Tb_AVR, + :Ka_AVR, + :Ta_AVR, + :Vr_min_AVR, + :Vr_max_AVR, + :Kc_AVR, + :Kf_AVR, + :Tf_AVR, ] get_n_params(::PSY.EXAC1) = 13 @@ -640,27 +668,27 @@ get_params(x::PSY.EXAC1) = [ PSY.get_Ke(x)] get_params_symbol(::PSY.EXAC1) = [ - :Tr_avr, #modified to make unique - :Tb, - :Tc, - :Ka, - :Ta, - :Vr_min, - :Vr_max, - :Te, - :Kf, - :Tf_avr, #modified to make unique - :Kc, - :Kd, - :Ke] - -#PRIME MOVERS + :Tr_AVR, + :Tb_AVR, + :Tc_AVR, + :Ka_AVR, + :Ta_AVR, + :Vr_min_AVR, + :Vr_max_AVR, + :Te_AVR, + :Kf_AVR, + :Tf_AVR, + :Kc_AVR, + :Kd_AVR, + :Ke_AVR] + +#TurbineGov get_n_params(::PSY.TGFixed) = 1 get_params(x::PSY.TGFixed) = [PSY.get_efficiency(x)] -get_params_symbol(::PSY.TGFixed) = [:efficiency] +get_params_symbol(::PSY.TGFixed) = [:efficiency_TurbineGov] get_n_params(::PSY.TGTypeII) = 3 get_params(x::PSY.TGTypeII) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_T2(x)] -get_params_symbol(::PSY.TGTypeII) = [:R_tg, :T1, :T2] +get_params_symbol(::PSY.TGTypeII) = [:R_tg_TurbineGovR, :T1_TurbineGov, :T2_TurbineGov] get_n_params(::PSY.GasTG) = 9 get_params(x::PSY.GasTG) = [ PSY.get_R(x), @@ -673,7 +701,17 @@ get_params(x::PSY.GasTG) = [ PSY.get_V_lim(x)[2], PSY.get_D_turb(x), ] -get_params_symbol(::PSY.GasTG) = [:R_tg, :T1, :T2, :T3, :AT, :Kt, :V_min, :V_max, :D_turb] +get_params_symbol(::PSY.GasTG) = [ + :R_tg_TurbineGov, + :T1_TurbineGov, + :T2_TurbineGov, + :T3_TurbineGov, + :AT_TurbineGov, + :Kt_TurbineGov, + :V_min_TurbineGov, + :V_max_TurbineGov, + :D_turb_TurbineGov, +] get_n_params(::PSY.TGTypeI) = 8 get_params(x::PSY.TGTypeI) = [PSY.get_R(x), PSY.get_Ts(x), @@ -685,14 +723,14 @@ get_params(x::PSY.TGTypeI) = [PSY.get_R(x), PSY.get_valve_position_limits(x)[2], ] -get_params_symbol(::PSY.TGTypeI) = [:R_tg, - :Ts, - :Tc, - :T3_tg, #modified to make unique - :T4_tg, #modified to make unique - :T5_tg, #modified to make unique - :valve_position_min, - :valve_position_max, +get_params_symbol(::PSY.TGTypeI) = [:R_tg_TurbineGov, + :Ts_TurbineGov, + :Tc_TurbineGov, + :T3_TurbineGov, + :T4_TurbineGov, + :T5_TurbineGov, + :valve_position_min_TurbineGov, + :valve_position_max_TurbineGov, ] get_n_params(::PSY.SteamTurbineGov1) = 7 get_params(x::PSY.SteamTurbineGov1) = [PSY.get_R(x), @@ -703,12 +741,12 @@ get_params(x::PSY.SteamTurbineGov1) = [PSY.get_R(x), PSY.get_T3(x), PSY.get_D_T(x)] get_params_symbol(::PSY.SteamTurbineGov1) = [:R_tg, - :T1_tg, #modified to make unique - :valve_position_min, - :valve_position_max, - :T2_tg, #modified to make unique - :T3_tg, #modified to make unique - :D_T] + :T1_TurbineGov, + :valve_position_min_TurbineGov, + :valve_position_max_TurbineGov, + :T2_TurbineGov, + :T3_TurbineGov, + :D_T_TurbineGov] get_n_params(::PSY.HydroTurbineGov) = 12 get_params(x::PSY.HydroTurbineGov) = [PSY.get_R(x), PSY.get_r(x), @@ -723,23 +761,23 @@ get_params(x::PSY.HydroTurbineGov) = [PSY.get_R(x), PSY.get_D_T(x), PSY.get_q_nl(x)] get_params_symbol(::PSY.HydroTurbineGov) = [ - :R_tg, #modified to make unique - :r, - :Tr, - :Tf, - :Tg, - :VELM, - :G_min, - :G_max, - :Tw, - :At, - :D_T, - :q_nl] + :R_TurbineGov, + :r_TurbineGov, + :Tr_TurbineGov, + :Tf_TurbineGov, + :Tg_TurbineGov, + :VELM_TurbineGov, + :G_min_TurbineGov, + :G_max_TurbineGov, + :Tw_TurbineGov, + :At_TurbineGov, + :D_T_TurbineGov, + :q_nl_TurbineGov] #PSS get_n_params(::PSY.PSSFixed) = 1 get_params(x::PSY.PSSFixed) = [PSY.get_V_pss(x)] -get_params_symbol(::PSY.PSSFixed) = [:V_pss] +get_params_symbol(::PSY.PSSFixed) = [:V_pss_PSS] get_n_params(::PSY.STAB1) = 7 get_params(x::PSY.STAB1) = [PSY.get_KT(x), @@ -750,13 +788,13 @@ get_params(x::PSY.STAB1) = [PSY.get_KT(x), PSY.get_T4(x), PSY.get_H_lim(x)] get_params_symbol(::PSY.STAB1) = - [:KT, - :T, - :T1T3, - :T3, - :T2T4, - :T4, - :H_lim] + [:KT_PSS, + :T_PSS, + :T1T3_PSS, + :T3_PSS, + :T2T4_PSS, + :T4_PSS, + :H_lim_PSS] #STATIC INJECTION get_n_params(::PSY.StaticInjection) = 1 From b2b06073de3575172a6987a0f893b8b952308eea Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 24 Apr 2024 15:59:24 -0400 Subject: [PATCH 06/76] sensitivity api (work in progress) --- Project.toml | 16 +- src/PowerSimulationsDynamics.jl | 5 + src/base/caches.jl | 39 ++- src/base/definitions.jl | 2 +- src/base/device_wrapper.jl | 4 +- src/base/jacobian.jl | 6 +- src/base/nlsolve_wrapper.jl | 26 +- src/base/perturbations.jl | 32 +- src/base/sensitivity_analysis.jl | 110 +++++++ src/base/simulation.jl | 202 ++++++++++-- src/base/simulation_initialization.jl | 53 +-- src/base/simulation_inputs.jl | 13 +- src/base/simulation_results.jl | 4 +- src/base/small_signal.jl | 2 +- .../generator_components/init_avr.jl | 46 ++- .../generator_components/init_machine.jl | 42 ++- .../generator_components/init_shaft.jl | 2 +- .../generator_components/init_tg.jl | 22 +- src/initialization/init_device.jl | 26 +- .../inverter_components/init_converter.jl | 4 +- .../inverter_components/init_filter.jl | 4 +- .../init_frequency_estimator.jl | 4 +- .../inverter_components/init_inner.jl | 8 +- src/models/branch.jl | 4 +- src/models/device.jl | 30 +- src/models/dynline_model.jl | 4 +- src/models/generator_models/avr_models.jl | 2 +- src/models/generator_models/machine_models.jl | 2 +- src/models/generator_models/pss_models.jl | 2 +- src/models/generator_models/shaft_models.jl | 2 +- src/models/generator_models/tg_models.jl | 2 +- src/models/inverter_models/DCside_models.jl | 2 +- .../inverter_models/converter_models.jl | 2 +- src/models/inverter_models/filter_models.jl | 2 +- .../frequency_estimator_models.jl | 2 +- .../inverter_models/inner_control_models.jl | 2 +- .../inverter_models/outer_control_models.jl | 2 +- src/models/network_model.jl | 2 +- src/models/saturation_models.jl | 4 +- src/models/system.jl | 8 +- src/post_processing/post_proc_generator.jl | 4 +- src/post_processing/post_proc_inverter.jl | 12 +- src/utils/psy_utils.jl | 7 - test/runtests.jl | 4 + test/test_base.jl | 12 +- test/test_case_sensitivity.jl | 303 ++++++++++++++++++ 46 files changed, 860 insertions(+), 228 deletions(-) create mode 100644 src/base/sensitivity_analysis.jl create mode 100644 test/test_case_sensitivity.jl diff --git a/Project.toml b/Project.toml index 1355baf98..050949752 100644 --- a/Project.toml +++ b/Project.toml @@ -4,6 +4,8 @@ authors = ["Jose Daniel Lara, Rodrigo Henriquez"] version = "0.14.1" [deps] +Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" +ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" @@ -21,23 +23,27 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" +Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [compat] +Accessors = "0.1.36" +ChainRulesCore = "1.23" DataFrames = "1" DataStructures = "~0.18" DocStringExtensions = "~0.9" FastClosures = "^0.3" ForwardDiff = "~v0.10" InfrastructureSystems = "^1.21" +LinearAlgebra = "1" +Logging = "1" NLsolve = "4" -PowerSystems = "^3.1.2" PowerFlows = "^0.6" PowerNetworkMatrices = "^0.9" +PowerSystems = "^3.1.2" PrettyTables = "1, 2" -SciMLBase = "2" -TimerOutputs = "~0.5" -LinearAlgebra = "1" -Logging = "1" Random = "1" +SciMLBase = "2" SparseArrays = "1" +TimerOutputs = "~0.5" +Zygote = "0.6" julia = "^1.6" diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index 369e6ab12..52f7107e6 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -81,12 +81,16 @@ import PowerFlows import PowerNetworkMatrices import TimerOutputs import FastClosures: @closure +import Zygote +import ChainRulesCore +import Accessors const PSY = PowerSystems const IS = InfrastructureSystems const PSID = PowerSimulationsDynamics const PF = PowerFlows const PNM = PowerNetworkMatrices +const CRC = ChainRulesCore using DocStringExtensions @@ -118,6 +122,7 @@ include("base/nlsolve_wrapper.jl") include("base/simulation_initialization.jl") include("base/small_signal.jl") include("base/model_validation.jl") +include("base/sensitivity_analysis.jl") #Common Models include("models/branch.jl") diff --git a/src/base/caches.jl b/src/base/caches.jl index 5d55ed8e1..eb8eb2f0f 100644 --- a/src/base/caches.jl +++ b/src/base/caches.jl @@ -22,7 +22,7 @@ end function JacobianCache{U}(F, inputs::SimulationInputs) where {U <: ForwardDiff.Dual} n_inj = get_injection_n_states(inputs) n_branches = get_branches_n_states(inputs) - @debug "injection ode size = $n_inj branches ode size = $n_branches" + CRC.@ignore_derivatives @debug "injection ode size = $n_inj branches ode size = $n_branches" bus_count = get_bus_count(inputs) inner_vars_count = get_inner_vars_count(inputs) n_global_vars = length(keys(get_global_vars_update_pointers(inputs))) @@ -70,28 +70,33 @@ get_global_vars(jc::JacobianCache, ::Type{T}) where {T <: ForwardDiff.Dual} = struct SimCache{F} <: Cache f!::F bus_count::Int - ode_output::Vector{Float64} - branches_ode::Vector{Float64} - current_balance::Vector{Float64} - inner_vars::Vector{Float64} - global_vars::Vector{Float64} + ode_output::Vector{Real} + branches_ode::Vector{Real} + current_balance::Vector{Real} + inner_vars::Vector{Real} + global_vars::Vector{Real} end function SimCache(f!, inputs::SimulationInputs) n_inj = get_injection_n_states(inputs) n_branches = get_branches_n_states(inputs) - @debug "injection ode size = $n_inj branches ode size = $n_branches" + CRC.@ignore_derivatives @debug "injection ode size = $n_inj branches ode size = $n_branches" bus_count = get_bus_count(inputs) inner_vars_count = get_inner_vars_count(inputs) n_global_vars = length(keys(get_global_vars_update_pointers(inputs))) + global_vars = CRC.@ignore_derivatives setindex!( + zeros(Real, n_global_vars), + 1.0, + GLOBAL_VAR_SYS_FREQ_INDEX, + ) return SimCache{typeof(f!)}( f!, bus_count, - zeros(Float64, n_inj), - zeros(Float64, n_branches), - zeros(Float64, 2 * bus_count), - zeros(Float64, inner_vars_count), - setindex!(zeros(Float64, n_global_vars), 1.0, GLOBAL_VAR_SYS_FREQ_INDEX), + zeros(Real, n_inj), + zeros(Real, n_branches), + zeros(Real, 2 * bus_count), + zeros(Real, inner_vars_count), + global_vars, ) end @@ -103,11 +108,11 @@ function get_current_injections_i(sc::SimCache, ::Type{Float64}) return view(sc.current_balance, ((sc.bus_count + 1):(sc.bus_count * 2))) end -get_ode_output(sc::SimCache, ::Type{Float64}) = sc.ode_output -get_branches_ode(sc::SimCache, ::Type{Float64}) = sc.branches_ode -get_current_balance(sc::SimCache, ::Type{Float64}) = sc.current_balance -get_inner_vars(sc::SimCache, ::Type{Float64}) = sc.inner_vars -get_global_vars(sc::SimCache, ::Type{Float64}) = sc.global_vars +get_ode_output(sc::SimCache, ::Type{T}) where {T <: Real} = sc.ode_output +get_branches_ode(sc::SimCache, ::Type{T}) where {T <: Real} = sc.branches_ode +get_current_balance(sc::SimCache, ::Type{T}) where {T <: Real} = sc.current_balance +get_inner_vars(sc::SimCache, ::Type{T}) where {T <: Real} = sc.inner_vars +get_global_vars(sc::SimCache, ::Type{T}) where {T <: Real} = sc.global_vars get_ω_sys(cache::Cache, T::Type{<:Union{Float64, ForwardDiff.Dual}}) = get_global_vars(cache, T)[GLOBAL_VAR_SYS_FREQ_INDEX] diff --git a/src/base/definitions.jl b/src/base/definitions.jl index e72214413..433a2e02a 100644 --- a/src/base/definitions.jl +++ b/src/base/definitions.jl @@ -243,4 +243,4 @@ end const BUILD_TIMER = TimerOutputs.TimerOutput() -const ACCEPTED_REAL_TYPES = Union{Float64, ForwardDiff.Dual} +const ACCEPTED_REAL_TYPES = Union{Float64, ForwardDiff.Dual, Real} diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index 2274dbda1..ae842cccc 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -522,9 +522,9 @@ set_Q_impedance!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.Q_impedance function set_connection_status(wrapper::Union{StaticWrapper, DynamicWrapper}, val::Int) if val == 0 - @debug "Generator $(PSY.get_name(wrapper)) status set to off" + CRC.@ignore_derivatives @debug "Generator $(PSY.get_name(wrapper)) status set to off" elseif val == 1 - @debug "Generator $(PSY.get_name(wrapper)) status set to on" + CRC.@ignore_derivatives @debug "Generator $(PSY.get_name(wrapper)) status set to on" else error("Invalid status $val. It can only take values 1 or 0") end diff --git a/src/base/jacobian.jl b/src/base/jacobian.jl index d0460ccf5..f9c724b71 100644 --- a/src/base/jacobian.jl +++ b/src/base/jacobian.jl @@ -97,7 +97,7 @@ function JacobianFunctionWrapper( m_ = (residual, x) -> m!(residual, x, p, 0.0) jconfig = ForwardDiff.JacobianConfig(m_, similar(x0), x0, ForwardDiff.Chunk(x0)) Jf = (Jv, x) -> begin - @debug "Evaluating Jacobian Function" + CRC.@ignore_derivatives @debug "Evaluating Jacobian Function" ForwardDiff.jacobian!(Jv, m_, zeros(n), x, jconfig) return end @@ -137,7 +137,7 @@ function JacobianFunctionWrapper( m_ = (residual, x) -> m!(residual, zeros(n), x, p, 0.0) jconfig = ForwardDiff.JacobianConfig(m_, similar(x0), x0, ForwardDiff.Chunk(x0)) Jf = (Jv, x) -> begin - @debug "Evaluating Jacobian Function" + CRC.@ignore_derivatives @debug "Evaluating Jacobian Function" ForwardDiff.jacobian!(Jv, m_, zeros(n), x, jconfig) return end @@ -178,7 +178,7 @@ function JacobianFunctionWrapper( n = length(x0) Jf = (Jv, x, h, t) -> begin - @debug "Evaluating Jacobian Function" + CRC.@ignore_derivatives @debug "Evaluating Jacobian Function" m_ = (residual, x) -> m!(residual, x, h, p, t) jconfig = ForwardDiff.JacobianConfig(m_, similar(x0), x0, ForwardDiff.Chunk(x0)) diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index ae5ef3f69..cf2d90f1c 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -82,11 +82,11 @@ end function _convergence_check(sys_solve::NLsolveWrapper, tol::Float64, solv::Symbol) if converged(sys_solve) - @info( + CRC.@ignore_derivatives @info( "Initialization non-linear solve succeeded with a tolerance of $(tol) using solver $(solv). Saving solution." ) else - @warn( + CRC.@ignore_derivatives @warn( "Initialization non-linear solve convergence failed, initial conditions do not meet conditions for an stable equilibrium.\nAttempting again with reduced numeric tolerance and using another solver" ) end @@ -95,14 +95,14 @@ end function _sorted_residuals(residual::Vector{Float64}) if isapprox(sum(abs.(residual)), 0.0; atol = STRICT_NLSOLVE_F_TOLERANCE) - @debug "Residual is zero with tolerance $(STRICT_NLSOLVE_F_TOLERANCE)" + CRC.@ignore_derivatives @debug "Residual is zero with tolerance $(STRICT_NLSOLVE_F_TOLERANCE)" return end ix_sorted = sortperm(abs.(residual); rev = true) show_residual = min(10, length(residual)) for i in 1:show_residual ix = ix_sorted[i] - @debug ix abs(residual[ix]) + CRC.@ignore_derivatives @debug ix abs(residual[ix]) end return end @@ -112,10 +112,10 @@ function _check_residual( inputs::SimulationInputs, tolerance::Float64, ) - @debug _sorted_residuals(residual) + CRC.@ignore_derivatives @debug _sorted_residuals(residual) val, ix = findmax(residual) sum_residual = sum(abs.(residual)) - @info "Residual from initial guess: max = $(val) at $ix, total = $sum_residual" + CRC.@ignore_derivatives @info "Residual from initial guess: max = $(val) at $ix, total = $sum_residual" if sum_residual > tolerance state_map = make_global_state_map(inputs) for (k, val) in state_map @@ -169,13 +169,13 @@ function refine_initial_condition!( break end for solv in [:trust_region, :newton] - @debug "Start NLSolve System Run with $(solv) and F_tol = $tol" + CRC.@ignore_derivatives @debug "Start NLSolve System Run with $(solv) and F_tol = $tol" show_trace = sim.console_level <= Logging.Info sys_solve = _nlsolve_call(initial_guess, f!, jacobian, tol, solv, show_trace) #sys_solve = _nlsolve_call(initial_guess, f!, tol, solv, show_trace) failed(sys_solve) && return BUILD_FAILED converged = _convergence_check(sys_solve, tol, solv) - @debug "Write initial guess vector using $solv with tol = $tol convergence = $converged" + CRC.@ignore_derivatives @debug "Write initial guess vector using $solv with tol = $tol convergence = $converged" initial_guess .= sys_solve.zero if converged break @@ -193,14 +193,16 @@ function refine_initial_condition!( f!(residual, initial_guess) if !converged || (sum(residual) > MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE) _check_residual(residual, inputs, MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE) - @warn("Initialization didn't found a solution to desired tolerances.\\ - Initial conditions do not meet conditions for an stable equilibrium. \\ - Simulation might fail") + CRC.@ignore_derivatives @warn( + "Initialization didn't found a solution to desired tolerances.\\ +Initial conditions do not meet conditions for an stable equilibrium. \\ +Simulation might fail" + ) end pf_diff = abs.(powerflow_solution .- initial_guess[bus_range]) if maximum(pf_diff) > MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE - @warn "The resulting voltages in the initial conditions differ from the power flow results" + CRC.@ignore_derivatives @warn "The resulting voltages in the initial conditions differ from the power flow results" end return end diff --git a/src/base/perturbations.jl b/src/base/perturbations.jl index cff5d4aca..a68dc7786 100644 --- a/src/base/perturbations.jl +++ b/src/base/perturbations.jl @@ -92,7 +92,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::BranchImped end return (integrator) -> begin - @debug "Changing impedance line $(PSY.get_name(branch)) by a factor of $(pert.multiplier)" + CRC.@ignore_derivatives @debug "Changing impedance line $(PSY.get_name(branch)) by a factor of $(pert.multiplier)" ybus_update!(inputs, branch, mult) end @@ -102,7 +102,7 @@ end function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::BranchTrip) branch = _get_branch_for_perturbation(sys, pert) return (integrator) -> begin - @debug "Tripping line $(PSY.get_name(branch))" + CRC.@ignore_derivatives @debug "Tripping line $(PSY.get_name(branch))" ybus_update!(inputs, branch, -1.0) end return @@ -371,7 +371,7 @@ function get_affect(inputs::SimulationInputs, ::PSY.System, pert::NetworkSwitch) return (integrator) -> begin # TODO: This code can be more performant using SparseMatrix methods for (i, v) in enumerate(pert.ybus_rectangular) - @debug "Changing Ybus network" + CRC.@ignore_derivatives @debug "Changing Ybus network" get_ybus(inputs)[i] = v end return @@ -556,9 +556,9 @@ function get_affect(inputs::SimulationInputs, ::PSY.System, pert::GeneratorTrip) return (integrator) -> begin wrapped_device = get_dynamic_injectors(inputs)[wrapped_device_ix] ix_range = get_ix_range(wrapped_device) - @debug "Changing connection status $(PSY.get_name(wrapped_device)), setting states $ix_range to 0.0" + CRC.@ignore_derivatives @debug "Changing connection status $(PSY.get_name(wrapped_device)), setting states $ix_range to 0.0" if integrator.du !== nothing - @debug "setting du $ix_range to 0.0" + CRC.@ignore_derivatives @debug "setting du $ix_range to 0.0" integrator.du[ix_range] .= 0.0 end integrator.u[ix_range] .= 0.0 @@ -599,7 +599,7 @@ mutable struct LoadChange <: Perturbation ) # Currently I'm assumming P_ref and Q_ref are constant impedance to if signal ∈ [:P_ref, :Q_ref] - @warn( + CRC.@ignore_derivatives @warn( "P_ref and Q_ref signals will be deprecated. It will be assumed as a change in constant impedance for StandardLoads and a change in constant power for PowerLoads. Allowed signals are $(ACCEPTED_LOADCHANGE_REFS)" ) end @@ -626,7 +626,9 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) wrapped_device_ix = _find_zip_load_ix(inputs, pert.device) ld = pert.device if !PSY.get_available(ld) - @error("Load $(PSY.get_name(ld)) is unavailable. Perturbation ignored") + CRC.@ignore_derivatives @error( + "Load $(PSY.get_name(ld)) is unavailable. Perturbation ignored" + ) return end ref_value = pert.ref_value @@ -652,7 +654,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) device_parameters = @view integrator.p[p_range] device_parameters[3] += P_change device_parameters[6] += Q_change - @debug "Changing load at bus $(PSY.get_name(wrapped_zip)) $(pert.signal) to $(pert.ref_value)" + CRC.@ignore_derivatives @debug "Changing load at bus $(PSY.get_name(wrapped_zip)) $(pert.signal) to $(pert.ref_value)" return end elseif isa(ld, PSY.StandardLoad) @@ -702,7 +704,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) Q_exp_old = exp_params.Q_exp exp_params.P_exp = P_exp_old + P_change exp_params.Q_exp = Q_exp_old + Q_change - @debug "Removing exponential load entry $(ld_name) at wrapper $(PSY.get_name(wrapped_zip))" + CRC.@ignore_derivatives @debug "Removing exponential load entry $(ld_name) at wrapper $(PSY.get_name(wrapped_zip))" return end else @@ -736,7 +738,9 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) wrapped_device_ix = _find_zip_load_ix(inputs, pert.device) ld = pert.device if !PSY.get_available(ld) - @error("Load $(PSY.get_name(ld)) is unavailable. Perturbation ignored") + CRC.@ignore_derivatives @error( + "Load $(PSY.get_name(ld)) is unavailable. Perturbation ignored" + ) return end if isa(ld, PSY.PowerLoad) @@ -750,7 +754,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) device_parameters = @view integrator.p[p_range] device_parameters[3] -= P_trip device_parameters[6] -= Q_trip - @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" + CRC.@ignore_derivatives @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end elseif isa(ld, PSY.StandardLoad) @@ -775,7 +779,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) # Update Constant Impedance device_parameters[5] -= P_impedance_trip device_parameters[8] -= Q_impedance_trip - @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" + CRC.@ignore_derivatives @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end elseif isa(ld, PSY.ExponentialLoad) @@ -788,7 +792,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) tuple_ix = exp_names[ld_name] deleteat!(exp_params, tuple_ix) delete!(exp_names, ld_name) - @debug "Removing exponential load entry $(ld_name) at wrapper $(PSY.get_name(wrapped_zip))" + CRC.@ignore_derivatives @debug "Removing exponential load entry $(ld_name) at wrapper $(PSY.get_name(wrapped_zip))" return end end @@ -833,7 +837,7 @@ end function get_affect(::SimulationInputs, ::PSY.System, pert::PerturbState) return (integrator) -> begin - @debug "Modifying state" + CRC.@ignore_derivatives @debug "Modifying state" integrator.u[pert.index] += pert.value return end diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl new file mode 100644 index 000000000..6e8cf4e4d --- /dev/null +++ b/src/base/sensitivity_analysis.jl @@ -0,0 +1,110 @@ +""" +function f(::Simulation) + +end +g = get_parameter_sensitivity_function!(sim, Vector{Tuple{String, Type{T}, Symbol}}, f) where {T<: Union{Device, DynamicComponent} +p = get_parameter_sensitivity_values(sim, Vector{Tuple{String, Type{T}, Symbol}}, f) where {T<: Union{Device, DynamicComponent} + +Zygote.gradient(g, p) +""" + +function _append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Device} + return s +end +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.AVR} = Symbol(s, :_AVR) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Machine} = Symbol(s, :_Machine) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.PSS} = Symbol(s, :_PSS) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Shaft} = Symbol(s, :_Shaft) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.TurbineGov} = Symbol(s, :_TurbineGov) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Converter} = Symbol(s, :_Converter) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.DCSource} = Symbol(s, :_DCSource) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Filter} = Symbol(s, :_Filter) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.FrequencyEstimator} = + Symbol(s, :_FrequencyEstimator) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.InnerControl} = + Symbol(s, :_InnerControl) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.OuterControl} = + Symbol(s, :_OuterControl) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.InverterLimiter} = + Symbol(s, :_InverterLimiter) + +function get_indices_in_parameter_vector(sim, device_param_pairs) + indices = Int[] + for (device_name, component_type, param_symbol) in device_param_pairs + ix = findfirst( + x -> PSY.get_name(x.dynamic_device) == device_name, + sim.inputs_init.dynamic_injectors, + ) + if ix !== nothing + wrapped_device = sim.inputs_init.dynamic_injectors[ix] + else + ix = findfirst( + x -> PSY.get_name(x.device) == device_name, + sim.inputs_init.static_injectors, + ) + if ix !== nothing + wrapped_device = sim.inputs_init.static_injectors[ix] + else + CRC.@ignore_derivatives @error "Device name not found in dynamic or static injectors" + end + end + full_symbol = _append_symbol(param_symbol, component_type) + external_ix = get_p_range(wrapped_device) + internal_ix = findfirst(isequal(full_symbol), get_params_symbol(wrapped_device)) + global_ix = external_ix[internal_ix] + @assert global_ix !== nothing + push!(indices, global_ix) + return indices + end +end + +function get_required_initialization_level(sim, device_param_pairs) + return INITIALIZED #TODO -implement check of what type of parameters were changed +end +function make_buffer(a) + buf = Zygote.Buffer(a) + for i in eachindex(a) + buf[i] = a[i] + end + return buf +end + +function make_array(b) + return copy(b) +end + +#TODO - try to go back to making simulation inputs mutable and not using Accessors.jl? +#https://fluxml.ai/Zygote.jl/latest/limitations/#mutable-structs-1 +#https://github.com/FluxML/Zygote.jl/issues/1127 +function set_parameters!(sim, indices, params) + inputs = sim.inputs + parameter_buffer = make_buffer(inputs.parameters) + for (ix, p) in zip(indices, params) + parameter_buffer[ix] = p + end + Accessors.@reset inputs.parameters = make_array(parameter_buffer) + sim.inputs = inputs +end + +function get_parameter_sensitivity_function!(sim, device_param_pairs, f) + indices = get_indices_in_parameter_vector(sim, device_param_pairs) + sim_level = get_required_initialization_level(sim, device_param_pairs) + reset!(sim) + @assert sim.status == BUILT + sim.initialize_level = sim_level + sim.enable_sensitivity = true + sensitivity_function = (p) -> + begin + sim.inputs = deepcopy(sim.inputs_init) + set_parameters!(sim, indices, p) + reset!(sim) + return f(sim) + end + return sensitivity_function +end + +function get_parameter_sensitivity_values(sim, device_param_pairs) + indices = get_indices_in_parameter_vector(sim, device_param_pairs) + param_vector = sim.inputs.parameters + return param_vector[indices] +end diff --git a/src/base/simulation.jl b/src/base/simulation.jl index 2cec48e34..3874ffc1d 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -10,7 +10,6 @@ mutable struct Simulation{T <: SimulationModel} tstops::Vector{Float64} callbacks::Vector simulation_folder::String - build_inputs::Bool inputs::Union{Nothing, SimulationInputs} inputs_init::Union{Nothing, SimulationInputs} results::Union{Nothing, SimulationResults} @@ -18,6 +17,7 @@ mutable struct Simulation{T <: SimulationModel} file_level::Base.CoreLogging.LogLevel multimachine::Bool frequency_reference::Union{ConstantFrequency, ReferenceBus} + enable_sensitivity::Bool end get_system(sim::Simulation) = sim.sys @@ -61,7 +61,6 @@ function Simulation( Vector{Float64}(), Vector{SciMLBase.AbstractDiscreteCallback}(), simulation_folder, - true, nothing, nothing, nothing, @@ -69,6 +68,7 @@ function Simulation( file_level, false, frequency_reference, + false, ) end @@ -144,7 +144,7 @@ function Simulation!( frequency_reference = get(kwargs, :frequency_reference, ReferenceBus()), ) - build!(sim; kwargs...) + build!(sim, Val(sim.enable_sensitivity); kwargs...) if get(kwargs, :system_to_file, false) PSY.to_json(system, joinpath(simulation_folder, "initialized_system.json")) end @@ -201,7 +201,7 @@ function Simulation( file_level = get(kwargs, :file_level, Logging.Info), frequency_reference = get(kwargs, :frequency_reference, ReferenceBus()), ) - build!(sim; kwargs...) + build!(sim, Val(sim.enable_sensitivity); kwargs...) if get(kwargs, :system_to_file, false) PSY.to_json(system, joinpath(simulation_folder, "input_system.json")) end @@ -209,10 +209,10 @@ function Simulation( end function reset!(sim::Simulation{T}) where {T <: SimulationModel} - @info "Rebuilding the simulation after reset" + CRC.@ignore_derivatives @info "Rebuilding the simulation after reset" sim.status = BUILD_INCOMPLETE - build!(sim) - @info "Simulation reset to status $(sim.status)" + build!(sim, Val(sim.enable_sensitivity)) + CRC.@ignore_derivatives @info "Simulation reset to status $(sim.status)" return end @@ -231,7 +231,7 @@ function configure_logging(sim::Simulation, file_mode; kwargs...) ) end -function _build_inputs!(sim::Simulation{T}, ::Val{true}) where {T <: SimulationModel} +function _build_inputs!(sim::Simulation{T}) where {T <: SimulationModel} simulation_system = get_system(sim) sim.inputs = SimulationInputs( T, @@ -243,12 +243,6 @@ function _build_inputs!(sim::Simulation{T}, ::Val{true}) where {T <: SimulationM return end -function _build_inputs!(sim::Simulation{T}, ::Val{false}) where {T <: SimulationModel} - sim.inputs = deepcopy(sim.inputs_init) - @debug "Simulation Inputs Copied" - return -end - function _get_flat_start(inputs::SimulationInputs) bus_count = get_bus_count(inputs) var_count = get_variable_count(inputs) @@ -286,9 +280,9 @@ function _get_jacobian(sim::Simulation{MassMatrixModel}) end function _build_perturbations!(sim::Simulation) - @info "Attaching Perturbations" + CRC.@ignore_derivatives @info "Attaching Perturbations" if isempty(sim.perturbations) - @debug "The simulation has no perturbations" + CRC.@ignore_derivatives @debug "The simulation has no perturbations" return SciMLBase.CallbackSet(), [0.0] end inputs = get_simulation_inputs(sim) @@ -312,7 +306,7 @@ function _add_callback!( sim::Simulation, inputs::SimulationInputs, ) where {T <: Perturbation} - @debug pert + CRC.@ignore_derivatives @debug pert condition = (x, t, integrator) -> t in [pert.time] affect = get_affect(inputs, get_system(sim), pert) callback_vector[ix] = SciMLBase.DiscreteCallback(condition, affect) @@ -324,6 +318,7 @@ function _get_diffeq_problem( sim::Simulation, model::SystemModel{ResidualModel, NoDelays}, jacobian::JacobianFunctionWrapper, + ::Val{false}, ) x0 = get_x0(sim) sim.x0_init = deepcopy(x0) @@ -351,6 +346,32 @@ function _get_diffeq_problem( sim::Simulation, model::SystemModel{MassMatrixModel, NoDelays}, jacobian::JacobianFunctionWrapper, + ::Val{true}, +) + x0 = get_x0(sim) + sim.x0_init = deepcopy(x0) + simulation_inputs = get_simulation_inputs(sim) + p = get_parameters(simulation_inputs) + sim.problem = SciMLBase.ODEProblem( + SciMLBase.ODEFunction{true}( + model; + mass_matrix = get_mass_matrix(simulation_inputs), + # Necessary to avoid unnecessary calculations in Rosenbrock methods + tgrad = (dT, u, p, t) -> dT .= false, + ), + x0, + get_tspan(sim), + p; + ) + sim.status = BUILT + return +end + +function _get_diffeq_problem( + sim::Simulation, + model::SystemModel{MassMatrixModel, NoDelays}, + jacobian::JacobianFunctionWrapper, + ::Val{false}, ) x0 = get_x0(sim) sim.x0_init = deepcopy(x0) @@ -383,6 +404,7 @@ function _get_diffeq_problem( sim::Simulation, model::SystemModel{MassMatrixModel, HasDelays}, jacobian::JacobianFunctionWrapper, + ::Val{false}, ) x0 = get_x0(sim) sim.x0_init = deepcopy(x0) @@ -400,14 +422,76 @@ function _get_diffeq_problem( h, get_tspan(sim), p; - constant_lags = filter!(x -> x != 0, unique(get_delays(simulation_inputs))), + constant_lags = get_constant_lags(simulation_inputs), ) sim.status = BUILT return end -function _build!(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} +function _get_diffeq_problem( + sim::Simulation, + model::SystemModel{MassMatrixModel, HasDelays}, + jacobian::JacobianFunctionWrapper, + ::Val{true}, +) + x0 = get_x0(sim) + sim.x0_init = deepcopy(x0) + simulation_inputs = get_simulation_inputs(sim) + h = get_history_function(sim) + p = get_parameters(simulation_inputs) + sim.problem = SciMLBase.DDEProblem( + SciMLBase.DDEFunction{true}( + model; + mass_matrix = get_mass_matrix(simulation_inputs), + ), + x0, + h, + get_tspan(sim), + p; + constant_lags = get_constant_lags(simulation_inputs), + ) + sim.status = BUILT + + return +end + +#Does not build inputs (enable_sensitivity = true) +function _build!(sim::Simulation{T}, ::Val{true}; kwargs...) where {T <: SimulationModel} + check_kwargs(kwargs, SIMULATION_ACCEPTED_KWARGS, "Simulation") + # Branches are a super set of Lines. Passing both kwargs will + # be redundant. + if get(kwargs, :all_branches_dynamic, false) + sys = get_system(sim) + transform_branches_to_dynamic(sys, PSY.ACBranch) + elseif get(kwargs, :all_lines_dynamic, false) + sys = get_system(sim) + transform_branches_to_dynamic(sys, PSY.Line) + end + sim.multimachine = + get_global_vars_update_pointers(sim.inputs)[GLOBAL_VAR_SYS_FREQ_INDEX] != + 0 + _pre_initialize_simulation!(sim) + if sim.status != BUILD_FAILED + simulation_inputs = get_simulation_inputs(sim) + jacobian = CRC.@ignore_derivatives _get_jacobian(sim) #see MWE; can ignore derivative of Jacobian construction? + model = T(simulation_inputs, get_x0(sim), SimCache) + refine_initial_condition!( + sim, + model, + jacobian, + Val(sim.initialize_level), + ) + CRC.@ignore_derivatives _build_perturbations!(sim) #todo - can we safely ignore derivatives here? + _get_diffeq_problem(sim, model, jacobian, Val(sim.enable_sensitivity)) + CRC.@ignore_derivatives @info "Simulations status = $(sim.status)" + else + CRC.@ignore_derivatives @error "The simulation couldn't be initialized correctly. Simulations status = $(sim.status)" + end + return +end + +function _build!(sim::Simulation{T}, ::Val{false}; kwargs...) where {T <: SimulationModel} check_kwargs(kwargs, SIMULATION_ACCEPTED_KWARGS, "Simulation") # Branches are a super set of Lines. Passing both kwargs will # be redundant. @@ -432,7 +516,7 @@ function _build!(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} end end TimerOutputs.@timeit BUILD_TIMER "Build Simulation Inputs" begin - _build_inputs!(sim, Val(sim.build_inputs)) + _build_inputs!(sim) sim.multimachine = get_global_vars_update_pointers(sim.inputs)[GLOBAL_VAR_SYS_FREQ_INDEX] != 0 @@ -460,7 +544,7 @@ function _build!(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} _build_perturbations!(sim) end TimerOutputs.@timeit BUILD_TIMER "Make DiffEq Problem" begin - _get_diffeq_problem(sim, model, jacobian) + _get_diffeq_problem(sim, model, jacobian, Val(sim.enable_sensitivity)) end @info "Simulations status = $(sim.status)" else @@ -475,10 +559,15 @@ function _build!(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} return end -function build!(sim; kwargs...) +function build!(sim, ::Val{true}; kwargs...) + _build!(sim, Val(sim.enable_sensitivity); kwargs...) + return sim.status +end + +function build!(sim, ::Val{false}; kwargs...) logger = configure_logging(sim, "w") Logging.with_logger(logger) do - _build!(sim; kwargs...) + _build!(sim, Val(sim.enable_sensitivity); kwargs...) #if sim.status == BUILT string_buffer = IOBuffer() TimerOutputs.print_timer( @@ -487,7 +576,7 @@ function build!(sim; kwargs...) sortby = :firstexec, compact = true, ) - @info "\n$(String(take!(string_buffer)))\n" + CRC.@ignore_derivatives @info "\n$(String(take!(string_buffer)))\n" #end end close(logger) @@ -500,10 +589,10 @@ function simulation_pre_step!(sim::Simulation) "The Simulation status is $(sim.status). Can not continue, correct your inputs and build the simulation again.", ) elseif sim.status == BUILT - @debug "Simulation status is $(sim.status)." + CRC.@ignore_derivatives @debug "Simulation status is $(sim.status)." elseif sim.status == SIMULATION_FINALIZED reset!(sim) - @info "The Simulation status is $(sim.status). Resetting the simulation" + CRC.@ignore_derivatives @info "The Simulation status is $(sim.status). Resetting the simulation" else error("Simulation status is $(sim.status). Can't continue.") end @@ -520,7 +609,48 @@ function _filter_kwargs(kwargs) return filter(x -> in(x[1], DIFFEQ_SOLVE_KWARGS), kwargs) end -function _execute!(sim::Simulation, solver; kwargs...) +function _execute!(sim::Simulation, ::Val{true}, solver; kwargs...) + CRC.@ignore_derivatives @debug "status before execute" sim.status + sim.status = SIMULATION_STARTED + time_log = Dict{Symbol, Any}() + if get(kwargs, :auto_abstol, false) + cb = AutoAbstol(true, get(kwargs, :abstol, 1e-9)) + callbacks = SciMLBase.CallbackSet((), tuple(push!(sim.callbacks, cb)...)) + else + callbacks = SciMLBase.CallbackSet((), tuple(sim.callbacks...)) + end + progress_enable = CRC.@ignore_derivatives _prog_meter_enabled() + solution, + time_log[:timed_solve_time], + time_log[:solve_bytes_alloc], + time_log[:sec_in_gc] = @timed SciMLBase.solve( + sim.problem, + solver; + callback = callbacks, + tstops = !isempty(sim.tstops) ? [sim.tstops[1] ÷ 2, sim.tstops...] : [], + progress = get(kwargs, :enable_progress_bar, progress_enable), + progress_steps = 1, + advance_to_tstop = !isempty(sim.tstops), + initializealg = SciMLBase.NoInit(), + _filter_kwargs(kwargs)..., + ) + if SciMLBase.successful_retcode(solution) + sim.status = SIMULATION_FINALIZED + sim.results = SimulationResults( + get_simulation_inputs(sim), + get_system(sim), + time_log, + solution, + ) + else + CRC.@ignore_derivatives @error( + "The simulation failed with return code $(solution.retcode)" + ) + sim.status = SIMULATION_FAILED + end +end + +function _execute!(sim::Simulation, ::Val{false}, solver; kwargs...) @debug "status before execute" sim.status simulation_pre_step!(sim) sim.status = SIMULATION_STARTED @@ -531,7 +661,7 @@ function _execute!(sim::Simulation, solver; kwargs...) else callbacks = SciMLBase.CallbackSet((), tuple(sim.callbacks...)) end - + progress_enable = _prog_meter_enabled() solution, time_log[:timed_solve_time], time_log[:solve_bytes_alloc], @@ -540,7 +670,7 @@ function _execute!(sim::Simulation, solver; kwargs...) solver; callback = callbacks, tstops = !isempty(sim.tstops) ? [sim.tstops[1] ÷ 2, sim.tstops...] : [], - progress = get(kwargs, :enable_progress_bar, _prog_meter_enabled()), + progress = get(kwargs, :enable_progress_bar, progress_enable), progress_steps = 1, advance_to_tstop = !isempty(sim.tstops), initializealg = SciMLBase.NoInit(), @@ -576,12 +706,17 @@ Solves the time-domain dynamic simulation model. - Additional solver keyword arguments can be included. See [Common Solver Options](https://diffeq.sciml.ai/stable/basics/common_solver_opts/) in the `DifferentialEquations.jl` documentation for more details. """ function execute!(sim::Simulation, solver; kwargs...) + __execute!(sim, Val(sim.enable_sensitivity), solver; kwargs...) +end + +function __execute!(sim::Simulation, ::Val{false}, solver; kwargs...) logger = configure_logging(sim, "a"; kwargs...) Logging.with_logger(logger) do try - _execute!(sim, solver; kwargs...) + _execute!(sim, Val(sim.enable_sensitivity), solver; kwargs...) catch e - @error "Execution failed" exception = (e, catch_backtrace()) + CRC.@ignore_derivatives @error "Execution failed" exception = + (e, catch_backtrace()) sim.status = SIMULATION_FAILED end end @@ -589,6 +724,11 @@ function execute!(sim::Simulation, solver; kwargs...) return sim.status end +function __execute!(sim::Simulation, ::Val{true}, solver; kwargs...) + _execute!(sim, Val(sim.enable_sensitivity), solver; kwargs...) + return sim.status +end + function read_results(sim::Simulation) return sim.results end diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index 619544067..3e2faa184 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -5,23 +5,23 @@ function power_flow_solution!( ) res = PF.solve_ac_powerflow!(sys) if !res - @error("PowerFlow failed to solve") + CRC.@ignore_derivatives @error("PowerFlow failed to solve") return BUILD_FAILED end bus_size = length(PSY.get_bus_numbers(sys)) - @debug "Updating bus voltage magnitude and angle to match power flow result" + CRC.@ignore_derivatives @debug "Updating bus voltage magnitude and angle to match power flow result" for bus in PSY.get_components(PSY.Bus, sys) bus_n = PSY.get_number(bus) bus_ix = get_lookup(inputs)[bus_n] initial_guess[bus_ix] = PSY.get_magnitude(bus) * cos(PSY.get_angle(bus)) initial_guess[bus_ix + bus_size] = PSY.get_magnitude(bus) * sin(PSY.get_angle(bus)) - @debug "$(PSY.get_name(bus)) V_r = $(initial_guess[bus_ix]), V_i = $(initial_guess[bus_ix + bus_size])" + CRC.@ignore_derivatives @debug "$(PSY.get_name(bus)) V_r = $(initial_guess[bus_ix]), V_i = $(initial_guess[bus_ix + bus_size])" end return BUILD_INCOMPLETE end function initialize_static_injection!(inputs::SimulationInputs) - @debug "Updating Source internal voltage magnitude and angle" + CRC.@ignore_derivatives @debug "Updating Source internal voltage magnitude and angle" static_injection_devices = get_static_injectors(inputs) parameters = get_parameters(inputs) if !isempty(static_injection_devices) @@ -33,7 +33,8 @@ function initialize_static_injection!(inputs::SimulationInputs) end catch e bt = catch_backtrace() - @error "Static Injection Failed to Initialize" exception = e, bt + CRC.@ignore_derivatives @error "Static Injection Failed to Initialize" exception = + e, bt return BUILD_FAILED end end @@ -57,7 +58,7 @@ function _initialization_debug(dynamic_device, static, x0_device::Vector{Float64 0, ) for (ix, state) in enumerate(PSY.get_states(dynamic_device)) - @debug state residual[ix] + CRC.@ignore_derivatives @debug state residual[ix] end return end @@ -67,12 +68,12 @@ function initialize_dynamic_injection!( inputs::SimulationInputs, system::PSY.System, ) - @debug "Updating Dynamic Injection Component Initial Guess" + CRC.@ignore_derivatives @debug "Updating Dynamic Injection Component Initial Guess" initial_inner_vars = zeros(get_inner_vars_count(inputs)) parameters = get_parameters(inputs) try for dynamic_device in get_dynamic_injectors(inputs) - @debug "Initializing $(PSY.get_name(dynamic_device)) - $(typeof(dynamic_device.device))" + CRC.@ignore_derivatives @debug "Initializing $(PSY.get_name(dynamic_device)) - $(typeof(dynamic_device.device))" _inner_vars = @view initial_inner_vars[get_inner_vars_index(dynamic_device)] _parameters = @view parameters[get_p_range(dynamic_device)] _states = @view initial_guess[get_ix_range(dynamic_device)] @@ -80,7 +81,8 @@ function initialize_dynamic_injection!( end catch e bt = catch_backtrace() - @error "Dynamic Injection Failed to Initialize" exception = e, bt + CRC.@ignore_derivatives @error "Dynamic Injection Failed to Initialize" exception = + e, bt return BUILD_FAILED end return BUILD_INCOMPLETE @@ -92,16 +94,17 @@ function initialize_dynamic_branches!( ) parameters = get_parameters(inputs) try - @debug "Initializing Dynamic Branches" + CRC.@ignore_derivatives @debug "Initializing Dynamic Branches" for br in get_dynamic_branches(inputs) - @debug "$(PSY.get_name(br)) - $(typeof(br))" + CRC.@ignore_derivatives @debug "$(PSY.get_name(br)) - $(typeof(br))" _parameters = @view parameters[get_p_range(br)] _states = @view initial_guess[get_ix_range(br)] initialize_dynamic_device!(br, _parameters, _states) end catch e bt = catch_backtrace() - @error "Dynamic Branches Failed to Initialize" exception = e, bt + CRC.@ignore_derivatives @error "Dynamic Branches Failed to Initialize" exception = + e, bt return BUILD_FAILED end return BUILD_INCOMPLETE @@ -132,7 +135,9 @@ function check_valid_values(initial_guess::Vector{Float64}, inputs::SimulationIn end if !isempty(invalid_initial_guess) - @error("Invalid initial condition values $invalid_initial_guess") + CRC.@ignore_derivatives @error( + "Invalid initial condition values $invalid_initial_guess" + ) return BUILD_FAILED end @@ -142,11 +147,11 @@ end # Default implementation for both models. This implementation is to future proof if there is # a divergence between the required build methods function _calculate_initial_guess!(sim::Simulation, ::Val{POWERFLOW_AND_DEVICES}) - @info("Pre-Initializing Simulation States") + CRC.@ignore_derivatives @info("Pre-Initializing Simulation States") inputs = get_simulation_inputs(sim) @assert sim.status == BUILD_INCOMPLETE while sim.status == BUILD_INCOMPLETE - @debug "Start state intialization routine" + CRC.@ignore_derivatives @debug "Start state intialization routine" TimerOutputs.@timeit BUILD_TIMER "Power Flow solution" begin sim.status = power_flow_solution!(sim.x0, get_system(sim), inputs) end @@ -161,7 +166,7 @@ function _calculate_initial_guess!(sim::Simulation, ::Val{POWERFLOW_AND_DEVICES} sim.status = initialize_dynamic_branches!(sim.x0, inputs) end else - @debug "No Dynamic Branches in the system" + CRC.@ignore_derivatives @debug "No Dynamic Branches in the system" end sim.status = check_valid_values(sim.x0, inputs) end @@ -174,10 +179,10 @@ function _initialize_state_space( ) where {T <: SimulationModel} inputs = get_simulation_inputs(sim) sim.x0 = _get_flat_start(inputs) - @info("Pre-Initializing Simulation States") + CRC.@ignore_derivatives @info("Pre-Initializing Simulation States") @assert sim.status == BUILD_INCOMPLETE while sim.status == BUILD_INCOMPLETE - @debug "Start state intialization routine" + CRC.@ignore_derivatives @debug "Start state intialization routine" TimerOutputs.@timeit BUILD_TIMER "Power Flow solution" begin sim.status = power_flow_solution!(sim.x0, get_system(sim), inputs) end @@ -192,7 +197,7 @@ function _initialize_state_space( sim.status = initialize_dynamic_branches!(sim.x0, inputs) end else - @debug "No Dynamic Branches in the system" + CRC.@ignore_derivatives @debug "No Dynamic Branches in the system" end sim.status = check_valid_values(sim.x0, inputs) end @@ -202,11 +207,11 @@ function _initialize_state_space( sim::Simulation{T}, ::Val{DEVICES_ONLY}, ) where {T <: SimulationModel} - @info("Pre-Initializing Simulation States") + CRC.@ignore_derivatives @info("Pre-Initializing Simulation States") inputs = get_simulation_inputs(sim) @assert sim.status == BUILD_INCOMPLETE while sim.status == BUILD_INCOMPLETE - @debug "Start state intialization routine" + CRC.@ignore_derivatives @debug "Start state intialization routine" TimerOutputs.@timeit BUILD_TIMER "Initialize Static Injectors" begin sim.status = initialize_static_injection!(inputs) end @@ -218,7 +223,7 @@ function _initialize_state_space( sim.status = initialize_dynamic_branches!(sim.x0, inputs) end else - @debug "No Dynamic Branches in the system" + CRC.@ignore_derivatives @debug "No Dynamic Branches in the system" end sim.status = check_valid_values(sim.x0, inputs) end @@ -245,7 +250,9 @@ function _initialize_state_space( ), ) end - @warn("Using existing initial conditions value for simulation initialization") + CRC.@ignore_derivatives @warn( + "Using existing initial conditions value for simulation initialization" + ) sim.x0 = deepcopy(sim.x0_init) sim.status = SIMULATION_INITIALIZED return diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index 2a15e0260..fea32fe1f 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -1,4 +1,4 @@ -mutable struct SimulationInputs +struct SimulationInputs dynamic_injectors::Vector{DynamicWrapper{<:PSY.DynamicInjection}} static_injectors::Vector static_loads::Vector @@ -20,7 +20,7 @@ mutable struct SimulationInputs DAE_vector::Vector{Bool} mass_matrix::LinearAlgebra.Diagonal{Float64} parameters::Vector{Float64} - delays::Vector + constant_lags::Vector end function SimulationInputs( @@ -81,7 +81,7 @@ function SimulationInputs( PSY.get_frequency(sys), ) - delays = get_system_delays(sys) + delays = get_constant_lags(sys) if !isempty(delays) @info "System has delays. Use the correct solver for delay differential equations." end @@ -138,7 +138,7 @@ get_total_shunts(inputs::SimulationInputs) = inputs.total_shunts get_DAE_vector(inputs::SimulationInputs) = inputs.DAE_vector get_mass_matrix(inputs::SimulationInputs) = inputs.mass_matrix get_parameters(inputs::SimulationInputs) = inputs.parameters -get_delays(inputs::SimulationInputs) = inputs.delays +get_constant_lags(inputs::SimulationInputs) = inputs.constant_lags # Utility function not to be used for performance sensitive operations function get_voltage_buses_ix(inputs::SimulationInputs) @@ -245,7 +245,7 @@ function _wrap_dynamic_injector_data( return wrapped_injector, state_count, parameter_count end -function get_system_delays(sys::PSY.System) +function get_constant_lags(sys::PSY.System) delays = [] for injector in get_injectors_with_dynamics(sys) device_delays = get_delays(PSY.get_dynamic_injector(injector)) @@ -253,7 +253,8 @@ function get_system_delays(sys::PSY.System) delays = vcat(delays, device_delays) end end - return delays + return filter!(x -> x != 0, unique(delays)) + end function _wrap_dynamic_branches( diff --git a/src/base/simulation_results.jl b/src/base/simulation_results.jl index 38bf4b5f9..7db94f07f 100644 --- a/src/base/simulation_results.jl +++ b/src/base/simulation_results.jl @@ -37,7 +37,7 @@ global index for a state. """ function _post_proc_state_series(solution, ix::Int, dt::Nothing) - ix_t = unique(i -> solution.t[i], eachindex(solution.t)) + ix_t = CRC.@ignore_derivatives unique(i -> solution.t[i], eachindex(solution.t)) ts = solution.t[ix_t] state = solution[ix, ix_t] return ts, state @@ -65,7 +65,7 @@ function post_proc_state_series( ) global_state_index = get_global_index(res) if !haskey(global_state_index, ref[1]) - @error "$(keys(global_state_index))" + CRC.@ignore_derivatives @error "$(keys(global_state_index))" error("State $(ref[2]) device $(ref[1]) not found in the system. ") end ix = get(global_state_index[ref[1]], ref[2], 0) diff --git a/src/base/small_signal.jl b/src/base/small_signal.jl index 80716ba53..e8d322e82 100644 --- a/src/base/small_signal.jl +++ b/src/base/small_signal.jl @@ -170,7 +170,7 @@ Returns the Small Signal Output object that contains the eigenvalues and partici """ function small_signal_analysis(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} inputs = get_simulation_inputs(sim) - if !(isempty(get_delays(inputs))) + if !(isempty(get_constant_lags(inputs))) return error("Small signal analysis not compatible with system model with delays") end x_eval = get(kwargs, :operating_point, get_x0(sim)) diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index 00050542e..e53c5178d 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -72,7 +72,9 @@ function initialize_avr!( x0 = [1.0, Vf0, Vf0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization of AVR in $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization of AVR in $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update V_ref @@ -138,7 +140,9 @@ function initialize_avr!( x0 = [1.0, Vf0, Vf0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization of AVR in $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization of AVR in $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update V_ref @@ -154,7 +158,9 @@ function initialize_avr!( y_ll1, _ = lead_lag(sol_x0[1] - Vm, sol_x0[2], K0, T2, T1) y_ll2, _ = lead_lag(y_ll1, K0 * sol_x0[3], 1.0, K0 * T4, K0 * T3) if (y_ll2 > Va_max) || (y_ll2 < Va_min) - @error("Regulator Voltage V_r = $(y_ll2) outside the limits") + CRC.@ignore_derivatives @error( + "Regulator Voltage V_r = $(y_ll2) outside the limits" + ) end end return @@ -208,7 +214,9 @@ function initialize_avr!( x0 = [1.0] sol = NLsolve.nlsolve(f_Ve!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization of AVR in $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization of AVR in $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero V_e0 = sol_x0[1] @@ -218,7 +226,9 @@ function initialize_avr!( V_FE0 = Kd * Xad_Ifd0 + Ke * V_e0 + Se0 * V_e0 V_r20 = V_FE0 if (V_r20 > Vr_max) || (V_r20 < Vr_min) - @error("Regulator Voltage V_R = $(V_r20) outside the limits") + CRC.@ignore_derivatives @error( + "Regulator Voltage V_R = $(V_r20) outside the limits" + ) end Tc_Tb_ratio = Tb <= eps() ? 0.0 : Tc / Tb V_r30 = -(Kf / Tf) * V_FE0 @@ -253,7 +263,9 @@ function initialize_avr!( x0 = [V_ref0, V_r10, V_r20, V_e0, V_r30] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization of AVR in $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization of AVR in $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update V_ref @@ -303,12 +315,14 @@ function initialize_avr!( x0 = [1.0, Vf0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization of AVR in $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization of AVR in $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero if (sol_x0[2] >= V_max + BOUNDS_TOLERANCE) || (sol_x0[2] <= V_min - BOUNDS_TOLERANCE) - @error( + CRC.@ignore_derivatives @error( "Vr limits for AVR in $(PSY.get_name(dynamic_device)) (Vr = $(sol_x0[2])), outside its limits V_max = $V_max, Vmin = $V_min. Consider updating the operating point." ) end @@ -386,13 +400,15 @@ function initialize_avr!( x0 = [1.0, Vf0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization of AVR in $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization of AVR in $(PSY.get_name(static)) failed" + ) else # if converge sol_x0 = sol.zero Vr2_0 = (sol_x0[2] + Ta_Tb * (sol_x0[1] - Vm)) * K # K * V_LL #check the limits if (Vr2_0 >= V_max + BOUNDS_TOLERANCE) || (Vr2_0 <= V_min - BOUNDS_TOLERANCE) - @error( + CRC.@ignore_derivatives @error( "Vr limits for AVR in $(PSY.get_name(dynamic_device)) (Vr = $(sol_x0[2])), outside its limits V_max = $V_max, Vmin = $V_min. Consider updating the operating point." ) end @@ -440,7 +456,7 @@ function initialize_avr!( # Check limits to field voltage if (Vt * Vr_min - Kc * Ifd > Vf0) || (Vf0 > Vt * Vr_max - Kc * Ifd) - @error( + CRC.@ignore_derivatives @error( "Field Voltage for AVR in $(PSY.get_name(dynamic_device)) is $(Vf0) pu, which is outside its limits. Consider updating the operating point." ) end @@ -506,7 +522,9 @@ function initialize_avr!( x0 = [10.0] # initial guess for Ve sol = NLsolve.nlsolve(f_Ve!, x0) if !NLsolve.converged(sol) - @warn("Initialization of AVR in $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization of AVR in $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero Ve = sol_x0[1] @@ -516,7 +534,7 @@ function initialize_avr!( VFE = Kd * Ifd0 + Ke * Ve + Se * Ve Vr2 = VFE if (Vr2 > Vr_max) || (Vr2 < Vr_min) - @error("Regulator Voltage V_R = $(Vr2) outside the limits") + CRC.@ignore_derivatives @error("Regulator Voltage V_R = $(Vr2) outside the limits") end Vr3 = -(Kf / Tf) * VFE Tc_Tb_ratio = Tb <= eps() ? 0.0 : Tc / Tb @@ -571,7 +589,7 @@ function initialize_avr!( # Check limits to field voltage if (Vt * Vr_min > Vf0) || (Vf0 > Vt * Vr_max - Kc * Ifd) - @error( + CRC.@ignore_derivatives @error( "Field Voltage for AVR in $(PSY.get_name(dynamic_device)) is $(Vf0) pu, which is outside its limits. Consider updating the operating point." ) end diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index 2f8bbdb47..3ed0b5c78 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -47,7 +47,9 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Machine $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update terminal voltages @@ -124,7 +126,9 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Machine $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update terminal voltages @@ -226,7 +230,9 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[1], V_dq0[2], V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Machine $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update terminal voltages @@ -322,7 +328,9 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[1], V_dq0[2], V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Machine $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update terminal voltages @@ -428,7 +436,9 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Machine $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update terminal voltages @@ -532,7 +542,9 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[1], V_dq0[2], V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Machine $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update terminal voltages @@ -632,7 +644,9 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Machine $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update terminal voltages @@ -784,7 +798,9 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, Vf0, eq_p0, ed_p0, ψ_kd0, ψ_kq0, Xad_Ifd0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Machine $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update terminal voltages @@ -910,7 +926,9 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, Vf0, eq_p0, ψ_kd0, ψq_pp0, Xad_Ifd0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Machine $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update terminal voltages @@ -1047,7 +1065,9 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, Vf0, eq_p0, ψ_kd0, ψq_pp0, Xad_Ifd0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Machine $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update terminal voltages @@ -1144,7 +1164,7 @@ static::PSY.StaticInjection, x0 = [δ0, τm0, 1.0, V_dq0[2], -V_dq0[1], 1.0, 0.0, 0.0] sol = NLsolve.nlsolve(f!, x0) if !NLsolve.converged(sol) - @warn("Initialization in Machine $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn("Initialization in Machine $(PSY.get_name(static)) failed") else sol_x0 = sol.zero #Update terminal voltages diff --git a/src/initialization/generator_components/init_shaft.jl b/src/initialization/generator_components/init_shaft.jl index 56f62b7c8..261eab6ec 100644 --- a/src/initialization/generator_components/init_shaft.jl +++ b/src/initialization/generator_components/init_shaft.jl @@ -82,7 +82,7 @@ function initialize_shaft!( x0 = [τm0, δ0, δ0, δ0, δ0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Shaft failed") + CRC.@ignore_derivatives @warn("Initialization in Shaft failed") else sol_x0 = sol.zero inner_vars[τm_var] = sol_x0[1] #τm diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index d60599ff8..4cb87447c 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -61,7 +61,9 @@ function initialize_tg!( ] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization of Turbine Governor $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization of Turbine Governor $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update Control Refs @@ -71,7 +73,7 @@ function initialize_tg!( tg_ix = get_local_state_ix(dynamic_device, PSY.TGTypeI) tg_states = @view device_states[tg_ix] if (sol_x0[2] > V_max) || (sol_x0[2] < V_min) - @error( + CRC.@ignore_derivatives @error( "Valve limits for TG in $(PSY.get_name(dynamic_device)) (x_g1 = $(sol_x0[2])), outside its limits V_max = $V_max, Vmin = $V_min. Consider updating the operating point." ) end @@ -110,7 +112,9 @@ function initialize_tg!( x0 = [τm0, 0.0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization of Turbine Governor $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization of Turbine Governor $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update Control Refs @@ -159,7 +163,9 @@ function initialize_tg!( x0 = [1.0 / inv_R, τm0, τm0, τm0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @error("Initialization of Turbine Governor $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @error( + "Initialization of Turbine Governor $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Update Control Refs @@ -239,12 +245,12 @@ function initialize_tg!( x0 = [1.0 / inv_R, τm0, τm0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in TG failed") + CRC.@ignore_derivatives @warn("Initialization in TG failed") else sol_x0 = sol.zero if (sol_x0[2] >= V_max + BOUNDS_TOLERANCE) || (sol_x0[2] <= V_min - BOUNDS_TOLERANCE) - @error( + CRC.@ignore_derivatives @error( "Valve limits for TG in $(PSY.get_name(dynamic_device)) (x_g1 = $(sol_x0[2])), outside its limits V_max = $V_max, Vmin = $V_min. Consider updating the operating point." ) end @@ -310,7 +316,9 @@ function initialize_tg!( x0 = [P0, 0, (r * Tr) * P0 / R, P0 / R, P0 / R] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization of Turbine Governor $(PSY.get_name(static)) failed") + CRC.@ignore_derivatives @warn( + "Initialization of Turbine Governor $(PSY.get_name(static)) failed" + ) else sol_x0 = sol.zero #Error if x_g3 is outside PI limits diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index 58af1a62c..38e026622 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -87,7 +87,7 @@ function initialize_static_device!( x0 = [V_R, V_I] sol = NLsolve.nlsolve(f!, x0) if !NLsolve.converged(sol) - @warn("Initialization in Source failed") + CRC.@ignore_derivatives @warn("Initialization in Source failed") else sol_x0 = sol.zero #Update terminal voltages @@ -135,7 +135,7 @@ function initialize_dynamic_device!( x0 = [V_R, V_I] sol = NLsolve.nlsolve(f!, x0) if !NLsolve.converged(sol) - @warn("Initialization in Periodic Variable Source failed") + CRC.@ignore_derivatives @warn("Initialization in Periodic Variable Source failed") else sol_x0 = sol.zero #Update terminal voltages @@ -281,7 +281,9 @@ function initialize_dynamic_device!( end sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Ind. Motor $(PSY.get_name(device)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Ind. Motor $(PSY.get_name(device)) failed" + ) else sol_x0 = sol.zero device_states[1] = sol_x0[4] # ψ_qs @@ -395,7 +397,9 @@ function initialize_dynamic_device!( end sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Ind. Motor $(PSY.get_name(device)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Ind. Motor $(PSY.get_name(device)) failed" + ) else sol_x0 = sol.zero device_states[1] = sol_x0[8] # ψ_qr @@ -458,11 +462,11 @@ function initialize_dynamic_device!( vr2 = thy if (thy > Vmax) || (thy < Vmin) - @error("Thyristor state thy = $(thy) outside the limits") + CRC.@ignore_derivatives @error("Thyristor state thy = $(thy) outside the limits") end if (vr2 > 1) || (vr2 < Rmin / Rbase) - @error("Regulator state vr2 = $(vr2) outside the limits") + CRC.@ignore_derivatives @error("Regulator state vr2 = $(vr2) outside the limits") end device_states[1] = K * (V_abs - V_ref0) # thy @@ -563,7 +567,9 @@ function initialize_dynamic_device!( end sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Active Load $(PSY.get_name(device)) failed") + CRC.@ignore_derivatives @warn( + "Initialization in Active Load $(PSY.get_name(device)) failed" + ) else sol_x0 = sol.zero device_states[1] = sol_x0[1] # θ_pll @@ -619,13 +625,13 @@ function initialize_dynamic_device!( Iq_cmd = Iq / Mult Ip_min, Ip_max, Iq_min, Iq_max = current_limit_logic(dynamic_device, Ip_cmd, Iq_cmd) if Ip_cmd >= Ip_max + BOUNDS_TOLERANCE || Ip_min - BOUNDS_TOLERANCE >= Ip_cmd - @error( + CRC.@ignore_derivatives @error( "Inverter $(PSY.get_name(static)) active current $(Ip_cmd) out of limits $(Ip_min) $(Ip_max). Check Power Flow or Parameters" ) end if Iq_cmd >= Iq_max + BOUNDS_TOLERANCE || Iq_min - BOUNDS_TOLERANCE >= Iq_cmd - @error( + CRC.@ignore_derivatives @error( "Inverter $(PSY.get_name(static)) reactive current $(Iq_cmd) out of limits $(Iq_min) $(Iq_max). Check Power Flow or Parameters" ) end @@ -660,7 +666,7 @@ function initialize_dynamic_device!( device_states[9] = Pord device_states[10] = Ip else - @error "Unsupported value of Freq_Flag" + CRC.@ignore_derivatives @error "Unsupported value of Freq_Flag" end #See Note 2 on PSSE Documentation diff --git a/src/initialization/inverter_components/init_converter.jl b/src/initialization/inverter_components/init_converter.jl index e276ffadb..c9a20a3e3 100644 --- a/src/initialization/inverter_components/init_converter.jl +++ b/src/initialization/inverter_components/init_converter.jl @@ -72,7 +72,7 @@ function initialize_converter!( _, Lv_pnt1 = PSY.get_Lv_pnts(converter) if (Iq < Io_lim) || (V_t > Vo_lim) || (V_t < Lv_pnt1) - @error( + CRC.@ignore_derivatives @error( "Power flow solution outside of inverter limits $(PSY.get_name(static)). Update parameters." ) end @@ -125,7 +125,7 @@ function initialize_converter!( _, Lv_pnt1 = PSY.get_Lv_pnts(converter) if (Iq < Io_lim) || (V_t > Vo_lim) || (V_t < Lv_pnt1) - @error( + CRC.@ignore_derivatives @error( "Power flow solution outside of inverter limits $(PSY.get_name(static)). Update parameters." ) end diff --git a/src/initialization/inverter_components/init_filter.jl b/src/initialization/inverter_components/init_filter.jl index c15cc6725..ca2b90b8e 100644 --- a/src/initialization/inverter_components/init_filter.jl +++ b/src/initialization/inverter_components/init_filter.jl @@ -58,7 +58,9 @@ function initialize_filter!( x0 = [V_R, V_I, Ir_filter, Ii_filter, V_R, V_I] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Filter failed $(PSY.get_name(static))") + CRC.@ignore_derivatives @warn( + "Initialization in Filter failed $(PSY.get_name(static))" + ) else sol_x0 = sol.zero #Update terminal voltages diff --git a/src/initialization/inverter_components/init_frequency_estimator.jl b/src/initialization/inverter_components/init_frequency_estimator.jl index adca14c22..e23d7f2cd 100644 --- a/src/initialization/inverter_components/init_frequency_estimator.jl +++ b/src/initialization/inverter_components/init_frequency_estimator.jl @@ -45,7 +45,7 @@ function initialize_frequency_estimator!( x0 = [Vpll_d0, Vpll_q0, ϵ_pll0, θ0_pll] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in PLL failed") + CRC.@ignore_derivatives @warn("Initialization in PLL failed") else sol_x0 = sol.zero @@ -109,7 +109,7 @@ function initialize_frequency_estimator!( x0 = [Vpll_q0, ϵ_pll0, θ0_pll] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in PLL failed") + CRC.@ignore_derivatives @warn("Initialization in PLL failed") else sol_x0 = sol.zero diff --git a/src/initialization/inverter_components/init_inner.jl b/src/initialization/inverter_components/init_inner.jl index a80419f3a..08e6b582f 100644 --- a/src/initialization/inverter_components/init_inner.jl +++ b/src/initialization/inverter_components/init_inner.jl @@ -99,7 +99,7 @@ function initialize_inner!( x0 = [θ0_oc, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Inner Control failed") + CRC.@ignore_derivatives @warn("Initialization in Inner Control failed") else sol_x0 = sol.zero #Update angle: @@ -207,7 +207,7 @@ function initialize_inner!( x0 = [0.0, 0.0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - @warn("Initialization in Inner Control failed") + CRC.@ignore_derivatives @warn("Initialization in Inner Control failed") else sol_x0 = sol.zero #Update Converter modulation @@ -270,13 +270,13 @@ function initialize_inner!( current_limit_logic(inner_control, Val(PQ_Flag), V_t, Ip_oc, Iq_cmd) if Ip_oc >= Ip_max + BOUNDS_TOLERANCE || Ip_min - BOUNDS_TOLERANCE >= Ip_oc - @error( + CRC.@ignore_derivatives @error( "Inverter $(PSY.get_name(static)) active current $(Ip_oc) out of limits $(Ip_min) $(Ip_max). Check Power Flow or Parameters" ) end if Iq_oc >= Iq_max + BOUNDS_TOLERANCE || Iq_min - BOUNDS_TOLERANCE >= Iq_oc - @error( + CRC.@ignore_derivatives @error( "Inverter $(PSY.get_name(static)) reactive current $(Iq_oc) out of limits $(Iq_min) $(Iq_max). Check Power Flow or Parameters" ) end diff --git a/src/models/branch.jl b/src/models/branch.jl index f1b13dbf5..e6770fda2 100644 --- a/src/models/branch.jl +++ b/src/models/branch.jl @@ -1,5 +1,5 @@ function branch!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r_from::T, @@ -32,7 +32,7 @@ function branch!( end function branch!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r_from::T, diff --git a/src/models/device.jl b/src/models/device.jl index 0ccb902f0..737317764 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -16,7 +16,7 @@ function device_mass_matrix_entries!( end function device!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, @@ -182,7 +182,7 @@ function device_mass_matrix_entries!( end function device!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, @@ -310,11 +310,11 @@ function mass_matrix_pvs_entries!( pvs::DynamicWrapper{PSY.PeriodicVariableSource}, global_index::ImmutableDict{Symbol, Int64}, ) - @debug "Using default mass matrix entries $pvs" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $pvs" end function device!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, @@ -783,7 +783,7 @@ function mass_matrix_induction_entries!( ) where { T <: Union{PSY.SingleCageInductionMachine, PSY.SimplifiedSingleCageInductionMachine}, } - @debug "Using default mass matrix entries $ind" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $ind" end """ @@ -792,7 +792,7 @@ Refer to "Analysis of Electric Machinery and Drive Systems" by Paul Krause, Oleg Wasynczuk and Scott Sudhoff for the equations """ function device!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, @@ -881,7 +881,7 @@ equations in "Analysis of Electric Machinery and Drive Systems" by Paul Krause, Oleg Wasynczuk and Scott Sudhoff. """ function device!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, @@ -978,14 +978,14 @@ function mass_matrix_csvgn1_entries!( csvgn1::DynamicWrapper{PSY.CSVGN1}, global_index::ImmutableDict{Symbol, Int64}, ) - @debug "Using default mass matrix entries $csvgn1" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $csvgn1" end """ Model of Static Shunt Compensator: CSVGN1. """ function device!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, @@ -1100,7 +1100,7 @@ Based on the paper `Malicious Control of an Active Load in an Islanded Mixed-Sou by C. Roberts, U. Markovic, D. Arnold and D. Callaway. """ function device!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, @@ -1249,7 +1249,7 @@ function mass_matrix_dera_entries!( end function device!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, @@ -1286,7 +1286,7 @@ end #Freq_Flag = 0 function _mdl_ode_AggregateDistributedGenerationA!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::Val{0}, @@ -1370,7 +1370,7 @@ function _mdl_ode_AggregateDistributedGenerationA!( elseif Pf_Flag == 0 _, dQ_V_dt = low_pass_mass_matrix(Q_ref / max(Vmeas, 0.01), Q_V, 1.0, T_iq) else - @error @error "Unsupported value of PQ_Flag" + CRC.@ignore_derivatives @error "Unsupported value of PQ_Flag" end #STATE Iq @@ -1431,7 +1431,7 @@ end #Freq_Flag = 1 function _mdl_ode_AggregateDistributedGenerationA!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::Val{1}, @@ -1519,7 +1519,7 @@ function _mdl_ode_AggregateDistributedGenerationA!( elseif Pf_Flag == 0 _, dQ_V_dt = low_pass_mass_matrix(Q_ref / max(Vmeas, 0.01), Q_V, 1.0, T_iq) else - @error "Unsupported value of PQ_Flag" + CRC.@ignore_derivatives @error "Unsupported value of PQ_Flag" end #STATE Iq diff --git a/src/models/dynline_model.jl b/src/models/dynline_model.jl index ae0cfd883..4270cc687 100644 --- a/src/models/dynline_model.jl +++ b/src/models/dynline_model.jl @@ -1,5 +1,5 @@ function mdl_branch_ode!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r_from::T, @@ -28,7 +28,7 @@ function mdl_branch_ode!( end function mdl_transformer_Lshape_ode!( - device_states::AbstractArray{T}, + device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r_from::T, diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index 6cd742212..6b5eab612 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -3,7 +3,7 @@ function mass_matrix_avr_entries!( avr::T, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {T <: PSY.AVR} - @debug "Using default mass matrix entries $T" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $T" return end diff --git a/src/models/generator_models/machine_models.jl b/src/models/generator_models/machine_models.jl index 96d07c135..4532a8fba 100644 --- a/src/models/generator_models/machine_models.jl +++ b/src/models/generator_models/machine_models.jl @@ -3,7 +3,7 @@ function mass_matrix_machine_entries!( machine::M, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {M <: PSY.Machine} - @debug "Using default mass matrix entries $M" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $M" end """ diff --git a/src/models/generator_models/pss_models.jl b/src/models/generator_models/pss_models.jl index 981abf53d..018facbc8 100644 --- a/src/models/generator_models/pss_models.jl +++ b/src/models/generator_models/pss_models.jl @@ -3,7 +3,7 @@ function mass_matrix_pss_entries!( ::P, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {P <: PSY.PSS} - @debug "Using default mass matrix entries $P" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $P" end function mass_matrix_pss_entries!( diff --git a/src/models/generator_models/shaft_models.jl b/src/models/generator_models/shaft_models.jl index 6a6b2c621..8e5ad581e 100644 --- a/src/models/generator_models/shaft_models.jl +++ b/src/models/generator_models/shaft_models.jl @@ -3,7 +3,7 @@ function mass_matrix_shaft_entries!( shaft::S, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {S <: PSY.Shaft} - @debug "Using default mass matrix entries $S" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $S" end function mdl_shaft_ode!( diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index 241ea02b1..fb059af7e 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -3,7 +3,7 @@ function mass_matrix_tg_entries!( tg::TG, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {TG <: PSY.TurbineGov} - @debug "Using default mass matrix entries $TG" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $TG" end function mass_matrix_tg_entries!( diff --git a/src/models/inverter_models/DCside_models.jl b/src/models/inverter_models/DCside_models.jl index da090c63a..60c89f42c 100644 --- a/src/models/inverter_models/DCside_models.jl +++ b/src/models/inverter_models/DCside_models.jl @@ -3,7 +3,7 @@ function mass_matrix_DCside_entries!( dc_side::DC, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {DC <: PSY.DCSource} - @debug "Using default mass matrix entries $DC" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $DC" end function mdl_DCside_ode!( diff --git a/src/models/inverter_models/converter_models.jl b/src/models/inverter_models/converter_models.jl index 3e60271bb..40bc4aa9f 100644 --- a/src/models/inverter_models/converter_models.jl +++ b/src/models/inverter_models/converter_models.jl @@ -3,7 +3,7 @@ function mass_matrix_converter_entries!( converter::C, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {C <: PSY.Converter} - @debug "Using default mass matrix entries $C" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $C" end function mdl_converter_ode!( diff --git a/src/models/inverter_models/filter_models.jl b/src/models/inverter_models/filter_models.jl index b93ee80ae..0d4aa940f 100644 --- a/src/models/inverter_models/filter_models.jl +++ b/src/models/inverter_models/filter_models.jl @@ -4,7 +4,7 @@ function mass_matrix_filter_entries!( global_index::Base.ImmutableDict{Symbol, Int64}, f0::Float64, ) where {F <: PSY.Filter} - @debug "Using default mass matrix entries $F" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $F" return end diff --git a/src/models/inverter_models/frequency_estimator_models.jl b/src/models/inverter_models/frequency_estimator_models.jl index d385051e7..0cc30a2a3 100644 --- a/src/models/inverter_models/frequency_estimator_models.jl +++ b/src/models/inverter_models/frequency_estimator_models.jl @@ -3,7 +3,7 @@ function mass_matrix_freq_estimator_entries!( freq_estimator::P, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {P <: PSY.FrequencyEstimator} - @debug "Using default mass matrix entries $P" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $P" end function mdl_freq_estimator_ode!( diff --git a/src/models/inverter_models/inner_control_models.jl b/src/models/inverter_models/inner_control_models.jl index 26f786e22..ccdf650cc 100644 --- a/src/models/inverter_models/inner_control_models.jl +++ b/src/models/inverter_models/inner_control_models.jl @@ -3,7 +3,7 @@ function mass_matrix_inner_entries!( inner_control::IC, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {IC <: PSY.InnerControl} - @debug "Using default mass matrix entries $IC" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $IC" return end diff --git a/src/models/inverter_models/outer_control_models.jl b/src/models/inverter_models/outer_control_models.jl index 2a5230dbe..828ff711d 100644 --- a/src/models/inverter_models/outer_control_models.jl +++ b/src/models/inverter_models/outer_control_models.jl @@ -3,7 +3,7 @@ function mass_matrix_outer_entries!( outer_control::O, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {O <: PSY.OuterControl} - @debug "Using default mass matrix entries $O" + CRC.@ignore_derivatives @debug "Using default mass matrix entries $O" end ##################################################### diff --git a/src/models/network_model.jl b/src/models/network_model.jl index 640038990..fd26a8aad 100644 --- a/src/models/network_model.jl +++ b/src/models/network_model.jl @@ -1,7 +1,7 @@ function network_model( inputs::SimulationInputs, I_balance::AbstractArray{T}, - voltages::AbstractArray{T}, + voltages::AbstractArray{<:ACCEPTED_REAL_TYPES}, ) where {T <: ACCEPTED_REAL_TYPES} # This operation might need improvement, when the total shunts aren't added the # function is not allocating diff --git a/src/models/saturation_models.jl b/src/models/saturation_models.jl index 6e6d3ff28..0a7cef89e 100644 --- a/src/models/saturation_models.jl +++ b/src/models/saturation_models.jl @@ -176,14 +176,14 @@ function current_limit_logic( Ip_max = I_max end else - @error "Unsupported value of PQ_Flag" + CRC.@ignore_derivatives @error "Unsupported value of PQ_Flag" end if Gen_Flag == 1 Ip_min = 0 elseif Gen_Flag == 0 Ip_min = -Ip_max else - @error "Unsupported value of Gen_Flag" + CRC.@ignore_derivatives @error "Unsupported value of Gen_Flag" end Iq_min = -Iq_max return Ip_min, Ip_max, Iq_min, Iq_max diff --git a/src/models/system.jl b/src/models/system.jl index 3d88082ae..01609aba7 100644 --- a/src/models/system.jl +++ b/src/models/system.jl @@ -11,7 +11,7 @@ function ResidualModel( T, ForwardDiff.pickchunksize(length(x0_init)), } - if isempty(get_delays(inputs)) + if isempty(get_constant_lags(inputs)) return SystemModel{ResidualModel, NoDelays}( inputs, Ctype{U}(system_residual!, inputs), @@ -27,7 +27,7 @@ end Instantiate an ResidualModel for ODE inputs. """ function ResidualModel(inputs, ::Vector{Float64}, ::Type{Ctype}) where {Ctype <: SimCache} - if isempty(get_delays(inputs)) + if isempty(get_constant_lags(inputs)) return SystemModel{ResidualModel, NoDelays}(inputs, Ctype(system_residual!, inputs)) else error( @@ -186,7 +186,7 @@ end Instantiate a MassMatrixModel for ODE inputs. """ function MassMatrixModel(inputs, ::Vector{Float64}, ::Type{Ctype}) where {Ctype <: SimCache} - if isempty(get_delays(inputs)) + if isempty(get_constant_lags(inputs)) return SystemModel{MassMatrixModel, NoDelays}( inputs, Ctype(system_mass_matrix!, inputs), @@ -212,7 +212,7 @@ function MassMatrixModel( T, ForwardDiff.pickchunksize(length(x0_init)), } - if isempty(get_delays(inputs)) + if isempty(get_constant_lags(inputs)) return SystemModel{MassMatrixModel, NoDelays}( inputs, Ctype{U}(system_mass_matrix!, inputs), diff --git a/src/post_processing/post_proc_generator.jl b/src/post_processing/post_proc_generator.jl index 1f25258dd..1f3cfb26c 100644 --- a/src/post_processing/post_proc_generator.jl +++ b/src/post_processing/post_proc_generator.jl @@ -528,7 +528,9 @@ function _field_current( res::SimulationResults, dt::Union{Nothing, Float64, Vector{Float64}}, ) where {M <: PSY.Machine} - @warn("Field current is not supported in the machine type $(M). Returning zeros.") + CRC.@ignore_derivatives @warn( + "Field current is not supported in the machine type $(M). Returning zeros." + ) ts, _ = post_proc_state_series(res, (name, :δ), dt) I_fd = zeros(length(ts)) return ts, I_fd diff --git a/src/post_processing/post_proc_inverter.jl b/src/post_processing/post_proc_inverter.jl index 6c53b37ae..94cf9cf82 100644 --- a/src/post_processing/post_proc_inverter.jl +++ b/src/post_processing/post_proc_inverter.jl @@ -45,7 +45,9 @@ function compute_field_current( V_I::Vector{Float64}, dt::Union{Nothing, Float64, Vector{Float64}}, ) where {G <: PSY.DynamicInverter} - @warn("Field current does not exist in inverters. Returning zeros.") + CRC.@ignore_derivatives @warn( + "Field current does not exist in inverters. Returning zeros." + ) return (nothing, zeros(length(V_R))) end @@ -59,7 +61,9 @@ function compute_field_voltage( dynamic_device::G, dt::Union{Nothing, Float64, Vector{Float64}}, ) where {G <: PSY.DynamicInverter} - @warn("Field voltage does not exist in inverters. Returning zeros.") + CRC.@ignore_derivatives @warn( + "Field voltage does not exist in inverters. Returning zeros." + ) _, state = _post_proc_state_series(res.solution, 1, dt) return (nothing, zeros(length(state))) end @@ -74,7 +78,9 @@ function compute_mechanical_torque( dynamic_device::G, dt::Union{Nothing, Float64, Vector{Float64}}, ) where {G <: PSY.DynamicInverter} - @warn("Mechanical torque is not used in inverters. Returning zeros.") + CRC.@ignore_derivatives @warn( + "Mechanical torque is not used in inverters. Returning zeros." + ) _, state = _post_proc_state_series(res.solution, 1, dt) return (nothing, zeros(length(state))) end diff --git a/src/utils/psy_utils.jl b/src/utils/psy_utils.jl index 36a8fd9ca..08dde1b89 100644 --- a/src/utils/psy_utils.jl +++ b/src/utils/psy_utils.jl @@ -33,13 +33,6 @@ function get_dynamic_branches(sys::PSY.System) return PSY.get_components(x -> PSY.get_available(x), PSY.DynamicBranch, sys) end -function _transform_all_lines!(sys::PSY.System) - for br in PSY.get_components(PSY.DynamicBranch, sys) - dyn_br = DynamicBranch(br) - @debug "Converted $(PSY.get_name(dyn_br)) to DynamicBranch" - add_component!(sys, dyn_br) - end -end function transform_ybus_to_rectangular( ybus::SparseArrays.SparseMatrixCSC{Complex{Float64}, Int}, diff --git a/test/runtests.jl b/test/runtests.jl index 76b8cf297..48bc51dbd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -14,6 +14,10 @@ using PowerFlows using PowerNetworkMatrices import LinearAlgebra using Logging +using SciMLSensitivity +using Zygote +using Optimization +using OptimizationOptimisers import Aqua Aqua.test_unbound_args(PowerSimulationsDynamics) diff --git a/test/test_base.jl b/test/test_base.jl index 923c3b1c3..d1849ea7c 100644 --- a/test/test_base.jl +++ b/test/test_base.jl @@ -812,7 +812,7 @@ end ) end -@testset "Test Build and Initialize Levels" begin +@testset "Test Initialize Levels" begin path = mktempdir() try #Compute Y_bus after fault @@ -840,16 +840,6 @@ end results_original = read_results(sim) series_original = get_state_series(results_original, ("generator-102-1", :δ); dt = 0.01) - for build_inputs in - [true, false] - sim.build_inputs = build_inputs - @test execute!(sim, IDA(); dtmax = 0.005, saveat = 0.005) == - PSID.SIMULATION_FINALIZED - results = read_results(sim) - series = get_state_series(results, ("generator-102-1", :δ); dt = 0.01) - @test series == series_original - end - sim.build_inputs = true for initialize_level in [PSID.POWERFLOW_AND_DEVICES, PSID.INITIALIZED, PSID.DEVICES_ONLY] sim.initialize_level = initialize_level diff --git a/test/test_case_sensitivity.jl b/test/test_case_sensitivity.jl new file mode 100644 index 000000000..d747b0891 --- /dev/null +++ b/test/test_case_sensitivity.jl @@ -0,0 +1,303 @@ + +""" +Case 1: +This case study defines a classical machine against an infinite bus. Sensitivitiy +Analysis is performed for the inertia of the generator. The fault is a change in the +source voltage. +""" +################################################## +############### LOAD DATA ###################### ## +################################################## + +omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + +################################################## +############### SOLVE PROBLEM #################### +################################################## + +s_device = get_component(Source, omib_sys, "InfBus") +s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) +#using PlotlyJS #for debug only + + +#NOTES ON SENSITIVITY ALGORITHMS FROM SCIMLSENSITIVITY +#ReverseDiffVJP and EnzymeVJP only options compatible with Hybrid DEs (DEs with callbacks) +#BacksolveAdjoint prone to instabilities whenever the Lipschitz constant is sufficiently large (stiff equations, PDE discretizations, and many other contexts) +#For ForwardDiffSensitivity, convert_tspan=true is needed for hybrid equations. +@testset "Test Gradients - Mass Matrix no delays" begin + path = mktempdir() + try + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + H_gt = + get_H(get_shaft(get_component(DynamicGenerator, omib_sys, "generator-102-1"))) + execute!(sim, Rodas5(); dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + for solver in [FBDF(), Rodas5(), QNDF()] + for tol in [1e-6, 1e-9, 1e-12] + function f(sim) + execute!( + sim, + solver; + abstol = tol, + reltol = tol, + dtmax = 0.005, + saveat = 0.005, + ) + res = read_results(sim) + t, δ = get_state_series(res, ("generator-102-1", :δ)) + #display(plot(scatter(x=t, y = δ))) + return sum(abs.(δ - δ_gt)) + end + g = PSID.get_parameter_sensitivity_function!( + sim, + [("generator-102-1", SingleMass, :H)], + f, + ) + #p = PSID.get_parameter_sensitivity_values(sim, [("generator-102-1", SingleMass, :H)]) + @test isapprox(Zygote.gradient(g, [3.14])[1][1], -8.0, atol = 1.0) + @test isapprox(Zygote.gradient(g, [3.15])[1][1], 8.0, atol = 1.0) + end + end + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + +@testset "Test Parameter Optimization Problem - no delays" begin + path = mktempdir() + try + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + H_gt = + get_H(get_shaft(get_component(DynamicGenerator, omib_sys, "generator-102-1"))) + execute!(sim, Rodas5(; autodiff = true); dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + + function f(sim) + execute!(sim, FBDF(; autodiff = true); dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ = get_state_series(res, ("generator-102-1", :δ)) + #display(plot(scatter(x=t, y = δ))) + return sum(abs.(δ - δ_gt)) + end + g = PSID.get_parameter_sensitivity_function!( + sim, + [("generator-102-1", SingleMass, :H)], + f, + ) + p = PSID.get_parameter_sensitivity_values( + sim, + [("generator-102-1", SingleMass, :H)], + ) + #H_values = [] + #loss_values = [] + function callback(u, l) + #push!(H_values, u.u[1]) + #push!(loss_values, l) + return false + end + optfun = OptimizationFunction((u, _) -> g(u), Optimization.AutoZygote()) + optprob = OptimizationProblem(optfun, [3.14]) + sol = Optimization.solve( + optprob, + OptimizationOptimisers.Adam(0.002); + callback = callback, + maxiters = 3, + ) + @test sol.u[1] == 3.144000187737475 + #display(plot(scatter(y=H_values))) + #display(plot(scatter(y=loss_values))) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + +@testset "Test Gradients - Mass Matrix with delays" begin + path = mktempdir() + try + gen = get_component(ThermalStandard, omib_sys, "generator-102-1") + dyn_gen = get_component(DynamicGenerator, omib_sys, "generator-102-1") + new_gov = PSY.DEGOV(; + T1 = 0.0, + T2 = 0.0, + T3 = 0.0, + K = 18.0, + T4 = 12.0, + T5 = 5.0, + T6 = 0.2, + Td = 0.5, + P_ref = 0.0, + ) + dyn_gen_new = DynamicGenerator(; + name = get_name(dyn_gen), + ω_ref = get_ω_ref(dyn_gen), + machine = get_machine(dyn_gen), + shaft = get_shaft(dyn_gen), + avr = get_avr(dyn_gen), + prime_mover = new_gov, + pss = get_pss(dyn_gen), + base_power = get_base_power(dyn_gen), + ) + remove_component!(omib_sys, dyn_gen) + add_component!(omib_sys, dyn_gen_new, gen) + + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + H_gt = + get_H(get_shaft(get_component(DynamicGenerator, omib_sys, "generator-102-1"))) + execute!( + sim, + MethodOfSteps(Rodas5(; autodiff = false)); + dtmax = 0.005, + saveat = 0.005, + ) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + for solver in [ + MethodOfSteps(Rodas5(; autodiff = true)), + MethodOfSteps(QNDF(; autodiff = true)), + ] + for tol in [1e-6] + function f(sim) + execute!( + sim, + solver; + abstol = tol, + reltol = tol, + dtmax = 0.005, + saveat = 0.005, + ) + res = read_results(sim) + t, δ = get_state_series(res, ("generator-102-1", :δ)) + #display(plot(scatter(x=t, y = δ))) + return sum(abs.(δ - δ_gt)) + end + g = PSID.get_parameter_sensitivity_function!( + sim, + [("generator-102-1", SingleMass, :H)], + f, + ) + #p = PSID.get_parameter_sensitivity_values(sim, [("generator-102-1", SingleMass, :H)]) + #display(Zygote.gradient(g, [3.14])) + @test isapprox(Zygote.gradient(g, [3.14])[1][1], -10.0, atol = 1.0) + @test isapprox(Zygote.gradient(g, [3.15])[1][1], 10.0, atol = 1.0) + end + end + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + +@testset "Test Parameter Optimization Problem - with delays" begin + path = mktempdir() + try + gen = get_component(ThermalStandard, omib_sys, "generator-102-1") + dyn_gen = get_component(DynamicGenerator, omib_sys, "generator-102-1") + new_gov = PSY.DEGOV(; + T1 = 0.0, + T2 = 0.0, + T3 = 0.0, + K = 18.0, + T4 = 12.0, + T5 = 5.0, + T6 = 0.2, + Td = 0.5, + P_ref = 0.0, + ) + dyn_gen_new = DynamicGenerator(; + name = get_name(dyn_gen), + ω_ref = get_ω_ref(dyn_gen), + machine = get_machine(dyn_gen), + shaft = get_shaft(dyn_gen), + avr = get_avr(dyn_gen), + prime_mover = new_gov, + pss = get_pss(dyn_gen), + base_power = get_base_power(dyn_gen), + ) + remove_component!(omib_sys, dyn_gen) + add_component!(omib_sys, dyn_gen_new, gen) + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + H_gt = + get_H(get_shaft(get_component(DynamicGenerator, omib_sys, "generator-102-1"))) + execute!( + sim, + MethodOfSteps(Rodas5(; autodiff = true)); + dtmax = 0.005, + saveat = 0.005, + ) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + + function f(sim) + execute!( + sim, + MethodOfSteps(Rodas5(; autodiff = true)); + abstol = 1e-6, + reltol = 1e-6, + dtmax = 0.005, + saveat = 0.005, + ) + res = read_results(sim) + t, δ = get_state_series(res, ("generator-102-1", :δ)) + #display(plot(scatter(x=t, y = δ))) + return sum(abs.(δ - δ_gt)) + end + g = PSID.get_parameter_sensitivity_function!( + sim, + [("generator-102-1", SingleMass, :H)], + f, + ) + p = PSID.get_parameter_sensitivity_values( + sim, + [("generator-102-1", SingleMass, :H)], + ) + #H_values = [] + #loss_values = [] + function callback(u, l) + #push!(H_values, u.u[1]) + #push!(loss_values, l) + return false + end + optfun = OptimizationFunction((u, _) -> g(u), Optimization.AutoZygote()) + optprob = OptimizationProblem(optfun, [3.14]) + sol = Optimization.solve( + optprob, + OptimizationOptimisers.Adam(0.002); + callback = callback, + maxiters = 3, + ) + @test sol.u[1] == 3.1440015515797763 + #display(plot(scatter(y=H_values))) + #display(plot(scatter(y=loss_values))) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end From 4b7164845005a0aeb32f212ae8f7a86b9e5be8ea Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 30 Apr 2024 12:36:06 -0400 Subject: [PATCH 07/76] remove refs, handling user input, add docs --- docs/make.jl | 1 + docs/src/sensitivity_analysis.md | 9 + src/PowerSimulationsDynamics.jl | 2 + src/base/definitions.jl | 8 - src/base/device_wrapper.jl | 104 +- src/base/perturbations.jl | 14 +- src/base/sensitivity_analysis.jl | 145 +- src/base/simulation.jl | 59 +- src/base/simulation_initialization.jl | 13 +- src/base/simulation_inputs.jl | 22 +- .../generator_components/init_avr.jl | 20 +- .../generator_components/init_shaft.jl | 2 +- .../generator_components/init_tg.jl | 20 +- src/initialization/init_device.jl | 91 +- .../inverter_components/init_filter.jl | 2 +- .../init_frequency_estimator.jl | 4 +- .../inverter_components/init_inner.jl | 6 +- .../inverter_components/init_outer.jl | 36 +- src/models/device.jl | 69 +- src/models/generator_models/avr_models.jl | 20 +- src/models/generator_models/tg_models.jl | 20 +- .../inverter_models/outer_control_models.jl | 60 +- src/utils/parameters.jl | 1262 +++++++++-------- test/Project.toml | 5 + test/test_base.jl | 4 +- test/test_case_sensitivity.jl | 38 +- 26 files changed, 1083 insertions(+), 953 deletions(-) create mode 100644 docs/src/sensitivity_analysis.md diff --git a/docs/make.jl b/docs/make.jl index 733595e8b..f3069edd8 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -23,6 +23,7 @@ makedocs(; "Reference Frames" => "reference_frames.md", "Perturbations" => "perturbations.md", "Time Delays" => "time_delays.md", + "Sensitivity Analysis" => "sensitivity_analysis.md", "Industrial Renewable Models" => "generic.md", "Generator Component Library" => Any[ "Machine" => "component_models/machines.md", diff --git a/docs/src/sensitivity_analysis.md b/docs/src/sensitivity_analysis.md new file mode 100644 index 000000000..4351bb453 --- /dev/null +++ b/docs/src/sensitivity_analysis.md @@ -0,0 +1,9 @@ +# Sensitivity Analysis + +PowerSimulationsDynamics has limited support for performing sensitivity analysis of system parameters with respect to a user defined loss function. See the tutorial for an example of sensitivity analysis. + +* `ForwardDiffSensitivity()` is used as the method for differentiating through the solve. See `SciMLSensitivity.jl` for more details. +* The gradient of the function provided by PSID can be calculated using `Zygote.jl`. +* The Jacobian is not passed to the ODE Problem during sensitivity analysis. +* Parameters for sensitivity analysis must not change the steady state operating condition. Parameters cannot be in the mass matrix. This limitation is expected to be relaxed in the future. +* Limited to mass matrix formulations and pure Julia solvers. Can check if a solver is compatible with `SciMLBase.isautodifferentiable()` diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index 52f7107e6..b6e4645d3 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -61,6 +61,8 @@ export is_valid export transform_load_to_constant_impedance export transform_load_to_constant_current export transform_load_to_constant_power +export get_parameter_sensitivity_function! +export get_parameter_sensitivity_values ####################################### Package Imports #################################### import Logging diff --git a/src/base/definitions.jl b/src/base/definitions.jl index 433a2e02a..3c8551003 100644 --- a/src/base/definitions.jl +++ b/src/base/definitions.jl @@ -101,14 +101,6 @@ end Base.to_index(ix::dq_ref) = Int(ix) Base.to_index(ix::RI_ref) = Int(ix) -@enum ref_ix begin - Q_ref_ix = 1 - V_ref_ix = 2 - ω_ref_ix = 3 - P_ref_ix = 4 -end -Base.to_index(ix::ref_ix) = Int(ix) - const MAPPING_DICT = Dict{String, OrderedDict{Symbol, Int}} const DEVICE_INTERNAL_MAPPING = Base.ImmutableDict{Int, Vector{Int}} diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index ae842cccc..2aac2144b 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -31,12 +31,16 @@ Wraps DynamicInjection devices from PowerSystems to handle changes in controls a status, and allocate the required indexes of the state space and parameter space. """ struct DynamicWrapper{T <: PSY.DynamicInjection} - dynamic_device::T - static_device::PSY.StaticInjection + device::T system_base_power::Float64 system_base_frequency::Float64 + static_type::Type{<:PSY.StaticInjection} bus_category::Type{<:BusCategory} connection_status::Base.RefValue{Float64} + V_ref::Base.RefValue{Float64} + ω_ref::Base.RefValue{Float64} + P_ref::Base.RefValue{Float64} + Q_ref::Base.RefValue{Float64} inner_vars_index::Vector{Int} ix_range::Vector{Int} ode_range::Vector{Int} @@ -49,12 +53,16 @@ struct DynamicWrapper{T <: PSY.DynamicInjection} ext::Dict{String, Any} function DynamicWrapper( - dynamic_device::T, - static_device::V, + device::T, system_base_power::Float64, system_base_frequency::Float64, + static_type::Type{<:PSY.StaticInjection}, bus_category::Type{<:BusCategory}, connection_status::Base.RefValue{Float64}, + V_ref::Base.RefValue{Float64}, + ω_ref::Base.RefValue{Float64}, + P_ref::Base.RefValue{Float64}, + Q_ref::Base.RefValue{Float64}, inner_vars_index, ix_range, ode_range, @@ -65,16 +73,20 @@ struct DynamicWrapper{T <: PSY.DynamicInjection} component_parameter_mapping::Base.ImmutableDict{Int, Vector{Int}}, input_port_mapping::Base.ImmutableDict{Int, Vector{Int}}, ext::Dict{String, Any}, - ) where {V <: PSY.StaticInjection, T <: PSY.DynamicInjection} - is_valid(dynamic_device) + ) where {T <: PSY.DynamicInjection} + is_valid(device) new{T}( - dynamic_device, - static_device, + device, system_base_power, system_base_frequency, + static_type, bus_category, connection_status, + V_ref, + ω_ref, + P_ref, + Q_ref, Vector{Int}(inner_vars_index), Vector{Int}(ix_range), Vector{Int}(ode_range), @@ -132,13 +144,6 @@ function _get_parameter_symbols( return get_params_symbol(dynamic_device) end -function _get_parameter_symbols( - dynamic_device::T, - static_device::PSY.StaticInjection, -) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} - return vcat(get_params_symbol(static_device), get_params_symbol(dynamic_device)) -end - function DynamicWrapper( static_device::T, dynamic_device::D, @@ -152,7 +157,8 @@ function DynamicWrapper( ) where {T <: PSY.StaticInjection, D <: PSY.DynamicInjection} device_states = PSY.get_states(dynamic_device) device_parameters = _get_parameter_symbols(dynamic_device, static_device) - @assert allunique(device_parameters) #mapping depends on unique parameters per device + #Parameter mappings depend on unique parameters per device + @assert allunique(device_parameters) component_state_mapping, input_port_mapping = state_port_mappings(dynamic_device, device_states) @@ -163,14 +169,17 @@ function DynamicWrapper( else reactive_power = PSY.get_reactive_power(static_device) end - return DynamicWrapper( dynamic_device, - static_device, sys_base_power, sys_base_freq, + T, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), + Base.Ref(PSY.get_V_ref(dynamic_device)), + Base.Ref(PSY.get_ω_ref(dynamic_device)), + Base.Ref(PSY.get_P_ref(dynamic_device)), + Base.Ref(reactive_power), inner_var_range, ix_range, ode_range, @@ -217,11 +226,15 @@ function DynamicWrapper( return DynamicWrapper( dynamic_device, - static_device, sys_base_power, sys_base_freq, + PSY.ThermalStandard, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), + Base.Ref(PSY.get_V_ref(dynamic_device)), + Base.Ref(PSY.get_ω_ref(dynamic_device)), + Base.Ref(PSY.get_P_ref(dynamic_device)), + Base.Ref(PSY.get_reactive_power(static_device)), inner_var_range, ix_range, ode_range, @@ -262,11 +275,15 @@ function DynamicWrapper( return DynamicWrapper( dynamic_device, - static_device, sys_base_power, sys_base_freq, + PSY.Source, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), + Base.Ref(0.0), + Base.Ref(0.0), + Base.Ref(0.0), + Base.Ref(0.0), collect(inner_var_range), collect(ix_range), collect(ode_range), @@ -284,7 +301,7 @@ function _index_local_parameters( component::PSY.DynamicComponent, device_parameters::Vector{Symbol}, ) - component_paramter_index = Vector{Int}(undef, get_n_params(component)) + component_paramter_index = Vector{Int}(undef, length(get_params(component))) component_parameters = get_params_symbol(component) for (ix, s) in enumerate(component_parameters) component_paramter_index[ix] = findfirst(x -> x == s, device_parameters) @@ -315,8 +332,7 @@ function _index_port_mapping!( return index_component_inputs end -get_dynamic_device(wrapper::DynamicWrapper) = wrapper.dynamic_device -get_static_device(wrapper::DynamicWrapper) = wrapper.static_device +get_device(wrapper::DynamicWrapper) = wrapper.device get_device_type(::DynamicWrapper{T}) where {T <: PSY.DynamicInjection} = T get_bus_category(wrapper::DynamicWrapper) = wrapper.bus_category get_inner_vars_index(wrapper::DynamicWrapper) = wrapper.inner_vars_index @@ -334,36 +350,46 @@ get_ext(wrapper::DynamicWrapper) = wrapper.ext get_system_base_power(wrapper::DynamicWrapper) = wrapper.system_base_power get_system_base_frequency(wrapper::DynamicWrapper) = wrapper.system_base_frequency +get_P_ref(wrapper::DynamicWrapper) = wrapper.P_ref[] +get_Q_ref(wrapper::DynamicWrapper) = wrapper.Q_ref[] +get_V_ref(wrapper::DynamicWrapper) = wrapper.V_ref[] +get_ω_ref(wrapper::DynamicWrapper) = wrapper.ω_ref[] + +set_P_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.P_ref[] = val +set_Q_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.Q_ref[] = val +set_V_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.V_ref[] = val +set_ω_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.ω_ref[] = val + # PSY overloads for the wrapper -PSY.get_name(wrapper::DynamicWrapper) = PSY.get_name(wrapper.dynamic_device) -PSY.get_ext(wrapper::DynamicWrapper) = PSY.get_ext(wrapper.dynamic_device) -PSY.get_states(wrapper::DynamicWrapper) = PSY.get_states(wrapper.dynamic_device) -PSY.get_n_states(wrapper::DynamicWrapper) = PSY.get_n_states(wrapper.dynamic_device) -PSY.get_base_power(wrapper::DynamicWrapper) = PSY.get_base_power(wrapper.dynamic_device) +PSY.get_name(wrapper::DynamicWrapper) = PSY.get_name(wrapper.device) +PSY.get_ext(wrapper::DynamicWrapper) = PSY.get_ext(wrapper.device) +PSY.get_states(wrapper::DynamicWrapper) = PSY.get_states(wrapper.device) +PSY.get_n_states(wrapper::DynamicWrapper) = PSY.get_n_states(wrapper.device) +PSY.get_base_power(wrapper::DynamicWrapper) = PSY.get_base_power(wrapper.device) PSY.get_machine(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} = - wrapper.dynamic_device.machine + wrapper.device.machine PSY.get_shaft(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} = - wrapper.dynamic_device.shaft + wrapper.device.shaft PSY.get_avr(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} = - wrapper.dynamic_device.avr + wrapper.device.avr PSY.get_prime_mover(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} = - wrapper.dynamic_device.prime_mover + wrapper.device.prime_mover PSY.get_pss(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} = - wrapper.dynamic_device.pss + wrapper.device.pss PSY.get_converter(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.dynamic_device.converter + wrapper.device.converter PSY.get_outer_control(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.dynamic_device.outer_control + wrapper.device.outer_control PSY.get_inner_control(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.dynamic_device.inner_control + wrapper.device.inner_control PSY.get_dc_source(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.dynamic_device.dc_source + wrapper.device.dc_source PSY.get_freq_estimator(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.dynamic_device.freq_estimator + wrapper.device.freq_estimator PSY.get_filter(wrapper::DynamicWrapper{T}) where {T <: PSY.DynamicInverter} = - wrapper.dynamic_device.filter + wrapper.device.filter # PSY overloads of specific Dynamic Injectors diff --git a/src/base/perturbations.jl b/src/base/perturbations.jl index a68dc7786..9a841cdb7 100644 --- a/src/base/perturbations.jl +++ b/src/base/perturbations.jl @@ -474,18 +474,8 @@ function get_affect(inputs::SimulationInputs, ::PSY.System, pert::ControlReferen wrapped_device_ix = _find_device_index(inputs, pert.device) return (integrator) -> begin wrapped_device = get_dynamic_injectors(inputs)[wrapped_device_ix] - p_range = get_p_range(wrapped_device) - p_local = @view integrator.p[p_range] - if pert.signal == :P_ref - ix = P_ref_ix - elseif pert.signal == :Q_ref - ix = Q_ref_ix - elseif pert.signal == :V_ref - ix = V_ref_ix - elseif pert.signal == :ω_ref - ix = ω_ref_ix - end - p_local[ix] = pert.ref_value + @debug "Changing $(PSY.get_name(wrapped_device)) $(pert.signal) to $(pert.ref_value)" + getfield(wrapped_device, pert.signal)[] = pert.ref_value return end end diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 6e8cf4e4d..dc056c026 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -1,12 +1,82 @@ """ -function f(::Simulation) + function get_parameter_sensitivity_function!( + sim::Simulation, + device_parameter_pairs::Vector{Tuple{String, Type{T}, Symbol}}, + f::function, + ) +Gets a function for taking gradients with respect to parameters. +# Arguments +- `sim::Simulation` : Initialized simulation object +- `device_parameter_pairs::Vector{Tuple{String, Type{T}, Symbol}}` : Tuple used to identify the parameter, via the device name, as a `String`, the type of the Device or DynamicComponent, and the parameter as a `Symbol`. +- `f::function` : User provided function with input a simulation and output a scalar value. This function can include executing the simulation and post-processing of results + +# Example +```julia +function f(sim::Simulation) + execute!(sim, Rodas5()) + res = read_results(sim) + _, δ = get_state_series(res, ("generator-1", :δ)) + sum(δ) end -g = get_parameter_sensitivity_function!(sim, Vector{Tuple{String, Type{T}, Symbol}}, f) where {T<: Union{Device, DynamicComponent} -p = get_parameter_sensitivity_values(sim, Vector{Tuple{String, Type{T}, Symbol}}, f) where {T<: Union{Device, DynamicComponent} +g = get_parameter_sensitivity_function!(sim, ("generator-1", SingleMass, :H), f) +Zygote.gradient(g, [2.0]); +``` +""" +function get_parameter_sensitivity_function!(sim, device_param_pairs, f) + indices = get_indices_in_parameter_vector(sim, device_param_pairs) + if indices === nothing + return nothing + end + sim_level = get_required_initialization_level(sim, device_param_pairs) + if sim_level === nothing + return nothing + end + reset!(sim) + @assert sim.status == BUILT + sim.initialize_level = sim_level + sim.enable_sensitivity = true + sensitivity_function = (p) -> + begin + sim.inputs = deepcopy(sim.inputs_init) + set_parameters!(sim, indices, p) + reset!(sim) + return f(sim) + end + return sensitivity_function +end + +""" + function get_parameter_sensitivity_function!( + sim::Simulation, + device_parameter_pairs::Vector{Tuple{String, Type{T}, Symbol}}, + f::function, + ) + +get_parameter_sensitivity_values can be used in conjunction with get_parameter_sensitivity_function! to get the starting values of the parameters for taking gradients. + +# Arguments +- `sim::Simulation` : Initialized simulation object +- `device_parameter_pairs::Vector{Tuple{String, Type{T}, Symbol}}` : Tuple used to identify the parameter, via the device name, as a `String`, the type of the Device or DynamicComponent, and the parameter as a `Symbol`. -Zygote.gradient(g, p) +# Example +```julia +function f(sim::Simulation) + execute!(sim, Rodas5()) + res = read_results(sim) + _, δ = get_state_series(res, ("generator-1", :δ)) + sum(δ) +end +g = get_parameter_sensitivity_function!(sim, ("generator-1", SingleMass, :H), f) +p = get_parameter_sensitivity_values(sim, ("generator-1", SingleMass, :H)) +Zygote.gradient(g, p); +``` """ +function get_parameter_sensitivity_values(sim, device_param_pairs) + indices = get_indices_in_parameter_vector(sim, device_param_pairs) + param_vector = sim.inputs.parameters + return param_vector[indices] +end function _append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Device} return s @@ -24,7 +94,12 @@ _append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.FrequencyEstimator} = _append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.InnerControl} = Symbol(s, :_InnerControl) _append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.OuterControl} = - Symbol(s, :_OuterControl) + @error "Specify PSY.ActivePowerControl or PSY.ReactivePowerControl" +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.ActivePowerControl} = + Symbol(s, :_ActivePowerControl) +_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.ReactivePowerControl} = + Symbol(s, :_ReactivePowerControl) + _append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.InverterLimiter} = Symbol(s, :_InverterLimiter) @@ -32,7 +107,7 @@ function get_indices_in_parameter_vector(sim, device_param_pairs) indices = Int[] for (device_name, component_type, param_symbol) in device_param_pairs ix = findfirst( - x -> PSY.get_name(x.dynamic_device) == device_name, + x -> PSY.get_name(x.device) == device_name, sim.inputs_init.dynamic_injectors, ) if ix !== nothing @@ -45,22 +120,51 @@ function get_indices_in_parameter_vector(sim, device_param_pairs) if ix !== nothing wrapped_device = sim.inputs_init.static_injectors[ix] else - CRC.@ignore_derivatives @error "Device name not found in dynamic or static injectors" + CRC.@ignore_derivatives @warn "Device $device_name not found in dynamic or static injectors" + return nothing end end full_symbol = _append_symbol(param_symbol, component_type) external_ix = get_p_range(wrapped_device) internal_ix = findfirst(isequal(full_symbol), get_params_symbol(wrapped_device)) + if internal_ix === nothing + @warn "Parameter :$param_symbol of $component_type not found." + return nothing + end global_ix = external_ix[internal_ix] - @assert global_ix !== nothing push!(indices, global_ix) return indices end end function get_required_initialization_level(sim, device_param_pairs) - return INITIALIZED #TODO -implement check of what type of parameters were changed + init_level = INITIALIZED + for (device_name, component_type, param_symbol) in device_param_pairs + metadata = get_params_metadata(component_type(nothing)) + symbols = [m.symbol for m in metadata] + full_symbol = _append_symbol(param_symbol, component_type) + ix = findfirst(isequal(full_symbol), symbols) + metadata_entry = metadata[ix] + if metadata_entry.in_mass_matrix == true + @warn "Parameter :$param_symbol of $component_type appears in mass matrix -- not supported" + return + end + if metadata_entry.in_network == true + @warn "Parameter :$param_symbol of $component_type appears in network -- not supported" + return + end + if metadata_entry.impacts_ic == true + @warn "Parameter :$param_symbol of $component_type appears in initialization -- not supported" + return + end + if metadata_entry.impacts_pf == true + @warn "Parameter :$param_symbol of $component_type impacts power flow -- not supported" + return + end + end + return init_level end + function make_buffer(a) buf = Zygote.Buffer(a) for i in eachindex(a) @@ -85,26 +189,3 @@ function set_parameters!(sim, indices, params) Accessors.@reset inputs.parameters = make_array(parameter_buffer) sim.inputs = inputs end - -function get_parameter_sensitivity_function!(sim, device_param_pairs, f) - indices = get_indices_in_parameter_vector(sim, device_param_pairs) - sim_level = get_required_initialization_level(sim, device_param_pairs) - reset!(sim) - @assert sim.status == BUILT - sim.initialize_level = sim_level - sim.enable_sensitivity = true - sensitivity_function = (p) -> - begin - sim.inputs = deepcopy(sim.inputs_init) - set_parameters!(sim, indices, p) - reset!(sim) - return f(sim) - end - return sensitivity_function -end - -function get_parameter_sensitivity_values(sim, device_param_pairs) - indices = get_indices_in_parameter_vector(sim, device_param_pairs) - param_vector = sim.inputs.parameters - return param_vector[indices] -end diff --git a/src/base/simulation.jl b/src/base/simulation.jl index 3874ffc1d..0443a656e 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -422,7 +422,7 @@ function _get_diffeq_problem( h, get_tspan(sim), p; - constant_lags = get_constant_lags(simulation_inputs), + constant_lags = filter(x -> x != 0, get_constant_lags(simulation_inputs)), ) sim.status = BUILT @@ -449,7 +449,7 @@ function _get_diffeq_problem( h, get_tspan(sim), p; - constant_lags = get_constant_lags(simulation_inputs), + constant_lags = filter(x -> x != 0, get_constant_lags(simulation_inputs)), ) sim.status = BUILT @@ -609,8 +609,11 @@ function _filter_kwargs(kwargs) return filter(x -> in(x[1], DIFFEQ_SOLVE_KWARGS), kwargs) end -function _execute!(sim::Simulation, ::Val{true}, solver; kwargs...) +function _execute!(sim::Simulation, solver; kwargs...) CRC.@ignore_derivatives @debug "status before execute" sim.status + if !(sim.enable_sensitivity) + CRC.@ignore_derivatives simulation_pre_step!(sim) + end sim.status = SIMULATION_STARTED time_log = Dict{Symbol, Any}() if get(kwargs, :auto_abstol, false) @@ -650,46 +653,6 @@ function _execute!(sim::Simulation, ::Val{true}, solver; kwargs...) end end -function _execute!(sim::Simulation, ::Val{false}, solver; kwargs...) - @debug "status before execute" sim.status - simulation_pre_step!(sim) - sim.status = SIMULATION_STARTED - time_log = Dict{Symbol, Any}() - if get(kwargs, :auto_abstol, false) - cb = AutoAbstol(true, get(kwargs, :abstol, 1e-9)) - callbacks = SciMLBase.CallbackSet((), tuple(push!(sim.callbacks, cb)...)) - else - callbacks = SciMLBase.CallbackSet((), tuple(sim.callbacks...)) - end - progress_enable = _prog_meter_enabled() - solution, - time_log[:timed_solve_time], - time_log[:solve_bytes_alloc], - time_log[:sec_in_gc] = @timed SciMLBase.solve( - sim.problem, - solver; - callback = callbacks, - tstops = !isempty(sim.tstops) ? [sim.tstops[1] ÷ 2, sim.tstops...] : [], - progress = get(kwargs, :enable_progress_bar, progress_enable), - progress_steps = 1, - advance_to_tstop = !isempty(sim.tstops), - initializealg = SciMLBase.NoInit(), - _filter_kwargs(kwargs)..., - ) - if SciMLBase.successful_retcode(solution) - sim.status = SIMULATION_FINALIZED - sim.results = SimulationResults( - get_simulation_inputs(sim), - get_system(sim), - time_log, - solution, - ) - else - @error("The simulation failed with return code $(solution.retcode)") - sim.status = SIMULATION_FAILED - end -end - """ execute!( sim::Simulation, @@ -706,14 +669,14 @@ Solves the time-domain dynamic simulation model. - Additional solver keyword arguments can be included. See [Common Solver Options](https://diffeq.sciml.ai/stable/basics/common_solver_opts/) in the `DifferentialEquations.jl` documentation for more details. """ function execute!(sim::Simulation, solver; kwargs...) - __execute!(sim, Val(sim.enable_sensitivity), solver; kwargs...) + execute!(sim, Val(sim.enable_sensitivity), solver; kwargs...) end -function __execute!(sim::Simulation, ::Val{false}, solver; kwargs...) +function execute!(sim::Simulation, ::Val{false}, solver; kwargs...) logger = configure_logging(sim, "a"; kwargs...) Logging.with_logger(logger) do try - _execute!(sim, Val(sim.enable_sensitivity), solver; kwargs...) + _execute!(sim, solver; kwargs...) catch e CRC.@ignore_derivatives @error "Execution failed" exception = (e, catch_backtrace()) @@ -724,8 +687,8 @@ function __execute!(sim::Simulation, ::Val{false}, solver; kwargs...) return sim.status end -function __execute!(sim::Simulation, ::Val{true}, solver; kwargs...) - _execute!(sim, Val(sim.enable_sensitivity), solver; kwargs...) +function execute!(sim::Simulation, ::Val{true}, solver; kwargs...) + _execute!(sim, solver; kwargs...) return sim.status end diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index 3e2faa184..40a72a260 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -73,11 +73,22 @@ function initialize_dynamic_injection!( parameters = get_parameters(inputs) try for dynamic_device in get_dynamic_injectors(inputs) + static = PSY.get_component( + dynamic_device.static_type, + system, + PSY.get_name(dynamic_device), + ) CRC.@ignore_derivatives @debug "Initializing $(PSY.get_name(dynamic_device)) - $(typeof(dynamic_device.device))" _inner_vars = @view initial_inner_vars[get_inner_vars_index(dynamic_device)] _parameters = @view parameters[get_p_range(dynamic_device)] _states = @view initial_guess[get_ix_range(dynamic_device)] - initialize_dynamic_device!(dynamic_device, _inner_vars, _parameters, _states) + initialize_dynamic_device!( + dynamic_device, + static, + _inner_vars, + _parameters, + _states, + ) end catch e bt = catch_backtrace() diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index fea32fe1f..f9510b165 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -71,6 +71,7 @@ function SimulationInputs( _update_initial_parameters!(initial_parameters, wrapped_loads) _update_initial_parameters!(initial_parameters, wrapped_static_injectors) end + mass_matrix = _make_mass_matrix(wrapped_injectors, n_vars, n_buses) DAE_vector = _make_DAE_vector(mass_matrix, n_vars, n_buses) _adjust_states!( @@ -186,14 +187,14 @@ function _get_n_params( dynamic_device::PSY.DynamicInjection, static_device::PSY.StaticInjection, ) - return get_n_params(dynamic_device) + return length(get_params(dynamic_device)) end function _get_n_params( dynamic_device::T, static_device::PSY.StaticInjection, ) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} - return get_n_params(dynamic_device) + get_n_params(static_device) + return length(get_params(dynamic_device)) end function _wrap_dynamic_injector_data( @@ -253,8 +254,7 @@ function get_constant_lags(sys::PSY.System) delays = vcat(delays, device_delays) end end - return filter!(x -> x != 0, unique(delays)) - + return unique(delays) end function _wrap_dynamic_branches( @@ -279,7 +279,7 @@ function _wrap_dynamic_branches( bus_ix_to = lookup[to_bus_number] ix_range = range(state_count; length = n_states) ode_range = range(branches_count; length = n_states) - n_params = get_n_params(br) + n_params = length(get_params(br)) p_range = range(parameter_count; length = n_params) @debug "ix_range=$ix_range ode_range=$ode_range p_range=$ode_range" wrapped_branches[ix] = BranchWrapper( @@ -315,7 +315,7 @@ function _wrap_static_injectors( end bus_n = PSY.get_number(PSY.get_bus(ld)) bus_ix = lookup[bus_n] - n_params = get_n_params(ld) + n_params = length(get_params(ld)) p_range = range(parameter_count; length = n_params) container[ix] = StaticWrapper(ld, bus_ix, p_range) parameter_count += n_params @@ -489,14 +489,12 @@ end function get_setpoints(inputs::SimulationInputs) dic = Dict{String, Dict{String, Float64}}() - parameters = get_parameters(inputs) for w in get_dynamic_injectors(inputs) dic_w = Dict{String, Float64}() - p_range = get_p_range(w) - dic_w["P_ref"] = parameters[p_range][P_ref_ix] - dic_w["Q_ref"] = parameters[p_range][Q_ref_ix] - dic_w["ω_ref"] = parameters[p_range][ω_ref_ix] - dic_w["V_ref"] = parameters[p_range][V_ref_ix] + dic_w["P_ref"] = get_P_ref(w) + dic_w["Q_ref"] = get_Q_ref(w) + dic_w["ω_ref"] = get_ω_ref(w) + dic_w["V_ref"] = get_V_ref(w) dic[PSY.get_name(w)] = dic_w end return dic diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index e53c5178d..31bd43661 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -9,7 +9,7 @@ function initialize_avr!( Vf = inner_vars[Vf_var] #Update Control Refs avr = PSY.get_avr(dynamic_device) - device_parameters[V_ref_ix] = Vf + set_V_ref(dynamic_device, Vf) PSY.set_Vf!(avr, Vf) PSY.set_V_ref!(avr, Vf) return @@ -34,7 +34,7 @@ function initialize_avr!( #Set V_ref PSY.set_V_ref!(PSY.get_avr(dynamic_device), Vm) #Update Control Refs - device_parameters[V_ref_ix] = Vm + set_V_ref(dynamic_device, Vm) return end @@ -79,7 +79,7 @@ function initialize_avr!( sol_x0 = sol.zero #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - device_parameters[V_ref_ix] = sol_x0[1] + set_V_ref(dynamic_device, sol_x0[1]) #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeI) avr_states = @view device_states[avr_ix] @@ -147,7 +147,7 @@ function initialize_avr!( sol_x0 = sol.zero #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - device_parameters[V_ref_ix] = sol_x0[1] + set_V_ref(dynamic_device, sol_x0[1]) #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeII) avr_states = @view device_states[avr_ix] @@ -270,7 +270,7 @@ function initialize_avr!( sol_x0 = sol.zero #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - device_parameters[V_ref_ix] = sol_x0[1] + set_V_ref(dynamic_device, sol_x0[1]) #Update AVR states avr_ix = get_local_state_ix(dynamic_device, typeof(avr)) avr_states = @view device_states[avr_ix] @@ -328,7 +328,7 @@ function initialize_avr!( end #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - device_parameters[V_ref_ix] = sol_x0[1] + set_V_ref(dynamic_device, sol_x0[1]) #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.SEXS) @@ -414,7 +414,7 @@ function initialize_avr!( end #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - device_parameters[V_ref_ix] = sol_x0[1] + set_V_ref(dynamic_device, sol_x0[1]) #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.SCRX) avr_states = @view device_states[avr_ix] @@ -465,7 +465,7 @@ function initialize_avr!( Vref0 = Vt + Vf0 / Ka PSY.set_V_ref!(avr, Vref0) - device_parameters[V_ref_ix] = Vref0 + set_V_ref(dynamic_device, Vref0) #States of EXST1_PTI are Vm, Vll, Vr, Vfb @@ -544,7 +544,7 @@ function initialize_avr!( #Update V_ref PSY.set_V_ref!(avr, Vref0) - device_parameters[V_ref_ix] = Vref0 + set_V_ref(dynamic_device, Vref0) #States of EXAC1 are Vm, Vr1, Vr2, Ve, Vr3 @@ -604,7 +604,7 @@ function initialize_avr!( Vref0 = Vt + Va / Ka PSY.set_V_ref!(avr, Vref0) - device_parameters[V_ref_ix] = Vref0 + set_V_ref(dynamic_device, Vref0) #States of ESST1A_PTI are Vm, Vr1, Vr2, Va, Vr3 diff --git a/src/initialization/generator_components/init_shaft.jl b/src/initialization/generator_components/init_shaft.jl index 261eab6ec..99cd66562 100644 --- a/src/initialization/generator_components/init_shaft.jl +++ b/src/initialization/generator_components/init_shaft.jl @@ -25,7 +25,7 @@ function initialize_shaft!( ω_sys = ω #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SingleMass) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.FiveMassShaft) internal_params = @view device_parameters[local_ix_params] _, _, diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index 4cb87447c..eed605a8a 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -14,7 +14,7 @@ function initialize_tg!( P_ref = τm0 / eff #Update Control Refs PSY.set_P_ref!(tg, P_ref) - device_parameters[P_ref_ix] = P_ref + set_P_ref(dynamic_device, P_ref) return end @@ -37,7 +37,7 @@ function initialize_tg!( inv_R = R < eps() ? 0.0 : (1.0 / R) #Get References - ω_ref = device_parameters[ω_ref_ix] + ω_ref = get_ω_ref(dynamic_device) ω0 = 1.0 function f!(out, x) P_ref = x[1] @@ -68,7 +68,7 @@ function initialize_tg!( sol_x0 = sol.zero #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - device_parameters[P_ref_ix] = sol_x0[1] + set_P_ref(dynamic_device, sol_x0[1]) #Update states tg_ix = get_local_state_ix(dynamic_device, PSY.TGTypeI) tg_states = @view device_states[tg_ix] @@ -100,7 +100,7 @@ function initialize_tg!( internal_params = @view device_parameters[local_ix_params] R, T1, T2 = internal_params inv_R = R < eps() ? 0.0 : (1.0 / R) - ω_ref = device_parameters[ω_ref_ix] + ω_ref = get_ω_ref(dynamic_device) ω0 = ω_ref function f!(out, x) @@ -119,7 +119,7 @@ function initialize_tg!( sol_x0 = sol.zero #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - device_parameters[P_ref_ix] = sol_x0[1] + set_P_ref(dynamic_device, sol_x0[1]) #Update states tg_ix = get_local_state_ix(dynamic_device, PSY.TGTypeII) tg_states = @view device_states[tg_ix] @@ -142,7 +142,7 @@ function initialize_tg!( tg = PSY.get_prime_mover(dynamic_device) #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.TGTypeI) + local_ix_params = get_local_parameter_ix(dynamic_device, PSY.GasTG) internal_params = @view device_parameters[local_ix_params] R, _, _, _, AT, Kt, V_min, V_max, D_turb = internal_params inv_R = R < eps() ? 0.0 : (1.0 / R) @@ -170,7 +170,7 @@ function initialize_tg!( sol_x0 = sol.zero #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - device_parameters[P_ref_ix] = sol_x0[1] + set_P_ref(dynamic_device, sol_x0[1]) #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] @@ -192,7 +192,7 @@ function initialize_tg!( #Get mechanical torque to SyncMach τm0 = inner_vars[τm_var] PSY.set_P_ref!(tg, τm0) - device_parameters[P_ref_ix] = τm0 + set_P_ref(dynamic_device, τm0) #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] @@ -256,7 +256,7 @@ function initialize_tg!( end #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - device_parameters[P_ref_ix] = sol_x0[1] + set_P_ref(dynamic_device, sol_x0[1]) #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] @@ -329,7 +329,7 @@ function initialize_tg!( end #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - device_parameters[P_ref_ix] = sol_x0[1] + set_P_ref(dynamic_device, sol_x0[1]) #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index 38e026622..0c7f155b9 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -1,11 +1,11 @@ function initialize_dynamic_device!( dynamic_device::DynamicWrapper{DynG}, + static::PSY.StaticInjection, initial_inner_vars::AbstractVector, parameters::AbstractVector, states::AbstractVector, ) where {DynG <: PSY.DynamicGenerator} #Obtain States - static = get_static_device(dynamic_device) #Initialize Machine and Shaft: δ and ω initialize_mach_shaft!(states, parameters, static, dynamic_device, initial_inner_vars) #Initialize extra Shaft states @@ -21,11 +21,11 @@ end function initialize_dynamic_device!( dynamic_device::DynamicWrapper{DynI}, + static::PSY.StaticInjection, initial_inner_vars::AbstractVector, parameters::AbstractVector, states::AbstractVector, ) where {DynI <: PSY.DynamicInverter} - static = get_static_device(dynamic_device) #Initialize Machine and Shaft: V and I initialize_filter!(states, parameters, static, dynamic_device, initial_inner_vars) @@ -71,8 +71,8 @@ function initialize_static_device!( I = conj(S0 / V) I_R = real(I) I_I = imag(I) - R_th = PSY.get_R_th(device.device) - X_th = PSY.get_X_th(device.device) + R_th = local_parameters[1] + X_th = local_parameters[2] Zmag = R_th^2 + X_th^2 function f!(out, x) @@ -103,11 +103,11 @@ end function initialize_dynamic_device!( dynamic_device::DynamicWrapper{PSY.PeriodicVariableSource}, + source::PSY.Source, initial_inner_vars::AbstractVector, parameters::AbstractVector, device_states::AbstractVector, ) - source = get_static_device(dynamic_device) #PowerFlow Data P0 = PSY.get_active_power(source) Q0 = PSY.get_reactive_power(source) @@ -143,15 +143,15 @@ function initialize_dynamic_device!( θ_internal = atan(sol_x0[2], sol_x0[1]) V_internal_freqs = 0.0 - V_freqs = PSY.get_internal_voltage_frequencies(get_dynamic_device(dynamic_device)) - V_coeff = PSY.get_internal_voltage_coefficients(get_dynamic_device(dynamic_device)) + V_freqs = PSY.get_internal_voltage_frequencies(get_device(dynamic_device)) + V_coeff = PSY.get_internal_voltage_coefficients(get_device(dynamic_device)) for (ix, ω) in enumerate(V_freqs) V_internal_freqs += V_coeff[ix][2] #sin(0) = 0; cos(0)=1 end θ_internal_freqs = 0.0 - θ_freqs = PSY.get_internal_angle_frequencies(get_dynamic_device(dynamic_device)) - θ_coeff = PSY.get_internal_angle_coefficients(get_dynamic_device(dynamic_device)) + θ_freqs = PSY.get_internal_angle_frequencies(get_device(dynamic_device)) + θ_coeff = PSY.get_internal_angle_coefficients(get_device(dynamic_device)) for (ix, ω) in enumerate(θ_freqs) θ_internal_freqs += θ_coeff[ix][2] #sin(0) = 0; cos(0)=1 end @@ -160,8 +160,8 @@ function initialize_dynamic_device!( device_states[1] = V_internal device_states[2] = θ_internal - PSY.set_internal_voltage_bias!(get_dynamic_device(dynamic_device), V_internal_bias) - PSY.set_internal_angle_bias!(get_dynamic_device(dynamic_device), θ_internal_bias) + PSY.set_internal_voltage_bias!(get_device(dynamic_device), V_internal_bias) + PSY.set_internal_angle_bias!(get_device(dynamic_device), θ_internal_bias) end return end @@ -192,19 +192,15 @@ end function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.SingleCageInductionMachine}, + device::PSY.StaticInjection, ::AbstractVector, device_parameters::AbstractVector, device_states::AbstractVector, ) Sbase = get_system_base_power(dynamic_wrapper) - device = get_static_device(dynamic_wrapper) # Get parameters - dynamic_device = get_dynamic_device(dynamic_wrapper) - _, - _, - _, - _, + dynamic_device = get_device(dynamic_wrapper) R_s, R_r, X_ls, @@ -292,31 +288,26 @@ function initialize_dynamic_device!( device_states[4] = sol_x0[7] # ψ_dr device_states[5] = sol_x0[8] # ωr # update τ_ref and B_sh - device_parameters[16] = sol_x0[3] # B_sh + device_parameters[12] = sol_x0[3] # B_sh PSY.set_B_shunt!(dynamic_device, sol_x0[3]) # B_sh - device_parameters[15] = sol_x0[9] # τ_m0 + device_parameters[11] = sol_x0[9] # τ_m0 PSY.set_τ_ref!(dynamic_device, sol_x0[9]) # τ_m0 - device_parameters[P_ref_ix] = sol_x0[9] # τ_m0 + set_P_ref(dynamic_wrapper, sol_x0[9]) # τ_m0 end return end function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.SimplifiedSingleCageInductionMachine}, + device::PSY.StaticInjection, ::AbstractVector, device_parameters::AbstractVector, device_states::AbstractVector, ) Sbase = get_system_base_power(dynamic_wrapper) - # Get parameters - dynamic_device = get_dynamic_device(dynamic_wrapper) - device = get_static_device(dynamic_wrapper) + dynamic_device = get_device(dynamic_wrapper) #Get parameters - _, - _, - _, - _, R_s, R_r, X_ls, @@ -407,28 +398,24 @@ function initialize_dynamic_device!( device_states[3] = sol_x0[10] # ωr # update τ_ref and B_sh PSY.set_B_shunt!(dynamic_device, sol_x0[5]) # B_sh - device_parameters[16] = sol_x0[5] # B_sh + device_parameters[12] = sol_x0[5] # B_sh PSY.set_τ_ref!(dynamic_device, sol_x0[11]) # τ_m0 - device_parameters[15] = sol_x0[11] # τ_m0 - device_parameters[P_ref_ix] = sol_x0[11] # τ_m0 + device_parameters[11] = sol_x0[11] # τ_m0 + set_P_ref(dynamic_wrapper, sol_x0[11]) # τ_m0 end return device_states end function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.CSVGN1}, + device::PSY.StaticInjection, ::AbstractVector, device_parameters::AbstractVector, device_states::AbstractVector, ) Sbase = get_system_base_power(dynamic_wrapper) - device = get_static_device(dynamic_wrapper) # Get parameters - dynamic_device = get_dynamic_device(dynamic_wrapper) - Q_ref, - V_ref, - ω_ref, - P_ref, + dynamic_device = get_device(dynamic_wrapper) K, T1, T2, @@ -442,7 +429,6 @@ function initialize_dynamic_device!( Mbase, R_th, X_th = device_parameters - # FIXME: base_power is changed to system's base_power when a CSVGN1 is attached to a Source using add_component!() # Temporarily, to avoid that, set_dynamic_injector!() could be used Rbase = Mbase @@ -456,7 +442,7 @@ function initialize_dynamic_device!( V_ref0 = V_abs - (Cbase / Sbase - Y) * 1 / K * Sbase / Mbase # update V_ref - device_parameters[V_ref_ix] = V_ref0 + set_V_ref(dynamic_wrapper, V_ref0) thy = K * (V_abs - V_ref0) vr2 = thy @@ -468,7 +454,6 @@ function initialize_dynamic_device!( if (vr2 > 1) || (vr2 < Rmin / Rbase) CRC.@ignore_derivatives @error("Regulator state vr2 = $(vr2) outside the limits") end - device_states[1] = K * (V_abs - V_ref0) # thy device_states[2] = 0.0 # vr1 device_states[3] = K * (V_abs - V_ref0) # vr2 @@ -478,20 +463,16 @@ end function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.ActiveConstantPowerLoad}, + device::PSY.StaticInjection, ::AbstractVector, device_parameters::AbstractVector, device_states::AbstractVector, ) - device = get_static_device(dynamic_wrapper) Sbase = get_system_base_power(dynamic_wrapper) - dynamic_device = get_dynamic_device(dynamic_wrapper) + dynamic_device = get_device(dynamic_wrapper) #Get parameters - Q_ref, - V_ref, - ω_ref, - P_ref, r_load, _, rf, @@ -587,20 +568,20 @@ function initialize_dynamic_device!( # update V_ref PSY.set_V_ref!(dynamic_device, V_ref0) - device_parameters[V_ref_ix] = V_ref0 - device_parameters[Q_ref_ix] = sol_x0[5] + set_V_ref(dynamic_wrapper, V_ref0) + set_Q_ref(dynamic_wrapper, sol_x0[5]) end return device_states end function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.AggregateDistributedGenerationA}, + static::PSY.StaticInjection, ::AbstractVector, device_parameters::AbstractVector, device_states::AbstractVector, ) - dynamic_device = get_dynamic_device(dynamic_wrapper) - static = get_static_device(dynamic_wrapper) + dynamic_device = get_device(dynamic_wrapper) #Get PowerFlow Data P0 = PSY.get_active_power(static) Q0 = PSY.get_reactive_power(static) @@ -671,7 +652,7 @@ function initialize_dynamic_device!( #See Note 2 on PSSE Documentation Vref0 = PSY.get_V_ref(dynamic_device) - K_qv = device_parameters[9] + K_qv = device_parameters[5] (dbd1, dbd2) = PSY.get_dbd_pnts(dynamic_device) if Vref0 == 0.0 Vref = Vmeas @@ -681,12 +662,12 @@ function initialize_dynamic_device!( Vref = Vmeas end - device_parameters[P_ref_ix] = Pref + set_P_ref(dynamic_wrapper, Pref) PSY.set_P_ref!(dynamic_device, Pref) - device_parameters[Q_ref_ix] = Qref - device_parameters[V_ref_ix] = Vref - device_parameters[ω_ref_ix] = Freq_ref + set_Q_ref(dynamic_wrapper, Qref) + set_V_ref(dynamic_wrapper, Vref) + set_ω_ref(dynamic_wrapper, Freq_ref) PSY.set_Pfa_ref!(dynamic_device, pfaref) - device_parameters[33] = pfaref + device_parameters[29] = pfaref return end diff --git a/src/initialization/inverter_components/init_filter.jl b/src/initialization/inverter_components/init_filter.jl index ca2b90b8e..1b09074ac 100644 --- a/src/initialization/inverter_components/init_filter.jl +++ b/src/initialization/inverter_components/init_filter.jl @@ -31,7 +31,7 @@ function initialize_filter!( lf, rf, cf, lg, rg = internal_params #Set parameters - ω_sys = device_parameters[ω_ref_ix] + ω_sys = get_ω_ref(dynamic_device) #To solve Vr_cnv, Vi_cnv, Ir_cnv, Ii_cnv, Vr_filter, Vi_filter function f!(out, x) diff --git a/src/initialization/inverter_components/init_frequency_estimator.jl b/src/initialization/inverter_components/init_frequency_estimator.jl index e23d7f2cd..17f3dfa23 100644 --- a/src/initialization/inverter_components/init_frequency_estimator.jl +++ b/src/initialization/inverter_components/init_frequency_estimator.jl @@ -19,7 +19,7 @@ function initialize_frequency_estimator!( local_ix_params = get_local_parameter_ix(dynamic_device, PSY.KauraPLL) internal_params = @view device_parameters[local_ix_params] _, kp_pll, ki_pll = internal_params - ω_ref = device_parameters[ω_ref_ix] + ω_ref = get_ω_ref(dynamic_device) #Get initial guess θ0_pll = atan(Vi_filter, Vr_filter) @@ -123,7 +123,7 @@ function initialize_frequency_estimator!( pll_states[3] = sol_x0[3] #Update guess of frequency estimator - inner_vars[ω_freq_estimator_var] = device_parameters[ω_ref_ix] + inner_vars[ω_freq_estimator_var] = get_ω_ref(dynamic_device) inner_vars[θ_freq_estimator_var] = sol_x0[3] end return diff --git a/src/initialization/inverter_components/init_inner.jl b/src/initialization/inverter_components/init_inner.jl index 08e6b582f..8449e1b0c 100644 --- a/src/initialization/inverter_components/init_inner.jl +++ b/src/initialization/inverter_components/init_inner.jl @@ -24,7 +24,7 @@ function initialize_inner!( Vi_filter = device_states[external_ix[6]] #Obtain inner variables for component - ω_oc = device_parameters[ω_ref_ix] + ω_oc = get_ω_ref(dynamic_device) θ0_oc = inner_vars[θ_oc_var] Vdc = inner_vars[Vdc_var] @@ -109,7 +109,7 @@ function initialize_inner!( #Assumes that angle is in second position outer_states[1] = sol_x0[1] inner_vars[θ_oc_var] = sol_x0[1] - device_parameters[V_ref_ix] = sol_x0[2] + set_V_ref(dynamic_device, sol_x0[2]) PSY.set_V_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), sol_x0[2], @@ -162,7 +162,7 @@ function initialize_inner!( Vi_filter = device_states[external_ix[6]] #Obtain inner variables for component - ω_oc = device_parameters[ω_ref_ix] + ω_oc = get_ω_ref(dynamic_device) θ0_oc = inner_vars[θ_freq_estimator_var] Vdc = inner_vars[Vdc_var] Id_cnv_ref = inner_vars[Id_oc_var] diff --git a/src/initialization/inverter_components/init_outer.jl b/src/initialization/inverter_components/init_outer.jl index 511a4d39e..90177f910 100644 --- a/src/initialization/inverter_components/init_outer.jl +++ b/src/initialization/inverter_components/init_outer.jl @@ -37,7 +37,7 @@ function initialize_outer!( Vi_cnv = inner_vars[Vi_cnv_var] θ0_oc = atan(Vi_cnv, Vr_cnv) - ω_ref = device_parameters[ω_ref_ix] + ω_ref = get_ω_ref(dynamic_device) #Obtain additional expressions p_elec_out = Ir_filter * Vr_filter + Ii_filter * Vi_filter q_elec_out = -Ii_filter * Vr_filter + Ir_filter * Vi_filter @@ -57,13 +57,13 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc inner_vars[ω_oc_var] = ω_ref - device_parameters[P_ref_ix] = p_elec_out + set_P_ref(dynamic_device, p_elec_out) PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) #Update Q_ref. Initialization assumes q_ref = q_elec_out of PF solution - device_parameters[Q_ref_ix] = q_elec_out + set_Q_ref(dynamic_device, q_elec_out) return end @@ -124,14 +124,14 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc - inner_vars[ω_oc_var] = device_parameters[ω_ref_ix] + inner_vars[ω_oc_var] = get_ω_ref(dynamic_device) #Update Q_ref. Initialization assumes q_ref = q_elec_out of PF solution - device_parameters[P_ref_ix] = p_elec_out + set_P_ref(dynamic_device, p_elec_out) PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - device_parameters[Q_ref_ix] = q_elec_out + set_Q_ref(dynamic_device, q_elec_out) end function initialize_outer!( @@ -190,14 +190,14 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc - inner_vars[ω_oc_var] = device_parameters[ω_ref_ix] + inner_vars[ω_oc_var] = get_ω_ref(dynamic_device) #Update Q_ref. Initialization assumes q_ref = q_elec_out of PF solution - device_parameters[P_ref_ix] = p_elec_out + set_P_ref(dynamic_device, p_elec_out) PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - device_parameters[Q_ref_ix] = q_elec_out + set_Q_ref(dynamic_device, q_elec_out) end function initialize_outer!( @@ -265,16 +265,16 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc - inner_vars[ω_oc_var] = device_parameters[ω_ref_ix] + inner_vars[ω_oc_var] = get_ω_ref(dynamic_device) inner_vars[Id_oc_var] = I_dq_cnv[d] inner_vars[Iq_oc_var] = I_dq_cnv[q] #Update Q_ref. Initialization assumes q_ref = q_elec_out from PF solution - device_parameters[P_ref_ix] = p_elec_out + set_P_ref(dynamic_device, p_elec_out) PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - device_parameters[Q_ref_ix] = q_elec_out + set_Q_ref(dynamic_device, q_elec_out) PSY.set_Q_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), q_elec_out, @@ -328,7 +328,7 @@ function initialize_outer!( ## Set references Vm = V_t PSY.set_Q_ref!(PSY.get_converter(dynamic_device), q_elec_out) - device_parameters[Q_ref_ix] = q_elec_out + set_Q_ref(dynamic_device, q_elec_out) PSY.set_Q_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), q_elec_out, @@ -337,15 +337,15 @@ function initialize_outer!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - device_parameters[P_ref_ix] = p_elec_out + set_P_ref(dynamic_device, p_elec_out) PSY.set_V_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), Vm, ) - device_parameters[V_ref_ix] = Vm + set_V_ref(dynamic_device, Vm) #Get Outer Controller parameters - q_ref = device_parameters[Q_ref_ix] + q_ref = get_Q_ref(dynamic_device) outer_control = PSY.get_outer_control(dynamic_device) active_power_control = PSY.get_active_power_control(outer_control) reactive_power_control = PSY.get_reactive_power_control(outer_control) @@ -376,10 +376,10 @@ function initialize_outer!( }, ) internal_params = @view device_parameters[local_ix_params] - active_n_params = get_n_params(active_power_control) + active_n_params = length(get_params(active_power_control)) active_ix_range_params = 1:active_n_params active_params = @view internal_params[active_ix_range_params] - reactive_n_params = get_n_params(reactive_power_control) + reactive_n_params = length(get_params(reactive_power_control)) reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) reactive_params = @view internal_params[reactive_ix_range_params] K_pg, diff --git a/src/models/device.jl b/src/models/device.jl index 737317764..320de43a5 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -208,7 +208,7 @@ function device!( inner_vars[Vi_inv_var] = voltage_i #Update V_ref - V_ref = device_parameters[V_ref_ix] + V_ref = get_V_ref(dynamic_device) inner_vars[V_oc_var] = V_ref #Update current inner_vars @@ -327,19 +327,19 @@ function device!( h, t, ) where {T <: ACCEPTED_REAL_TYPES} - ω_θ = PSY.get_internal_angle_frequencies(get_dynamic_device(dynamic_device)) - ω_V = PSY.get_internal_angle_frequencies(get_dynamic_device(dynamic_device)) + ω_θ = PSY.get_internal_angle_frequencies(get_device(dynamic_device)) + ω_V = PSY.get_internal_angle_frequencies(get_device(dynamic_device)) dV = 0 for (ix, A) in - enumerate(PSY.get_internal_voltage_coefficients(get_dynamic_device(dynamic_device))) + enumerate(PSY.get_internal_voltage_coefficients(get_device(dynamic_device))) t <= 0 && continue dV += ω_V[ix] * (A[1] * cos(ω_V[ix] * t) - A[2] * sin(ω_V[ix] * t)) end dθ = 0 for (ix, A) in - enumerate(PSY.get_internal_angle_coefficients(get_dynamic_device(dynamic_device))) + enumerate(PSY.get_internal_angle_coefficients(get_device(dynamic_device))) t <= 0 && continue dθ += ω_θ[ix] * (A[1] * cos(ω_θ[ix] * t) - A[2] * sin(ω_θ[ix] * t)) end @@ -351,8 +351,8 @@ function device!( output_ode[2] = dθ #update current - R_th = PSY.get_R_th(get_dynamic_device(dynamic_device)) - X_th = PSY.get_X_th(get_dynamic_device(dynamic_device)) + R_th = PSY.get_R_th(get_device(dynamic_device)) + X_th = PSY.get_X_th(get_device(dynamic_device)) Zmag = R_th^2 + X_th^2 current_r[1] += R_th * (V_R - voltage_r[1]) / Zmag + X_th * (V_I - voltage_i[1]) / Zmag #in system pu flowing out current_i[1] += R_th * (V_I - voltage_i[1]) / Zmag - X_th * (V_R - voltage_r[1]) / Zmag #in system pu flowing out @@ -823,10 +823,6 @@ function device!( ωr = device_states[5] #Get parameters - _, - _, - _, - _, R_s, R_r, X_ls, @@ -910,10 +906,6 @@ function device!( ωr = device_states[3] #Get parameters - _, - _, - _, - _, R_s, R_r, X_ls, @@ -999,10 +991,12 @@ function device!( t, ) where {T <: ACCEPTED_REAL_TYPES} Sbase = get_system_base_power(dynamic_wrapper) + V_ref = get_V_ref(dynamic_wrapper) # TODO: V_abs is the voltage magnitude on the high side of generator step-up transformer, if present. V_abs = sqrt(voltage_r^2 + voltage_i^2) if get_connection_status(dynamic_wrapper) < 1.0 + @error "NOT CONNECTED? " output_ode .= zero(T) return end @@ -1013,10 +1007,6 @@ function device!( vr2 = device_states[3] #Get parameters - Q_ref, - V_ref, - ω_ref, - P_ref, K, T1, T2, @@ -1075,7 +1065,7 @@ function device_mass_matrix_entries!( dynamic_device::DynamicWrapper{PSY.ActiveConstantPowerLoad}, ) global_index = get_global_index(dynamic_device) - device = get_dynamic_device(dynamic_device) + device = get_device(dynamic_device) bool_mm_value = PSY.get_is_filter_differential(device) f0 = get_system_base_frequency(dynamic_device) ωb = 2 * pi * f0 @@ -1115,6 +1105,7 @@ function device!( ) where {T <: ACCEPTED_REAL_TYPES} Sbase = get_system_base_power(dynamic_wrapper) f0 = get_system_base_frequency(dynamic_wrapper) + V_ref = get_V_ref(dynamic_wrapper) if get_connection_status(dynamic_wrapper) < 1.0 output_ode .= zero(T) return @@ -1145,10 +1136,6 @@ function device!( I_dq_cnv = ri_dq(θ_pll + pi / 2) * [Ir_cnv; Ii_cnv] #Get parameters - Q_ref, - V_ref, - ω_ref, - P_ref, r_load, c_dc, rf, @@ -1171,7 +1158,7 @@ function device!( # Compute DC side output Id_ref, dη_dt = pi_block(V_ref - v_dc, η, kpv, kiv) - Iq_ref = Q_ref + Iq_ref = get_Q_ref(dynamic_wrapper) # Compute AC controller expressions Vd_ref_uncomp, dγd_dt = pi_block(-Id_ref + I_dq_cnv[d], γd, kpc, kic) Vq_ref_uncomp, dγq_dt = pi_block(-Iq_ref + I_dq_cnv[q], γq, kpc, kic) @@ -1230,8 +1217,8 @@ function mass_matrix_dera_entries!( dera::DynamicWrapper{PSY.AggregateDistributedGenerationA}, global_index::ImmutableDict{Symbol, Int64}, ) - ddera = get_dynamic_device(dera) - Freq_Flag = PSY.get_Freq_Flag(get_dynamic_device(dera)) + ddera = get_device(dera) + Freq_Flag = PSY.get_Freq_Flag(get_device(dera)) if Freq_Flag == 1 mass_matrix[global_index[:Vmeas], global_index[:Vmeas]] = PSY.get_T_rv(ddera) mass_matrix[global_index[:Pmeas], global_index[:Pmeas]] = PSY.get_Tp(ddera) @@ -1262,7 +1249,7 @@ function device!( h, t, ) where {T <: ACCEPTED_REAL_TYPES} - Freq_Flag = PSY.get_Freq_Flag(get_dynamic_device(dynamic_wrapper)) + Freq_Flag = PSY.get_Freq_Flag(get_device(dynamic_wrapper)) _mdl_ode_AggregateDistributedGenerationA!( device_states, output_ode, @@ -1302,12 +1289,12 @@ function _mdl_ode_AggregateDistributedGenerationA!( sys_ω = global_vars[GLOBAL_VAR_SYS_FREQ_INDEX] Sbase = get_system_base_power(dynamic_wrapper) Vt = sqrt(voltage_r^2 + voltage_i^2) - dynamic_device = get_dynamic_device(dynamic_wrapper) + dynamic_device = get_device(dynamic_wrapper) #Obtain References (from wrapper and device) Pfa_ref = PSY.get_Pfa_ref(dynamic_device) - P_ref = device_parameters[P_ref_ix] - Q_ref = device_parameters[Q_ref_ix] - V_ref = device_parameters[V_ref_ix] + P_ref = get_P_ref(dynamic_wrapper) + Q_ref = get_Q_ref(dynamic_wrapper) + V_ref = get_V_ref(dynamic_wrapper) #Get flags Pf_Flag = PSY.get_Pf_Flag(dynamic_device) @@ -1325,10 +1312,6 @@ function _mdl_ode_AggregateDistributedGenerationA!( Iq_cmd = Iq #Get parameters - Q_ref, - V_ref, - ω_ref, - P_ref, T_rv, Trf, dbd1, @@ -1447,13 +1430,13 @@ function _mdl_ode_AggregateDistributedGenerationA!( sys_ω = global_vars[GLOBAL_VAR_SYS_FREQ_INDEX] Sbase = get_system_base_power(dynamic_wrapper) Vt = sqrt(voltage_r^2 + voltage_i^2) - dynamic_device = get_dynamic_device(dynamic_wrapper) + dynamic_device = get_device(dynamic_wrapper) #Obtain References (from wrapper and device) Pfa_ref = PSY.get_Pfa_ref(dynamic_device) - P_ref = device_parameters[P_ref_ix] - Q_ref = device_parameters[Q_ref_ix] - V_ref = device_parameters[V_ref_ix] - ω_ref = device_parameters[ω_ref_ix] + P_ref = get_P_ref(dynamic_wrapper) + Q_ref = get_Q_ref(dynamic_wrapper) + V_ref = get_V_ref(dynamic_wrapper) + ω_ref = get_ω_ref(dynamic_wrapper) #Get flags Pf_Flag = PSY.get_Pf_Flag(dynamic_device) @@ -1474,10 +1457,6 @@ function _mdl_ode_AggregateDistributedGenerationA!( Iq_cmd = Iq #Get parameters - Q_ref, - V_ref, - ω_ref, - P_ref, T_rv, Trf, dbd1, diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index 6b5eab612..d75eeefd0 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -72,7 +72,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Update Vf voltage on inner vars. In AVRFixed, Vf = V_ref - inner_vars[Vf_var] = device_parameters[V_ref_ix] + inner_vars[Vf_var] = get_V_ref(dynamic_device) return end @@ -88,7 +88,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V_ref = device_parameters[V_ref_ix] + V_ref = get_V_ref(dynamic_device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.AVRSimple) @@ -125,7 +125,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = device_parameters[V_ref_ix] + V0_ref = get_V_ref(dynamic_device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeI) @@ -179,7 +179,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = device_parameters[V_ref_ix] + V0_ref = get_V_ref(dynamic_device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeII) @@ -244,7 +244,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V_ref = device_parameters[V_ref_ix] + V_ref = get_V_ref(dynamic_device) #Obtain avr avr = PSY.get_avr(dynamic_device) @@ -325,7 +325,7 @@ function mdl_avr_ode!( t, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = device_parameters[V_ref_ix] + V0_ref = get_V_ref(dynamic_device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.SEXS) @@ -371,7 +371,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = device_parameters[V_ref_ix] + V0_ref = get_V_ref(dynamic_device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.SCRX) # @@ -434,7 +434,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = device_parameters[V_ref_ix] + V0_ref = get_V_ref(dynamic_device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.EXST1) @@ -500,7 +500,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V_ref = device_parameters[V_ref_ix] + V_ref = get_V_ref(dynamic_device) #Obtain avr avr = PSY.get_avr(dynamic_device) @@ -577,7 +577,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = device_parameters[V_ref_ix] + V0_ref = get_V_ref(dynamic_device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.ESST1A) diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index fb059af7e..41cee7d33 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -42,7 +42,7 @@ function mdl_tg_ode!( local_ix_params = get_local_parameter_ix(device, PSY.TGFixed) internal_params = @view device_parameters[local_ix_params] efficiency = internal_params[1] - P_ref = device_parameters[P_ref_ix] + P_ref = get_P_ref(device) inner_vars[τm_var] = P_ref * efficiency return end @@ -59,8 +59,8 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - ω_ref = device_parameters[ω_ref_ix] - P_ref = device_parameters[P_ref_ix] + ω_ref = get_ω_ref(device) + P_ref = get_P_ref(device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.TGTypeI) @@ -112,8 +112,8 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - ω_ref = device_parameters[ω_ref_ix] - P_ref = device_parameters[P_ref_ix] + ω_ref = get_ω_ref(device) + P_ref = get_P_ref(device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.TGTypeII) @@ -159,7 +159,7 @@ function mdl_tg_ode!( #Obtain TG tg = PSY.get_prime_mover(device) #Obtain references - P_ref = device_parameters[P_ref_ix] + P_ref = get_P_ref(device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, typeof(tg)) @@ -215,7 +215,7 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - P_ref = device_parameters[P_ref_ix] + P_ref = get_P_ref(device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.GasTG) @@ -270,8 +270,8 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - P_ref = device_parameters[P_ref_ix] - ω_ref = device_parameters[ω_ref_ix] + P_ref = get_P_ref(device) + ω_ref = get_ω_ref(device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.HydroTurbineGov) @@ -342,7 +342,7 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - P_ref = device_parameters[P_ref_ix] + P_ref = get_P_ref(device) #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.DEGOV) diff --git a/src/models/inverter_models/outer_control_models.jl b/src/models/inverter_models/outer_control_models.jl index 828ff711d..bc18a6c06 100644 --- a/src/models/inverter_models/outer_control_models.jl +++ b/src/models/inverter_models/outer_control_models.jl @@ -47,8 +47,8 @@ function _mdl_ode_RE_active_controller_AB!( } #Obtain external parameters - p_ref = device_parameters[P_ref_ix] - ω_ref = device_parameters[ω_ref_ix] + p_ref = get_P_ref(dynamic_device) + ω_ref = get_ω_ref(dynamic_device) # To do: Obtain proper frequency for a plant. For now using the system frequency. ω_plant = ω_sys @@ -61,7 +61,7 @@ function _mdl_ode_RE_active_controller_AB!( }, ) internal_params = @view device_parameters[local_ix_params] - active_n_params = get_n_params(active_power_control) + active_n_params = length(get_params(active_power_control)) active_ix_range_params = 1:active_n_params active_params = @view internal_params[active_ix_range_params] K_pg, @@ -156,7 +156,7 @@ function _mdl_ode_RE_active_controller_AB!( } #Obtain external parameters - p_ref = device_parameters[P_ref_ix] + p_ref = get_P_ref(dynamic_device) #Obtain additional Active Power Controller parameters local_ix_params = get_local_parameter_ix( dynamic_device, @@ -166,7 +166,7 @@ function _mdl_ode_RE_active_controller_AB!( }, ) internal_params = @view device_parameters[local_ix_params] - active_n_params = get_n_params(active_power_control) + active_n_params = length(get_params(active_power_control)) active_ix_range_params = 1:active_n_params active_params = @view internal_params[active_ix_range_params] K_pg, @@ -244,7 +244,7 @@ function _mdl_ode_RE_reactive_controller_AB!( } #Obtain external parameters - q_ref = device_parameters[Q_ref_ix] + q_ref = get_Q_ref(dynamic_device) # Get Reactive Controller parameters local_ix_params = get_local_parameter_ix( @@ -257,8 +257,8 @@ function _mdl_ode_RE_reactive_controller_AB!( outer_control = PSY.get_outer_control(dynamic_device) active_power_control = PSY.get_active_power_control(outer_control) internal_params = @view device_parameters[local_ix_params] - active_n_params = get_n_params(active_power_control) - reactive_n_params = get_n_params(reactive_power_control) + active_n_params = length(get_params(active_power_control)) + reactive_n_params = length(get_params(reactive_power_control)) reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) reactive_params = @view internal_params[reactive_ix_range_params] T_fltr, @@ -350,7 +350,7 @@ function _mdl_ode_RE_reactive_controller_AB!( L <: Union{Nothing, PSY.InverterLimiter}, } #Obtain external parameters - q_ref = device_parameters[Q_ref_ix] + q_ref = get_Q_ref(dynamic_device) outer_control = PSY.get_outer_control(dynamic_device) active_power_control = PSY.get_active_power_control(outer_control) # Get Reactive Controller parameters @@ -362,8 +362,8 @@ function _mdl_ode_RE_reactive_controller_AB!( }, ) internal_params = @view device_parameters[local_ix_params] - active_n_params = get_n_params(active_power_control) - reactive_n_params = get_n_params(reactive_power_control) + active_n_params = length(get_params(active_power_control)) + reactive_n_params = length(get_params(reactive_power_control)) reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) reactive_params = @view internal_params[reactive_ix_range_params] T_fltr, @@ -453,7 +453,7 @@ function _mdl_ode_RE_reactive_controller_AB!( L <: Union{Nothing, PSY.InverterLimiter}, } #Obtain external parameters - V_ref = device_parameters[V_ref_ix] + V_ref = get_V_ref(dynamic_device) #Obtain regulated voltage (assumed to be terminal voltage) V_reg = sqrt(inner_vars[Vr_inv_var]^2 + inner_vars[Vi_inv_var]^2) @@ -473,8 +473,8 @@ function _mdl_ode_RE_reactive_controller_AB!( internal_params = @view device_parameters[local_ix_params] outer_control = PSY.get_outer_control(dynamic_device) active_power_control = PSY.get_active_power_control(outer_control) - active_n_params = get_n_params(active_power_control) - reactive_n_params = get_n_params(reactive_power_control) + active_n_params = length(get_params(active_power_control)) + reactive_n_params = length(get_params(reactive_power_control)) reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) reactive_params = @view internal_params[reactive_ix_range_params] T_fltr, @@ -582,7 +582,7 @@ function _mdl_ode_RE_reactive_controller_AB!( L <: Union{Nothing, PSY.InverterLimiter}, } #Obtain external parameters - V_ref = device_parameters[V_ref_ix] + V_ref = get_V_ref(dynamic_device) #Obtain regulated voltage (assumed to be terminal voltage) V_reg = sqrt(inner_vars[Vr_inv_var]^2 + inner_vars[Vi_inv_var]^2) @@ -601,8 +601,8 @@ function _mdl_ode_RE_reactive_controller_AB!( internal_params = @view device_parameters[local_ix_params] outer_control = PSY.get_outer_control(dynamic_device) active_power_control = PSY.get_active_power_control(outer_control) - active_n_params = get_n_params(active_power_control) - reactive_n_params = get_n_params(reactive_power_control) + active_n_params = length(get_params(active_power_control)) + reactive_n_params = length(get_params(reactive_power_control)) reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) reactive_params = @view internal_params[reactive_ix_range_params] T_fltr, @@ -718,10 +718,10 @@ function mdl_outer_ode!( internal_params = @view device_parameters[local_ix_params] Ta, kd, kω, kq, ωf = internal_params - q_ref = device_parameters[Q_ref_ix] - V_ref = device_parameters[V_ref_ix] - ω_ref = device_parameters[ω_ref_ix] - p_ref = device_parameters[P_ref_ix] + q_ref = get_Q_ref(dynamic_device) + V_ref = get_V_ref(dynamic_device) + ω_ref = get_ω_ref(dynamic_device) + p_ref = get_P_ref(dynamic_device) f0 = get_system_base_frequency(dynamic_device) ωb = 2 * pi * f0 #Rated angular frequency @@ -810,10 +810,10 @@ function mdl_outer_ode!( ωf = PSY.get_ωf(reactive_power_control) #Reactive power filter cutoff frequency #Obtain external parameters - p_ref = device_parameters[P_ref_ix] - ω_ref = device_parameters[ω_ref_ix] - V_ref = device_parameters[V_ref_ix] - q_ref = device_parameters[Q_ref_ix] + p_ref = get_P_ref(dynamic_device) + ω_ref = get_ω_ref(dynamic_device) + V_ref = get_V_ref(dynamic_device) + q_ref = get_Q_ref(dynamic_device) #Obtain indices for component w/r to device local_ix = get_local_state_ix( @@ -904,9 +904,9 @@ function mdl_outer_ode!( k2 = PSY.get_k2(reactive_power_control) #Obtain external parameters - p_ref = device_parameters[P_ref_ix] - V_ref = device_parameters[V_ref_ix] - q_ref = device_parameters[Q_ref_ix] + p_ref = get_P_ref(dynamic_device) + V_ref = get_V_ref(dynamic_device) + q_ref = get_Q_ref(dynamic_device) #Obtain indices for component w/r to device local_ix = get_local_state_ix( @@ -1006,8 +1006,8 @@ function mdl_outer_ode!( ωf = PSY.get_ωf(reactive_power_control) #Reactive power filter cutoff frequency #Obtain external parameters - p_ref = device_parameters[P_ref_ix] - q_ref = device_parameters[Q_ref_ix] + p_ref = get_P_ref(dynamic_device) + q_ref = get_Q_ref(dynamic_device) #Obtain indices for component w/r to device local_ix = get_local_state_ix( diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index 6497aa57d..c310cde85 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -1,19 +1,52 @@ +struct ParamsMetadata + symbol::Symbol + in_mass_matrix::Bool + in_network::Bool + impacts_ic::Bool + impacts_pf::Bool +end +get_params_symbol(x) = [metadata.symbol for metadata in get_params_metadata(x)] + +# TODO - temporary for dynamic components that have not yet been modified to use parameters. +function get_params(x::PSY.Device) + @warn "Parameters not yet defined for device: $(typeof(x))" + Float64[] +end +function get_params(x::T) where {T <: PSY.DynamicComponent} + @warn "Parameters not yet defined for dynamic component: $(typeof(x))" + Float64[] +end +get_params_metadata(::T) where {T <: PSY.DynamicComponent} = ParamsMetadata[] +get_params(::PSY.ActivePowerControl) = Float64[] +get_params_metadata(::PSY.ActivePowerControl) = ParamsMetadata[] +get_params(::PSY.ReactivePowerControl) = Float64[] +get_params_metadata(::PSY.ReactivePowerControl) = ParamsMetadata[] get_params( d::DynamicWrapper{T}, -) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} = - vcat(get_params(get_static_device(d)), get_params(get_dynamic_device(d))) -get_params_symbol( +) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} = get_params(get_device(d)) +get_params_metadata( d::DynamicWrapper{T}, ) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} = - vcat(:Q_ref, get_params_symbol(get_dynamic_device(d))) -get_params(d::DynamicWrapper) = get_params(get_dynamic_device(d)) + get_params_metadata(get_device(d)) + +get_params(d::DynamicWrapper) = get_params(get_device(d)) +get_params_metadata(d::DynamicWrapper) = get_params_metadata(get_device(d)) + get_params(d::StaticWrapper) = get_params(get_device(d)) -get_n_params(x::BranchWrapper) = get_n_params(get_branch(x)) -get_params(x::BranchWrapper) = get_params(PSY.get_branch(get_branch(x))) -get_n_params(x::PSY.DynamicBranch) = get_n_params(PSY.get_branch(x)) -get_n_params(x::PSY.Line) = 2 +get_params_metadata(d::StaticWrapper) = get_params_metadata(get_device(d)) + +get_params(x::BranchWrapper) = get_params(get_branch(x)) +get_params_metadata(x::BranchWrapper) = get_params_metadata(get_branch(x)) + +get_params(x::PSY.DynamicBranch) = get_params(PSY.get_branch(x)) +get_params_metadata(x::PSY.DynamicBranch) = get_params_metadata(PSY.get_branch(x)) + get_params(x::PSY.Line) = [PSY.get_r(x), PSY.get_x(x)] +get_params_metadata(::PSY.Line) = [ + ParamsMetadata(:r, false, true, true, true), + ParamsMetadata(:x, false, true, true, true), +] function get_params(d::StaticLoadWrapper) loads = get_loads(d) @@ -41,37 +74,22 @@ function get_params(d::StaticLoadWrapper) Q_power += PSY.get_constant_reactive_power(ld) * base_power_conversion end end - return [V_ref, Θ_ref, P_power, P_current, P_impedance, Q_power, Q_current, Q_impedance] end +get_params_metadata(::StaticLoadWrapper) = [ + ParamsMetadata(:V_ref, false, false, true, true), + ParamsMetadata(:Θ_ref, false, false, true, true), + ParamsMetadata(:P_power, false, false, true, true), + ParamsMetadata(:P_current, false, false, true, true), + ParamsMetadata(:P_impedance, false, false, true, true), + ParamsMetadata(:Q_power, false, false, true, true), + ParamsMetadata(:Q_current, false, false, true, true), + ParamsMetadata(:Q_impedance, false, false, true, true), +] -# TODO - temporary for Dynamic components that have not yet been modified to use parameters. -# Allows the -get_n_params(x::PSY.DynamicComponent) = 0 -get_params(::PSY.DynamicComponent) = Float64[] -get_params_symbol(::PSY.DynamicComponent) = Symbol[] -get_n_params(x::PSY.ActivePowerControl) = 0 -get_params(::PSY.ActivePowerControl) = Float64[] -get_params_symbol(::PSY.ActivePowerControl) = Symbol[] -get_n_params(x::PSY.ReactivePowerControl) = 0 -get_params(::PSY.ReactivePowerControl) = Float64[] -get_params_symbol(::PSY.ReactivePowerControl) = Symbol[] - -get_n_params(g::PSY.DynamicInverter) = - 3 + get_n_params(PSY.get_converter(g)) + - get_n_params(PSY.get_outer_control(g)) + get_n_params(PSY.get_inner_control(g)) + - get_n_params(PSY.get_dc_source(g)) + get_n_params(PSY.get_freq_estimator(g)) + - get_n_params(PSY.get_filter(g)) - -#INVERTERS +########### INVERTERS ############# function get_params(g::PSY.DynamicInverter) - refs = [ - PSY.get_V_ref(g), - PSY.get_ω_ref(g), - PSY.get_P_ref(g), - ] vcat( - refs, get_params(PSY.get_converter(g)), get_params(PSY.get_outer_control(g)), get_params(PSY.get_inner_control(g)), @@ -80,83 +98,95 @@ function get_params(g::PSY.DynamicInverter) get_params(PSY.get_filter(g)), ) end -get_params_symbol(g::PSY.DynamicInverter) = vcat( - [:V_ref, :ω_ref, :P_ref], - get_params_symbol(PSY.get_converter(g)), - get_params_symbol(PSY.get_outer_control(g)), - get_params_symbol(PSY.get_inner_control(g)), - get_params_symbol(PSY.get_dc_source(g)), - get_params_symbol(PSY.get_freq_estimator(g)), - get_params_symbol(PSY.get_filter(g)), -) +function get_params_metadata(g::PSY.DynamicInverter) + vcat( + get_params_metadata(PSY.get_converter(g)), + get_params_metadata(PSY.get_outer_control(g)), + get_params_metadata(PSY.get_inner_control(g)), + get_params_metadata(PSY.get_dc_source(g)), + get_params_metadata(PSY.get_freq_estimator(g)), + get_params_metadata(PSY.get_filter(g)), + ) +end #FILTERS -get_n_params(x::PSY.LCLFilter) = 5 get_params(x::PSY.LCLFilter) = [PSY.get_lf(x), PSY.get_rf(x), PSY.get_cf(x), PSY.get_lg(x), PSY.get_rg(x)] -get_params_symbol(::PSY.LCLFilter) = - [:lf_Filter, :rf_Filter, :cf_Filter, :lg_Filter, :rg_Filter] - -get_n_params(x::PSY.RLFilter) = 2 +get_params_metadata(::PSY.LCLFilter) = [ + ParamsMetadata(:lf_Filter, true, false, true, false), + ParamsMetadata(:rf_Filter, false, false, true, false), + ParamsMetadata(:cf_Filter, true, false, true, false), + ParamsMetadata(:lg_Filter, true, false, true, false), + ParamsMetadata(:rg_Filter, false, false, true, false), +] get_params(x::PSY.RLFilter) = [PSY.get_rf(x), PSY.get_lf(x)] -get_params_symbol(::PSY.RLFilter) = [:rf_Filter, :lf_Filter] +get_params_metadata(::PSY.RLFilter) = [ + ParamsMetadata(:rf_Filter, false, false, true, false), + ParamsMetadata(:lf_Filter, false, false, true, false), +] + #OUTER CONTROL -get_n_params(x::PSY.OuterControl) = - get_n_params(PSY.get_active_power_control(x)) + - get_n_params(PSY.get_reactive_power_control(x)) get_params(x::PSY.OuterControl) = vcat( get_params(PSY.get_active_power_control(x)), get_params(PSY.get_reactive_power_control(x)), ) -get_params_symbol(x::PSY.OuterControl) = vcat( - get_params_symbol(PSY.get_active_power_control(x)), - get_params_symbol(PSY.get_reactive_power_control(x)), +get_params_metadata(x::PSY.OuterControl) = vcat( + get_params_metadata(PSY.get_active_power_control(x)), + get_params_metadata(PSY.get_reactive_power_control(x)), ) #ACTIVE POWER CONTROL -get_n_params(::PSY.VirtualInertia) = 3 get_params(x::PSY.VirtualInertia) = [PSY.get_Ta(x), PSY.get_kd(x), PSY.get_kω(x)] -get_params_symbol(::PSY.VirtualInertia) = - [:Ta_OuterControl, :kd_OuterControl, :kω_OuterControl] - -get_n_params(::PSY.ActiveRenewableControllerAB) = 17 -get_params(x::PSY.ActiveRenewableControllerAB) = - [PSY.get_K_pg(x), - PSY.get_K_ig(x), - PSY.get_T_p(x), - PSY.get_fdbd_pnts(x)[1], - PSY.get_fdbd_pnts(x)[2], - PSY.get_fe_lim(x)[1], - PSY.get_fe_lim(x)[2], - PSY.get_P_lim(x)[1], - PSY.get_P_lim(x)[2], - PSY.get_T_g(x), - PSY.get_D_dn(x), - PSY.get_D_up(x), - PSY.get_dP_lim(x)[1], - PSY.get_dP_lim(x)[2], - PSY.get_P_lim_inner(x)[1], - PSY.get_P_lim_inner(x)[2], - PSY.get_T_pord(x)] -get_params_symbol(::PSY.ActiveRenewableControllerAB) = [:K_pg_OuterControl, - :K_ig_OuterControl, - :T_p_ap_OuterControl, #modified to make unique - :fdbd1_OuterControl, - :fdbd2_OuterControl, - :fe_min_OuterControl, - :fe_max_OuterControl, - :P_min_OuterControl, - :P_max_OuterControl, - :T_g_ap_OuterControl, #modified to make unique - :D_dn_OuterControl, - :D_up_OuterControl, - :dP_min_OuterControl, - :dP_max_OuterControl, - :P_min_inner_OuterControl, - :P_max_inner_OuterControl, - :T_pord_OuterControl] +get_params_metadata(::PSY.VirtualInertia) = [ + ParamsMetadata(:Ta_ActivePowerControl, false, false, false, false), + ParamsMetadata(:kd_ActivePowerControl, false, false, false, false), + ParamsMetadata(:kω_ActivePowerControl, false, false, false, false), +] +get_params(x::PSY.ActiveRenewableControllerAB) = [ + PSY.get_K_pg(x), + PSY.get_K_ig(x), + PSY.get_T_p(x), + PSY.get_fdbd_pnts(x)[1], + PSY.get_fdbd_pnts(x)[2], + PSY.get_fe_lim(x)[1], + PSY.get_fe_lim(x)[2], + PSY.get_P_lim(x)[1], + PSY.get_P_lim(x)[2], + PSY.get_T_g(x), + PSY.get_D_dn(x), + PSY.get_D_up(x), + PSY.get_dP_lim(x)[1], + PSY.get_dP_lim(x)[2], + PSY.get_P_lim_inner(x)[1], + PSY.get_P_lim_inner(x)[2], + PSY.get_T_pord(x)] +get_params_metadata(::PSY.ActiveRenewableControllerAB) = [ + ParamsMetadata(:K_pg_ActivePowerControl, false, false, false, false), + ParamsMetadata(:K_ig_ActivePowerControl, false, false, true, false), + ParamsMetadata(:T_p_ActivePowerControl, false, false, true, false), + ParamsMetadata(:fdbd1_ActivePowerControl, false, false, false, false), + ParamsMetadata(:fdbd2_ActivePowerControl, false, false, false, false), + ParamsMetadata(:fe_min_ActivePowerControl, false, false, false, false), + ParamsMetadata(:fe_max_ActivePowerControl, false, false, false, false), + ParamsMetadata(:P_min_ActivePowerControl, false, false, false, false), + ParamsMetadata(:P_max_ActivePowerControl, false, false, false, false), + ParamsMetadata(:T_g_ap_ActivePowerControl, false, false, false, false), + ParamsMetadata(:D_dn_ActivePowerControl, false, false, false, false), + ParamsMetadata(:D_up_ActivePowerControl, false, false, false, false), + ParamsMetadata(:dP_min_ActivePowerControl, false, false, false, false), + ParamsMetadata(:dP_max_ActivePowerControl, false, false, false, false), + ParamsMetadata(:P_min_inner_ActivePowerControl, false, false, false, false), + ParamsMetadata(:P_max_inner_ActivePowerControl, false, false, false, false), + ParamsMetadata(:T_pord_ActivePowerControl, false, false, false, false), +] -get_n_params(::PSY.ReactiveRenewableControllerAB) = 22 -get_params(x::PSY.ReactiveRenewableControllerAB) = [PSY.get_T_fltr(x), +#REACTIVE POWER CONTROL +get_params(x::PSY.ReactivePowerDroop) = [PSY.get_kq(x), PSY.get_ωf(x)] +get_params_metadata(x::PSY.ReactivePowerDroop) = [ + ParamsMetadata(:kq_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:ωf_ReactivePowerControl, false, false, false, false), +] +get_params(x::PSY.ReactiveRenewableControllerAB) = [ + PSY.get_T_fltr(x), PSY.get_K_p(x), PSY.get_K_i(x), PSY.get_T_ft(x), @@ -177,102 +207,110 @@ get_params(x::PSY.ReactiveRenewableControllerAB) = [PSY.get_T_fltr(x), PSY.get_V_lim(x)[1], PSY.get_V_lim(x)[2], PSY.get_K_qp(x), - PSY.get_K_qi(x)] -get_params_symbol(::PSY.ReactiveRenewableControllerAB) = [:T_fltr_OuterControl, - :K_p_OuterControl, - :K_i_OuterControl, - :T_ft_OuterControl, - :T_fv_OuterControl, - :V_frz_OuterControl, - :R_c_OuterControl, - :X_c_OuterControl, - :K_c_OuterControl, - :e_min_OuterControl, - :e_max_OuterControl, - :dbd_pnts1_OuterControl, - :dbd_pnts2_OuterControl, - :Q_min_OuterControl, - :Q_max_OuterControl, - :T_p_OuterControl, - :Q_min_inner_OuterControl, - :Q_max_inner_OuterControl, - :V_min_OuterControl, - :V_max_OuterControl, - :K_qp_OuterControl, - :K_qi_OuterControl] + PSY.get_K_qi(x), +] +get_params_metadata(::PSY.ReactiveRenewableControllerAB) = [ + ParamsMetadata(:T_fltr_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:K_p_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:K_i_ReactivePowerControl, false, false, true, false), + ParamsMetadata(:T_ft_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:T_fv_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:V_frz_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:R_c_ReactivePowerControl, false, false, true, false), + ParamsMetadata(:X_c_ReactivePowerControl, false, false, true, false), + ParamsMetadata(:K_c_ReactivePowerControl, false, false, true, false), + ParamsMetadata(:e_min_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:e_max_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:dbd_pnts1_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:dbd_pnts2_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:Q_min_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:Q_max_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:T_p_ReactivePowerControl, false, false, true, false), + ParamsMetadata(:Q_min_inner_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:Q_max_inner_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:V_min_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:V_max_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:K_qp_ReactivePowerControl, false, false, false, false), + ParamsMetadata(:K_qi_ReactivePowerControl, false, false, true, false), +] -#REACTIVE POWER CONTROL -get_n_params(::PSY.ReactivePowerDroop) = 2 -get_params(x::PSY.ReactivePowerDroop) = [PSY.get_kq(x), PSY.get_ωf(x)] -get_params_symbol(x::PSY.ReactivePowerDroop) = [:kq_OuterControl, :ωf_OuterControl] #INNER CONTROL -get_n_params(::PSY.VoltageModeControl) = 10 -get_params(x::PSY.VoltageModeControl) = - [PSY.get_kpv(x), PSY.get_kiv(x), PSY.get_kffv(x), PSY.get_rv(x), PSY.get_lv(x), - PSY.get_kpc(x), PSY.get_kic(x), PSY.get_kffi(x), PSY.get_ωad(x), PSY.get_kad(x)] -get_params_symbol(x::PSY.VoltageModeControl) = - [ - :kpv_OuterControl, - :kiv_OuterControl, - :kffv_OuterControl, - :rv_OuterControl, - :lv_OuterControl, - :kpc_OuterControl, - :kic_OuterControl, - :kffi_OuterControl, - :ωad_OuterControl, - :kad_OuterControl, - ] - -get_n_params(::PSY.RECurrentControlB) = 13 -get_params(x::PSY.RECurrentControlB) = - [ - PSY.get_Vdip_lim(x)[1], - PSY.get_Vdip_lim(x)[2], - PSY.get_T_rv(x), - PSY.get_dbd_pnts(x)[1], - PSY.get_dbd_pnts(x)[2], - PSY.get_K_qv(x), - PSY.get_Iqinj_lim(x)[1], - PSY.get_Iqinj_lim(x)[2], - PSY.get_V_ref0(x), - PSY.get_K_vp(x), - PSY.get_K_vi(x), - PSY.get_T_iq(x), - PSY.get_I_max(x)] -get_params_symbol(x::PSY.RECurrentControlB) = - [:Vdip_min_OuterControl, - :Vdip_max_OuterControl, - :T_rv_OuterControl, - :dbd_pnts_1_OuterControl, - :dbd_pnts_2_OuterControl, - :K_qv_OuterControl, - :Iqinj_min_OuterControl, - :Iqinj_max_OuterControl, - :V_ref0_OuterControl, - :K_vp_OuterControl, - :K_vi_OuterControl, - :T_iq_OuterControl, - :I_max_OuterControl] +get_params(x::PSY.VoltageModeControl) = [ + PSY.get_kpv(x), + PSY.get_kiv(x), + PSY.get_kffv(x), + PSY.get_rv(x), + PSY.get_lv(x), + PSY.get_kpc(x), + PSY.get_kic(x), + PSY.get_kffi(x), + PSY.get_ωad(x), + PSY.get_kad(x), +] +get_params_metadata(::PSY.VoltageModeControl) = [ + ParamsMetadata(:kpv_InnerControl, false, false, true, false), + ParamsMetadata(:kiv_InnerControl, false, false, true, false), + ParamsMetadata(:kffv_InnerControl, false, false, true, false), + ParamsMetadata(:rv_InnerControl, false, false, true, false), + ParamsMetadata(:lv_InnerControl, false, false, true, false), + ParamsMetadata(:kpc_InnerControl, false, false, true, false), + ParamsMetadata(:kic_InnerControl, false, false, true, false), + ParamsMetadata(:kffi_InnerControl, false, false, true, false), + ParamsMetadata(:ωad_InnerControl, false, false, false, false), + ParamsMetadata(:kad_InnerControl, false, false, true, false), +] +get_params(x::PSY.RECurrentControlB) = [ + PSY.get_Vdip_lim(x)[1], + PSY.get_Vdip_lim(x)[2], + PSY.get_T_rv(x), + PSY.get_dbd_pnts(x)[1], + PSY.get_dbd_pnts(x)[2], + PSY.get_K_qv(x), + PSY.get_Iqinj_lim(x)[1], + PSY.get_Iqinj_lim(x)[2], + PSY.get_V_ref0(x), + PSY.get_K_vp(x), + PSY.get_K_vi(x), + PSY.get_T_iq(x), + PSY.get_I_max(x), +] +get_params_metadata(::PSY.RECurrentControlB) = [ + ParamsMetadata(:Vdip_min_InnerControl, false, false, false, false), + ParamsMetadata(:Vdip_max_InnerControl, false, false, false, false), + ParamsMetadata(:T_rv_InnerControl, true, false, false, false), + ParamsMetadata(:dbd_pnts_1_InnerControl, false, false, false, false), + ParamsMetadata(:dbd_pnts_2_InnerControl, false, false, false, false), + ParamsMetadata(:K_qv_InnerControl, false, false, false, false), + ParamsMetadata(:Iqinj_min_InnerControl, false, false, false, false), + ParamsMetadata(:Iqinj_max_InnerControl, false, false, false, false), + ParamsMetadata(:V_ref0_InnerControl, false, false, true, false), + ParamsMetadata(:K_vp_InnerControl, false, false, false, false), + ParamsMetadata(:K_vi_InnerControl, false, false, true, false), + ParamsMetadata(:T_iq_InnerControl, true, false, false, false), + ParamsMetadata(:I_max_InnerControl, false, false, false, false), +] #DC SOURCE -get_n_params(::PSY.FixedDCSource) = 1 get_params(x::PSY.FixedDCSource) = [PSY.get_voltage(x)] -get_params_symbol(x::PSY.FixedDCSource) = [:voltage_DCSource] +get_params_metadata(::PSY.FixedDCSource) = + [ParamsMetadata(:voltage_DCSource, false, false, false, false)] + #FREQ ESTIMATOR -get_n_params(::PSY.KauraPLL) = 3 get_params(x::PSY.KauraPLL) = [PSY.get_ω_lp(x), PSY.get_kp_pll(x), PSY.get_ki_pll(x)] -get_params_symbol(::PSY.KauraPLL) = - [:ω_lp_FrequencyEstimator, :kp_pll_FrequencyEstimator, :ki_pll_FrequencyEstimator] -get_n_params(::PSY.FixedFrequency) = 1 +get_params_metadata(::PSY.KauraPLL) = [ + ParamsMetadata(:ω_lp_FrequencyEstimator, false, false, false, false) + ParamsMetadata(:kp_pll_FrequencyEstimator, false, false, true, false) + ParamsMetadata(:ki_pll_FrequencyEstimator, false, false, true, false) +] get_params(x::PSY.FixedFrequency) = [PSY.get_frequency(x)] -get_params_symbol(::PSY.FixedFrequency) = [:frequency_FrequencyEstimator] +get_params_metadata(::PSY.FixedFrequency) = + [ParamsMetadata(:frequency_FrequencyEstimator, false, false, false, false)] + #CONVERTER -get_n_params(::PSY.AverageConverter) = 0 -get_params(x::PSY.AverageConverter) = Float64[] -get_params_symbol(::PSY.AverageConverter) = Symbol[] -get_n_params(x::PSY.RenewableEnergyConverterTypeA) = 17 -get_params(x::PSY.RenewableEnergyConverterTypeA) = [PSY.get_T_g(x), +get_params(::PSY.AverageConverter) = Float64[] +get_params_metadata(::PSY.AverageConverter) = ParamsMetadata[] +get_params(x::PSY.RenewableEnergyConverterTypeA) = [ + PSY.get_T_g(x), PSY.get_Rrpwr(x), PSY.get_Brkpt(x), PSY.get_Zerox(x), @@ -288,39 +326,31 @@ get_params(x::PSY.RenewableEnergyConverterTypeA) = [PSY.get_T_g(x), PSY.get_Accel(x), PSY.get_Q_ref(x), PSY.get_R_source(x), - PSY.get_X_source(x)] -get_params_symbol(::PSY.RenewableEnergyConverterTypeA) = [:T_g_Converter, - :Rrpwr_Converter, - :Brkpt_Converter, - :Zerox_Converter, - :Lvpl1_Converter, - :Vo_lim_Converter, - :Lv_pnt0_Converter, - :Lv_pnt1_Converter, - :Io_lim_Converter, - :T_fltr_cnv_Converter, #modified to make unique - :K_hv_Converter, - :Iqr_min_Converter, - :Iqr_max_Converter, - :Accel_Converter, - :Q_ref_cnv_Converter, #modified to make unique - :R_source_Converter, - :X_source_Converter] + PSY.get_X_source(x), +] +get_params_metadata(::PSY.RenewableEnergyConverterTypeA) = [ + ParamsMetadata(:T_g_Converter, false, false, false, false) + ParamsMetadata(:Rrpwr_Converter, false, false, false, false) + ParamsMetadata(:Brkpt_Converter, false, false, false, false) + ParamsMetadata(:Zerox_Converter, false, false, false, false) + ParamsMetadata(:Lvpl1_Converter, false, false, false, false) + ParamsMetadata(:Vo_lim_Converter, false, false, true, false) + ParamsMetadata(:Lv_pnt0_Converter, false, false, false, false) + ParamsMetadata(:Lv_pnt1_Converter, false, false, true, false) + ParamsMetadata(:Io_lim_Converter, false, false, true, false) + ParamsMetadata(:T_fltr_Converter, false, false, false, false) + ParamsMetadata(:K_hv_Converter, false, false, false, false) + ParamsMetadata(:Iqr_min_Converter, false, false, false, false) + ParamsMetadata(:Iqr_max_Converter, false, false, false, false) + ParamsMetadata(:Accel_Converter, false, false, false, false) + ParamsMetadata(:Q_ref_Converter, false, false, false, false) + ParamsMetadata(:R_source_Converter, false, false, false, false) + ParamsMetadata(:X_source_Converter, false, false, false, false) +] -#GENERATORS -get_n_params(g::PSY.DynamicGenerator) = - 3 + - get_n_params(PSY.get_machine(g)) + get_n_params(PSY.get_shaft(g)) + - get_n_params(PSY.get_avr(g)) + get_n_params(PSY.get_prime_mover(g)) + - get_n_params(PSY.get_pss(g)) +########### GENERATORS ############# function get_params(g::PSY.DynamicGenerator) - refs = [ - PSY.get_V_ref(g), - PSY.get_ω_ref(g), - PSY.get_P_ref(g), - ] vcat( - refs, get_params(PSY.get_machine(g)), get_params(PSY.get_shaft(g)), get_params(PSY.get_avr(g)), @@ -328,20 +358,23 @@ function get_params(g::PSY.DynamicGenerator) get_params(PSY.get_pss(g)), ) end -get_params_symbol(g::PSY.DynamicGenerator) = vcat( - [:V_ref, :ω_ref, :P_ref], - get_params_symbol(PSY.get_machine(g)), - get_params_symbol(PSY.get_shaft(g)), - get_params_symbol(PSY.get_avr(g)), - get_params_symbol(PSY.get_prime_mover(g)), - get_params_symbol(PSY.get_pss(g)), -) +function get_params_metadata(g::PSY.DynamicGenerator) + vcat( + get_params_metadata(PSY.get_machine(g)), + get_params_metadata(PSY.get_shaft(g)), + get_params_metadata(PSY.get_avr(g)), + get_params_metadata(PSY.get_prime_mover(g)), + get_params_metadata(PSY.get_pss(g)), + ) +end #MACHINES -get_n_params(::PSY.BaseMachine) = 3 get_params(x::PSY.BaseMachine) = [PSY.get_R(x), PSY.get_Xd_p(x), PSY.get_eq_p(x)] -get_params_symbol(::PSY.BaseMachine) = [:R_Machine, :Xd_p_Machine, :eq_p_Machine] -get_n_params(::PSY.OneDOneQMachine) = 7 +get_params_metadata(::PSY.BaseMachine) = [ + ParamsMetadata(:R_Machine, false, false, true, false), + ParamsMetadata(:Xd_p_Machine, false, false, true, false), + ParamsMetadata(:eq_p_Machine, false, false, true, false), +] get_params(x::PSY.OneDOneQMachine) = [ PSY.get_R(x), PSY.get_Xd(x), @@ -351,38 +384,48 @@ get_params(x::PSY.OneDOneQMachine) = [ PSY.get_Td0_p(x), PSY.get_Tq0_p(x), ] -get_params_symbol(x::PSY.OneDOneQMachine) = [ - :R_Machine, - :Xd_Machine, - :Xq_Machine, - :Xd_p_Machine, - :Xq_p_Machine, - :Td0_p_Machine, - :Tq0_p_Machine, -] -get_n_params(::PSY.MarconatoMachine) = 14 -get_params(x::PSY.MarconatoMachine) = - [PSY.get_R(x), PSY.get_Xd(x), PSY.get_Xq(x), PSY.get_Xd_p(x), PSY.get_Xq_p(x), - PSY.get_Xd_pp(x), PSY.get_Xq_pp(x), - PSY.get_Td0_p(x), PSY.get_Tq0_p(x), PSY.get_Td0_pp(x), PSY.get_Tq0_pp(x), - PSY.get_T_AA(x), PSY.get_γd(x), PSY.get_γq(x)] -get_params_symbol(x::PSY.MarconatoMachine) = [ - :R_Machine, - :Xd_Machine, - :Xq_Machine, - :Xd_p_Machine, - :Xq_p_Machine, - :Xd_pp_Machine, - :Xq_pp_Machine, - :Td0_p_Machine, - :Tq0_p_Machine, - :Td0_pp_Machine, - :Tq0_pp_Machine, - :T_AA_Machine, - :γd_Machine, - :γq_Machine, -] -get_n_params(::PSY.AndersonFouadMachine) = 11 +get_params_metadata(::PSY.OneDOneQMachine) = [ + ParamsMetadata(:R_Machine, false, false, true, false), + ParamsMetadata(:Xd_Machine, false, false, true, false), + ParamsMetadata(:Xq_Machine, false, false, true, false), + ParamsMetadata(:Xd_p_Machine, false, false, true, false), + ParamsMetadata(:Xq_p_Machine, false, false, true, false), + ParamsMetadata(:Td0_p_Machine, false, false, false, false), + ParamsMetadata(:Tq0_p_Machine, false, false, false, false), +] +#TODO - SimpleMarconatoMachine +get_params(x::PSY.MarconatoMachine) = [ + PSY.get_R(x), + PSY.get_Xd(x), + PSY.get_Xq(x), + PSY.get_Xd_p(x), + PSY.get_Xq_p(x), + PSY.get_Xd_pp(x), + PSY.get_Xq_pp(x), + PSY.get_Td0_p(x), + PSY.get_Tq0_p(x), + PSY.get_Td0_pp(x), + PSY.get_Tq0_pp(x), + PSY.get_T_AA(x), + PSY.get_γd(x), + PSY.get_γq(x), +] +get_params_metadata(::PSY.MarconatoMachine) = [ + ParamsMetadata(:R_Machine, false, false, true, false), + ParamsMetadata(:Xd_Machine, false, false, true, false), + ParamsMetadata(:Xq_Machine, false, false, true, false), + ParamsMetadata(:Xd_p_Machine, false, false, true, false), + ParamsMetadata(:Xq_p_Machine, false, false, true, false), + ParamsMetadata(:Xd_pp_Machine, false, false, true, false), + ParamsMetadata(:Xq_pp_Machine, false, false, true, false), + ParamsMetadata(:Td0_p_Machine, false, false, true, false), + ParamsMetadata(:Tq0_p_Machine, false, false, false, false), + ParamsMetadata(:Td0_pp_Machine, false, false, false, false), + ParamsMetadata(:Tq0_pp_Machine, false, false, false, false), + ParamsMetadata(:T_AA_Machine, false, false, true, false), + ParamsMetadata(:γd_Machine, false, false, true, false), + ParamsMetadata(:γq_Machine, false, false, true, false), +] get_params(x::PSY.AndersonFouadMachine) = [ PSY.get_R(x), PSY.get_Xd(x), @@ -395,23 +438,20 @@ get_params(x::PSY.AndersonFouadMachine) = [ PSY.get_Tq0_p(x), PSY.get_Td0_pp(x), PSY.get_Tq0_pp(x)] - -get_params_symbol(x::PSY.AndersonFouadMachine) = [:R_Machine, - :Xd_Machine, - :Xq_Machine, - :Xd_p_Machine, - :Xq_p_Machine, - :Xd_pp_Machine, - :Xq_pp_Machine, - :Td0_p_Machine, - :Tq0_p_Machine, - :Td0_pp_Machine, - :Tq0_pp_Machine] - +get_params_metadata(::PSY.AndersonFouadMachine) = [ + ParamsMetadata(:R_Machine, false, false, true, false), + ParamsMetadata(:Xd_Machine, false, false, true, false), + ParamsMetadata(:Xq_Machine, false, false, true, false), + ParamsMetadata(:Xd_p_Machine, false, false, true, false), + ParamsMetadata(:Xq_p_Machine, false, false, true, false), + ParamsMetadata(:Xd_pp_Machine, false, false, true, false), + ParamsMetadata(:Xq_pp_Machine, false, false, true, false), + ParamsMetadata(:Td0_p_Machine, false, false, false, false), + ParamsMetadata(:Tq0_p_Machine, false, false, false, false), + ParamsMetadata(:Td0_pp_Machine, false, false, false, false), + ParamsMetadata(:Tq0_pp_Machine, false, false, false, false), +] #NOTE: Saturation not considered as paramters -get_n_params( - x::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, -) = 16 get_params( x::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, ) = [ @@ -432,29 +472,26 @@ get_params( PSY.get_γ_q2(x), PSY.get_γ_qd(x), ] -get_params_symbol( +get_params_metadata( ::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, ) = [ - :R_Machine, - :Td0_p_Machine, - :Td0_pp_Machine, - :Tq0_p_Machine, - :Tq0_pp_Machine, - :Xd_Machine, - :Xq_Machine, - :Xd_p_Machine, - :Xq_p_Machine, - :Xd_pp_Machine, - :Xl_Machine, - :γ_d1_Machine, - :γ_q1_Machine, - :γ_d2_Machine, - :γ_q2_Machine, - :γ_qd_Machine, -] -get_n_params( - ::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, -) = 12 + ParamsMetadata(:R_Machine, false, false, true, false), + ParamsMetadata(:Td0_p_Machine, false, false, true, false), + ParamsMetadata(:Td0_pp_Machine, false, false, true, false), + ParamsMetadata(:Tq0_p_Machine, false, false, true, false), + ParamsMetadata(:Tq0_pp_Machine, false, false, true, false), + ParamsMetadata(:Xd_Machine, false, false, true, false), + ParamsMetadata(:Xq_Machine, false, false, true, false), + ParamsMetadata(:Xd_p_Machine, false, false, true, false), + ParamsMetadata(:Xq_p_Machine, false, false, true, false), + ParamsMetadata(:Xd_pp_Machine, false, false, true, false), + ParamsMetadata(:Xl_Machine, false, false, true, false), + ParamsMetadata(:γ_d1_Machine, false, false, true, false), + ParamsMetadata(:γ_q1_Machine, false, false, true, false), + ParamsMetadata(:γ_d2_Machine, false, false, true, false), + ParamsMetadata(:γ_q2_Machine, false, false, true, false), + ParamsMetadata(:γ_qd_Machine, false, false, true, false), +] get_params( x::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, ) = [ @@ -471,28 +508,29 @@ get_params( PSY.get_γ_q1(x), PSY.get_γ_d2(x), ] -get_params_symbol( +get_params_metadata( ::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, ) = [ - :R_Machine, - :Td0_p_Machine, - :Td0_pp_Machine, - :Tq0_pp_Machine, - :Xd_Machine, - :Xq_Machine, - :Xd_p_Machine, - :Xd_pp_Machine, - :Xl_Machine, - :γ_d1_Machine, - :γ_q1_Machine, - :γ_d2_Machine, + ParamsMetadata(:R_Machine, false, false, true, false), + ParamsMetadata(:Td0_p_Machine, false, false, true, false), + ParamsMetadata(:Td0_pp_Machine, false, false, true, false), + ParamsMetadata(:Tq0_pp_Machine, false, false, true, false), + ParamsMetadata(:Xd_Machine, false, false, true, false), + ParamsMetadata(:Xq_Machine, false, false, true, false), + ParamsMetadata(:Xd_p_Machine, false, false, true, false), + ParamsMetadata(:Xd_pp_Machine, false, false, true, false), + ParamsMetadata(:Xl_Machine, false, false, true, false), + ParamsMetadata(:γ_d1_Machine, false, false, true, false), + ParamsMetadata(:γ_q1_Machine, false, false, true, false), + ParamsMetadata(:γ_d2_Machine, false, false, true, false), ] #SHAFTS -get_n_params(::PSY.SingleMass) = 2 get_params(x::PSY.SingleMass) = [PSY.get_H(x), PSY.get_D(x)] -get_params_symbol(::PSY.SingleMass) = [:H_Shaft, :D_Shaft] -get_n_params(::PSY.FiveMassShaft) = 18 +get_params_metadata(::PSY.SingleMass) = [ + ParamsMetadata(:H_Shaft, false, false, false, false), + ParamsMetadata(:D_Shaft, false, false, false, false), +] get_params(x::PSY.FiveMassShaft) = [ PSY.get_H(x), PSY.get_H_hp(x), @@ -513,35 +551,32 @@ get_params(x::PSY.FiveMassShaft) = [ PSY.get_K_lp(x), PSY.get_K_ex(x), ] - -get_params_symbol(::PSY.FiveMassShaft) = [ - :H_Shaft, - :H_hp_Shaft, - :H_ip_Shaft, - :H_lp_Shaft, - :H_ex_Shaft, - :D_Shaft, - :D_hp_Shaft, - :D_ip_Shaft, - :D_lp_Shaft, - :D_ex_Shaft, - :D_12_Shaft, - :D_23_Shaft, - :D_34_Shaft, - :D_45_Shaft, - :K_hp_Shaft, - :K_ip_Shaft, - :K_lp_Shaft, - :K_ex_Shaft] +get_params_metadata(::PSY.FiveMassShaft) = [ + ParamsMetadata(:H_Shaft, false, false, false, false) + ParamsMetadata(:H_hp_Shaft, false, false, false, false) + ParamsMetadata(:H_ip_Shaft, false, false, false, false) + ParamsMetadata(:H_lp_Shaft, false, false, false, false) + ParamsMetadata(:H_ex_Shaft, false, false, false, false) + ParamsMetadata(:D_Shaft, false, false, true, false) + ParamsMetadata(:D_hp_Shaft, false, false, true, false) + ParamsMetadata(:D_ip_Shaft, false, false, true, false) + ParamsMetadata(:D_lp_Shaft, false, false, true, false) + ParamsMetadata(:D_ex_Shaft, false, false, true, false) + ParamsMetadata(:D_12_Shaft, false, false, true, false) + ParamsMetadata(:D_23_Shaft, false, false, true, false) + ParamsMetadata(:D_34_Shaft, false, false, true, false) + ParamsMetadata(:D_45_Shaft, false, false, true, false) + ParamsMetadata(:K_hp_Shaft, false, false, true, false) + ParamsMetadata(:K_ip_Shaft, false, false, true, false) + ParamsMetadata(:K_lp_Shaft, false, false, true, false) + ParamsMetadata(:K_ex_Shaft, false, false, true, false) +] #AVRS -get_n_params(::PSY.AVRFixed) = 0 -get_params(x::PSY.AVRFixed) = Float64[] -get_params_symbol(::PSY.AVRFixed) = Symbol[] -get_n_params(::PSY.AVRSimple) = 1 +get_params(::PSY.AVRFixed) = Float64[] +get_params_metadata(::PSY.AVRFixed) = ParamsMetadata[] get_params(x::PSY.AVRSimple) = [PSY.get_Kv(x)] -get_params_symbol(::PSY.AVRSimple) = [:Kv_AVR] -get_n_params(::PSY.AVRTypeI) = 9 +get_params_metadata(::PSY.AVRSimple) = [ParamsMetadata(:Kv_AVR, false, false, false, false)] get_params(x::PSY.AVRTypeI) = [ PSY.get_Ka(x), PSY.get_Ke(x), @@ -553,9 +588,17 @@ get_params(x::PSY.AVRTypeI) = [ PSY.get_Ae(x), PSY.get_Be(x), ] -get_params_symbol(::PSY.AVRTypeI) = - [:Ka_AVR, :Ke_AVR, :Kf_AVR, :Ta_AVR, :Te_AVR, :Tf_AVR, :Tr_AVR, :Ae_AVR, :Be_AVR] -get_n_params(::PSY.SEXS) = 6 +get_params_metadata(::PSY.AVRTypeI) = [ + ParamsMetadata(:Ka_AVR, false, false, true, false), + ParamsMetadata(:Ke_AVR, false, false, true, false), + ParamsMetadata(:Kf_AVR, false, false, true, false), + ParamsMetadata(:Ta_AVR, false, false, false, false), + ParamsMetadata(:Te_AVR, false, false, false, false), + ParamsMetadata(:Tf_AVR, false, false, true, false), + ParamsMetadata(:Tr_AVR, false, false, false, false), + ParamsMetadata(:Ae_AVR, false, false, true, false), + ParamsMetadata(:Be_AVR, false, false, true, false), +] get_params(x::PSY.SEXS) = [ PSY.get_Ta_Tb(x), PSY.get_Tb(x), @@ -564,34 +607,40 @@ get_params(x::PSY.SEXS) = [ PSY.get_V_lim(x)[1], PSY.get_V_lim(x)[2], ] -get_params_symbol(::PSY.SEXS) = - Symbol[:Ta_Tb_AVR, :Tb_AVR, :K_AVR, :Te_AVR, :V_min_AVR, :V_max_AVR] -get_n_params(::PSY.AVRTypeII) = 11 -get_params(x::PSY.AVRTypeII) = - [PSY.get_K0(x), - PSY.get_T1(x), - PSY.get_T2(x), - PSY.get_T3(x), - PSY.get_T4(x), - PSY.get_Te(x), - PSY.get_Tr(x), - PSY.get_Va_lim(x)[1], - PSY.get_Va_lim(x)[2], - PSY.get_Ae(x), - PSY.get_Be(x)] -get_params_symbol(::PSY.AVRTypeII) = - [:K0_AVR, - :T1_AVR, - :T2_AVR, - :T3_AVR, - :T4_AVR, - :Te_AVR, - :Tr_AVR, - :Va_min_AVR, - :Va_max_AVR, - :Ae_AVR, - :Be_AVR] -get_n_params(::PSY.ESAC1A) = 15 +get_params_metadata(::PSY.SEXS) = [ + ParamsMetadata(:Ta_Tb_AVR, false, false, true, false) + ParamsMetadata(:Tb_AVR, false, false, false, false) + ParamsMetadata(:K_AVR, false, false, true, false) + ParamsMetadata(:Te_AVR, false, false, false, false) + ParamsMetadata(:V_min_AVR, false, false, true, false) + ParamsMetadata(:V_max_AVR, false, false, true, false) +] +get_params(x::PSY.AVRTypeII) = [ + PSY.get_K0(x), + PSY.get_T1(x), + PSY.get_T2(x), + PSY.get_T3(x), + PSY.get_T4(x), + PSY.get_Te(x), + PSY.get_Tr(x), + PSY.get_Va_lim(x)[1], + PSY.get_Va_lim(x)[2], + PSY.get_Ae(x), + PSY.get_Be(x), +] +get_params_metadata(::PSY.AVRTypeII) = [ + ParamsMetadata(:K0_AVR, false, false, true, false), + ParamsMetadata(:T1_AVR, false, false, true, false), + ParamsMetadata(:T2_AVR, false, false, true, false), + ParamsMetadata(:T3_AVR, false, false, true, false), + ParamsMetadata(:T4_AVR, false, false, true, false), + ParamsMetadata(:Te_AVR, false, false, true, false), + ParamsMetadata(:Tr_AVR, false, false, false, false), + ParamsMetadata(:Va_min_AVR, false, false, true, false), + ParamsMetadata(:Va_max_AVR, false, false, true, false), + ParamsMetadata(:Ae_AVR, false, false, true, false), + ParamsMetadata(:Be_AVR, false, false, true, false), +] get_params(x::PSY.ESAC1A) = [ PSY.get_Tr(x), PSY.get_Tb(x), @@ -607,24 +656,27 @@ get_params(x::PSY.ESAC1A) = [ PSY.get_Kd(x), PSY.get_Ke(x), PSY.get_Vr_lim(x)[1], - PSY.get_Vr_lim(x)[2]] -get_params_symbol(::PSY.ESAC1A) = [:Tr, - :Tb_AVR, - :Tc_AVR, - :Ka_AVR, - :Ta_AVR, - :Va_min_AVR, - :Va_max_AVR, - :Te_AVR, - :Kf_AVR, - :Tf_AVR, - :Kc_AVR, - :Kd_AVR, - :Ke_AVR, - :Vr_min_AVR, - :Vr_max_AVR] -get_n_params(::PSY.EXST1) = 12 -get_params(x::PSY.EXST1) = [PSY.get_Tr(x), + PSY.get_Vr_lim(x)[2], +] +get_params_metadata(::PSY.ESAC1A) = [ + ParamsMetadata(:Tr, false, false, true, false), + ParamsMetadata(:Tb_AVR, false, false, true, false), + ParamsMetadata(:Tc_AVR, false, false, true, false), + ParamsMetadata(:Ka_AVR, false, false, true, false), + ParamsMetadata(:Ta_AVR, false, false, false, false), + ParamsMetadata(:Va_min_AVR, false, false, false, false), + ParamsMetadata(:Va_max_AVR, false, false, false, false), + ParamsMetadata(:Te_AVR, false, false, false, false), + ParamsMetadata(:Kf_AVR, false, false, true, false), + ParamsMetadata(:Tf_AVR, false, false, true, false), + ParamsMetadata(:Kc_AVR, false, false, true, false), + ParamsMetadata(:Kd_AVR, false, false, true, false), + ParamsMetadata(:Ke_AVR, false, false, true, false), + ParamsMetadata(:Vr_min_AVR, false, false, true, false), + ParamsMetadata(:Vr_max_AVR, false, false, true, false), +] +get_params(x::PSY.EXST1) = [ + PSY.get_Tr(x), PSY.get_Vi_lim(x)[1], PSY.get_Vi_lim(x)[2], PSY.get_Tc(x), @@ -635,23 +687,22 @@ get_params(x::PSY.EXST1) = [PSY.get_Tr(x), PSY.get_Vr_lim(x)[2], PSY.get_Kc(x), PSY.get_Kf(x), - PSY.get_Tf(x)] -get_params_symbol(::PSY.EXST1) = [ - :Tr_AVR, - :Vi_min_AVR, - :Vi_max_AVR, - :Tc_AVR, - :Tb_AVR, - :Ka_AVR, - :Ta_AVR, - :Vr_min_AVR, - :Vr_max_AVR, - :Kc_AVR, - :Kf_AVR, - :Tf_AVR, + PSY.get_Tf(x), +] +get_params_metadata(::PSY.EXST1) = [ + ParamsMetadata(:Tr_AVR, true, false, false, false), + ParamsMetadata(:Vi_min_AVR, false, false, false, false), + ParamsMetadata(:Vi_max_AVR, false, false, false, false), + ParamsMetadata(:Tc_AVR, false, false, true, false), + ParamsMetadata(:Tb_AVR, true, false, true, false), + ParamsMetadata(:Ka_AVR, false, false, true, false), + ParamsMetadata(:Ta_AVR, true, false, false, false), + ParamsMetadata(:Vr_min_AVR, false, false, true, false), + ParamsMetadata(:Vr_max_AVR, false, false, true, false), + ParamsMetadata(:Kc_AVR, false, false, true, false), + ParamsMetadata(:Kf_AVR, false, false, true, false), + ParamsMetadata(:Tf_AVR, false, false, true, false), ] - -get_n_params(::PSY.EXAC1) = 13 get_params(x::PSY.EXAC1) = [ PSY.get_Tr(x), PSY.get_Tb(x), @@ -666,30 +717,32 @@ get_params(x::PSY.EXAC1) = [ PSY.get_Kc(x), PSY.get_Kd(x), PSY.get_Ke(x)] - -get_params_symbol(::PSY.EXAC1) = [ - :Tr_AVR, - :Tb_AVR, - :Tc_AVR, - :Ka_AVR, - :Ta_AVR, - :Vr_min_AVR, - :Vr_max_AVR, - :Te_AVR, - :Kf_AVR, - :Tf_AVR, - :Kc_AVR, - :Kd_AVR, - :Ke_AVR] +get_params_metadata(::PSY.EXAC1) = [ + ParamsMetadata(:Tr_AVR, true, false, false, false), + ParamsMetadata(:Tb_AVR, true, false, true, false), + ParamsMetadata(:Tc_AVR, false, false, true, false), + ParamsMetadata(:Ka_AVR, false, false, true, false), + ParamsMetadata(:Ta_AVR, true, false, false, false), + ParamsMetadata(:Vr_min_AVR, false, false, true, false), + ParamsMetadata(:Vr_max_AVR, false, false, true, false), + ParamsMetadata(:Te_AVR, false, false, false, false), + ParamsMetadata(:Kf_AVR, false, false, true, false), + ParamsMetadata(:Tf_AVR, false, false, true, false), + ParamsMetadata(:Kc_AVR, false, false, true, false), + ParamsMetadata(:Kd_AVR, false, false, true, false), + ParamsMetadata(:Ke_AVR, false, false, true, false), +] #TurbineGov -get_n_params(::PSY.TGFixed) = 1 get_params(x::PSY.TGFixed) = [PSY.get_efficiency(x)] -get_params_symbol(::PSY.TGFixed) = [:efficiency_TurbineGov] -get_n_params(::PSY.TGTypeII) = 3 +get_params_metadata(::PSY.TGFixed) = + [ParamsMetadata(:efficiency_TurbineGov, false, false, true, false)] get_params(x::PSY.TGTypeII) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_T2(x)] -get_params_symbol(::PSY.TGTypeII) = [:R_tg_TurbineGovR, :T1_TurbineGov, :T2_TurbineGov] -get_n_params(::PSY.GasTG) = 9 +get_params_metadata(::PSY.TGTypeII) = [ + ParamsMetadata(:R_tg_TurbineGovR, false, false, true, false), + ParamsMetadata(:T1_TurbineGov, false, false, true, false), + ParamsMetadata(:T2_TurbineGov, false, false, true, false), +] get_params(x::PSY.GasTG) = [ PSY.get_R(x), PSY.get_T1(x), @@ -701,19 +754,19 @@ get_params(x::PSY.GasTG) = [ PSY.get_V_lim(x)[2], PSY.get_D_turb(x), ] -get_params_symbol(::PSY.GasTG) = [ - :R_tg_TurbineGov, - :T1_TurbineGov, - :T2_TurbineGov, - :T3_TurbineGov, - :AT_TurbineGov, - :Kt_TurbineGov, - :V_min_TurbineGov, - :V_max_TurbineGov, - :D_turb_TurbineGov, -] -get_n_params(::PSY.TGTypeI) = 8 -get_params(x::PSY.TGTypeI) = [PSY.get_R(x), +get_params_metadata(::PSY.GasTG) = [ + ParamsMetadata(:R_TurbineGov, false, false, true, false), + ParamsMetadata(:T1_TurbineGov, false, false, false, false), + ParamsMetadata(:T2_TurbineGov, false, false, false, false), + ParamsMetadata(:T3_TurbineGov, false, false, false, false), + ParamsMetadata(:AT_TurbineGov, false, false, true, false), + ParamsMetadata(:Kt_TurbineGov, false, false, true, false), + ParamsMetadata(:V_min_TurbineGov, false, false, true, false), + ParamsMetadata(:V_max_TurbineGov, false, false, true, false), + ParamsMetadata(:D_turb_TurbineGov, false, false, true, false), +] +get_params(x::PSY.TGTypeI) = [ + PSY.get_R(x), PSY.get_Ts(x), PSY.get_Tc(x), PSY.get_T3(x), @@ -722,17 +775,16 @@ get_params(x::PSY.TGTypeI) = [PSY.get_R(x), PSY.get_valve_position_limits(x)[1], PSY.get_valve_position_limits(x)[2], ] - -get_params_symbol(::PSY.TGTypeI) = [:R_tg_TurbineGov, - :Ts_TurbineGov, - :Tc_TurbineGov, - :T3_TurbineGov, - :T4_TurbineGov, - :T5_TurbineGov, - :valve_position_min_TurbineGov, - :valve_position_max_TurbineGov, -] -get_n_params(::PSY.SteamTurbineGov1) = 7 +get_params_metadata(::PSY.TGTypeI) = [ + ParamsMetadata(:R_tg_TurbineGov, false, false, true, false), + ParamsMetadata(:Ts_TurbineGov, false, false, false, false), + ParamsMetadata(:Tc_TurbineGov, false, false, true, false), + ParamsMetadata(:T3_TurbineGov, false, false, true, false), + ParamsMetadata(:T4_TurbineGov, false, false, true, false), + ParamsMetadata(:T5_TurbineGov, false, false, true, false), + ParamsMetadata(:valve_position_min_TurbineGov, false, false, true, false), + ParamsMetadata(:valve_position_max_TurbineGov, false, false, true, false), +] get_params(x::PSY.SteamTurbineGov1) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_valve_position_limits(x)[1], @@ -740,15 +792,17 @@ get_params(x::PSY.SteamTurbineGov1) = [PSY.get_R(x), PSY.get_T2(x), PSY.get_T3(x), PSY.get_D_T(x)] -get_params_symbol(::PSY.SteamTurbineGov1) = [:R_tg, - :T1_TurbineGov, - :valve_position_min_TurbineGov, - :valve_position_max_TurbineGov, - :T2_TurbineGov, - :T3_TurbineGov, - :D_T_TurbineGov] -get_n_params(::PSY.HydroTurbineGov) = 12 -get_params(x::PSY.HydroTurbineGov) = [PSY.get_R(x), +get_params_metadata(::PSY.SteamTurbineGov1) = [ + ParamsMetadata(:R_tg, false, false, true, false), + ParamsMetadata(:T1_TurbineGov, false, false, true, false), + ParamsMetadata(:valve_position_min_TurbineGov, false, false, true, false), + ParamsMetadata(:valve_position_max_TurbineGov, false, false, true, false), + ParamsMetadata(:T2_TurbineGov, false, false, true, false), + ParamsMetadata(:T3_TurbineGov, false, false, true, false), + ParamsMetadata(:D_T_TurbineGov, false, false, true, false), +] +get_params(x::PSY.HydroTurbineGov) = [ + PSY.get_R(x), PSY.get_r(x), PSY.get_Tr(x), PSY.get_Tf(x), @@ -759,112 +813,95 @@ get_params(x::PSY.HydroTurbineGov) = [PSY.get_R(x), PSY.get_Tw(x), PSY.get_At(x), PSY.get_D_T(x), - PSY.get_q_nl(x)] -get_params_symbol(::PSY.HydroTurbineGov) = [ - :R_TurbineGov, - :r_TurbineGov, - :Tr_TurbineGov, - :Tf_TurbineGov, - :Tg_TurbineGov, - :VELM_TurbineGov, - :G_min_TurbineGov, - :G_max_TurbineGov, - :Tw_TurbineGov, - :At_TurbineGov, - :D_T_TurbineGov, - :q_nl_TurbineGov] + PSY.get_q_nl(x), +] +get_params_metadata(::PSY.HydroTurbineGov) = [ + ParamsMetadata(:R_TurbineGov, false, false, true, false), + ParamsMetadata(:r_TurbineGov, false, false, true, false), + ParamsMetadata(:Tr_TurbineGov, false, false, true, false), + ParamsMetadata(:Tf_TurbineGov, true, false, false, false), + ParamsMetadata(:Tg_TurbineGov, true, false, false, false), + ParamsMetadata(:VELM_TurbineGov, false, false, false, false), + ParamsMetadata(:G_min_TurbineGov, false, false, true, false), + ParamsMetadata(:G_max_TurbineGov, false, false, true, false), + ParamsMetadata(:Tw_TurbineGov, false, false, false, false), + ParamsMetadata(:At_TurbineGov, false, false, true, false), + ParamsMetadata(:D_T_TurbineGov, false, false, true, false), + ParamsMetadata(:q_nl_TurbineGov, false, false, true, false), +] #PSS -get_n_params(::PSY.PSSFixed) = 1 get_params(x::PSY.PSSFixed) = [PSY.get_V_pss(x)] -get_params_symbol(::PSY.PSSFixed) = [:V_pss_PSS] - -get_n_params(::PSY.STAB1) = 7 -get_params(x::PSY.STAB1) = [PSY.get_KT(x), +get_params_metadata(::PSY.PSSFixed) = + [ParamsMetadata(:V_pss_PSS, false, false, false, false)] +get_params(x::PSY.STAB1) = [ + PSY.get_KT(x), PSY.get_T(x), PSY.get_T1T3(x), PSY.get_T3(x), PSY.get_T2T4(x), PSY.get_T4(x), - PSY.get_H_lim(x)] -get_params_symbol(::PSY.STAB1) = - [:KT_PSS, - :T_PSS, - :T1T3_PSS, - :T3_PSS, - :T2T4_PSS, - :T4_PSS, - :H_lim_PSS] - -#STATIC INJECTION -get_n_params(::PSY.StaticInjection) = 1 -get_params(x::PSY.StaticInjection) = [PSY.get_reactive_power(x)] -get_params_symbol(::PSY.StaticInjection) = [:Q_ref] + PSY.get_H_lim(x), +] +get_params_metadata(::PSY.STAB1) = [ + ParamsMetadata(:KT_PSS, false, false, false, false), + ParamsMetadata(:T_PSS, false, false, false, false), + ParamsMetadata(:T1T3_PSS, false, false, false, false), + ParamsMetadata(:T3_PSS, false, false, false, false), + ParamsMetadata(:T2T4_PSS, false, false, false, false), + ParamsMetadata(:T4_PSS, false, false, false, false), + ParamsMetadata(:H_lim_PSS, false, false, false, false), +] -get_n_params(::PSY.StandardLoad) = 1 -get_params(x::PSY.StandardLoad) = [PF.get_total_q(x)] -get_params_symbol(::PSY.StandardLoad) = [:Q_ref] #SOURCE -get_n_params(::PSY.Source) = 4 get_params(x::PSY.Source) = [ PSY.get_R_th(x), PSY.get_X_th(x), PSY.get_internal_voltage(x), PSY.get_internal_angle(x), ] -#Parameters not implemented for PVS - requires change in PSY Struct to have information required to construct and deconstruct parameter vector -get_n_params(x::PSY.PeriodicVariableSource) = 4 -get_params(x::PSY.PeriodicVariableSource) = Float64[0.0, 0.0, 0.0, 0.0] +get_params_metadata(::PSY.Source) = [ + ParamsMetadata(:R_th, false, false, true, false), + ParamsMetadata(:X_th, false, false, true, false), + ParamsMetadata(:internal_voltage, false, false, true, false), #set during initialization -- incompatible with sensitivity analysis? + ParamsMetadata(:internal_angle, false, false, true, false), #set during initialization -- incompatible with sensitivity analysis? +] +#Parameters not implemented for PeriodicVariableSource - requires change in PSY Struct to have information required to construct and deconstruct parameter vector #DYNAMIC LOADS -get_n_params(::PSY.ActiveConstantPowerLoad) = 18 -get_params(x::PSY.ActiveConstantPowerLoad) = - [ - 0.0, - 0.0, - 0.0, - 0.0, - PSY.get_r_load(x), - PSY.get_c_dc(x), - PSY.get_rf(x), - PSY.get_lf(x), - PSY.get_cf(x), - PSY.get_rg(x), - PSY.get_lg(x), - PSY.get_kp_pll(x), - PSY.get_ki_pll(x), - PSY.get_kpv(x), - PSY.get_kiv(x), - PSY.get_kpc(x), - PSY.get_kic(x), - PSY.get_base_power(x)] -get_params_symbol(::PSY.ActiveConstantPowerLoad) = - [ - :Q_ref, - :V_ref, - :ω_ref, - :P_ref, - :r_load, - :c_dc, - :rf, - :lf, - :cf, - :rg, - :lg, - :kp_pll, - :ki_pll, - :kpv, - :kiv, - :kpc, - :kic, - :base_power] - -get_n_params(::PSY.SingleCageInductionMachine) = 18 +get_params(x::PSY.ActiveConstantPowerLoad) = [ + PSY.get_r_load(x), + PSY.get_c_dc(x), + PSY.get_rf(x), + PSY.get_lf(x), + PSY.get_cf(x), + PSY.get_rg(x), + PSY.get_lg(x), + PSY.get_kp_pll(x), + PSY.get_ki_pll(x), + PSY.get_kpv(x), + PSY.get_kiv(x), + PSY.get_kpc(x), + PSY.get_kic(x), + PSY.get_base_power(x), +] +get_params_metadata(::PSY.ActiveConstantPowerLoad) = [ + ParamsMetadata(:r_load, false, false, true, false), + ParamsMetadata(:c_dc, false, false, false, false), + ParamsMetadata(:rf, false, false, true, false), + ParamsMetadata(:lf, true, false, true, false), + ParamsMetadata(:cf, true, false, true, false), + ParamsMetadata(:rg, false, false, true, false), + ParamsMetadata(:lg, true, false, true, false), + ParamsMetadata(:kp_pll, false, false, false, false), + ParamsMetadata(:ki_pll, false, false, false, false), + ParamsMetadata(:kpv, false, false, false, false), + ParamsMetadata(:kiv, false, false, true, false), + ParamsMetadata(:kpc, false, false, false, false), + ParamsMetadata(:kic, false, false, true, false), + ParamsMetadata(:base_power, false, false, true, false), +] get_params(x::PSY.SingleCageInductionMachine) = [ - 0.0,#refs unused - 0.0,#refs unused - 0.0, #refs unused - 0.0, #refs unused PSY.get_R_s(x), PSY.get_R_r(x), PSY.get_X_ls(x), @@ -879,31 +916,23 @@ get_params(x::PSY.SingleCageInductionMachine) = [ PSY.get_B_shunt(x), PSY.get_X_ad(x), PSY.get_X_aq(x)] -get_params_symbol(::PSY.SingleCageInductionMachine) = [ - :Q_ref, - :V_ref, - :ω_ref, - :P_ref, - :R_s, - :R_r, - :X_ls, - :X_lr, - :X_m, - :H, - :A, - :B, - :base_power, - :C, - :τ_ref, - :B_shunt, - :X_ad, - :X_aq] -get_n_params(::PSY.SimplifiedSingleCageInductionMachine) = 19 +get_params_metadata(::PSY.SingleCageInductionMachine) = [ + ParamsMetadata(:R_s, false, false, true, false), + ParamsMetadata(:R_r, false, false, true, false), + ParamsMetadata(:X_ls, false, false, true, false), + ParamsMetadata(:X_lr, false, false, true, false), + ParamsMetadata(:X_m, false, false, false, false), + ParamsMetadata(:H, false, false, false, false), + ParamsMetadata(:A, false, false, true, false), + ParamsMetadata(:B, false, false, true, false), + ParamsMetadata(:base_power, false, false, true, false), + ParamsMetadata(:C, false, false, true, false), + ParamsMetadata(:τ_ref, false, false, true, false), + ParamsMetadata(:B_shunt, false, false, true, false), + ParamsMetadata(:X_ad, false, false, true, false), + ParamsMetadata(:X_aq, false, false, true, false), +] get_params(x::PSY.SimplifiedSingleCageInductionMachine) = [ - 0.0,#refs unused - 0.0,#refs unused - 0.0, #refs unused - 0.0, #refs unused PSY.get_R_s(x), PSY.get_R_r(x), PSY.get_X_ls(x), @@ -919,32 +948,24 @@ get_params(x::PSY.SimplifiedSingleCageInductionMachine) = [ PSY.get_X_ss(x), PSY.get_X_rr(x), PSY.get_X_p(x)] -get_params_symbol(::PSY.SimplifiedSingleCageInductionMachine) = [ - :Q_ref, - :V_ref, - :ω_ref, - :P_ref, - :R_s, - :R_r, - :X_ls, - :X_lr, - :X_m, - :H, - :A, - :B, - :base_power, - :C, - :τ_ref, - :B_shunt, - :X_ss, - :X_rr, - :X_p] - -get_n_params(x::PSY.AggregateDistributedGenerationA) = 33 -get_params(x::PSY.AggregateDistributedGenerationA) = [PSY.get_Q_ref(x), - PSY.get_V_ref(x), - PSY.get_ω_ref(x), - PSY.get_P_ref(x), +get_params_metadata(::PSY.SimplifiedSingleCageInductionMachine) = [ + ParamsMetadata(:R_s, false, false, true, false), + ParamsMetadata(:R_r, false, false, true, false), + ParamsMetadata(:X_ls, false, false, false, false), + ParamsMetadata(:X_lr, false, false, false, false), + ParamsMetadata(:X_m, false, false, true, false), + ParamsMetadata(:H, false, false, false, false), + ParamsMetadata(:A, false, false, true, false), + ParamsMetadata(:B, false, false, true, false), + ParamsMetadata(:base_power, false, false, true, false), + ParamsMetadata(:C, false, false, true, false), + ParamsMetadata(:τ_ref, false, false, true, false), + ParamsMetadata(:B_shunt, false, false, true, false), + ParamsMetadata(:X_ss, false, false, true, false), + ParamsMetadata(:X_rr, false, false, true, false), + ParamsMetadata(:X_p, false, false, true, false), +] +get_params(x::PSY.AggregateDistributedGenerationA) = [ PSY.get_T_rv(x), PSY.get_Trf(x), PSY.get_dbd_pnts(x)[1], @@ -973,14 +994,41 @@ get_params(x::PSY.AggregateDistributedGenerationA) = [PSY.get_Q_ref(x), PSY.get_Iq_lim(x)[1], PSY.get_Iq_lim(x)[2], PSY.get_base_power(x), - PSY.get_Pfa_ref(x)] + PSY.get_Pfa_ref(x), +] +get_params_metadata(::PSY.AggregateDistributedGenerationA) = [ + ParamsMetadata(:T_rv, true, false, false, false), + ParamsMetadata(:Trf, true, false, false, false), + ParamsMetadata(:dbd_pnts, false, false, false, false), + ParamsMetadata(:dbd_pnts, false, false, false, false), + ParamsMetadata(:K_qv, false, false, true, false), + ParamsMetadata(:Tp, true, false, false, false), + ParamsMetadata(:T_iq, true, false, false, false), + ParamsMetadata(:D_dn, false, false, false, false), + ParamsMetadata(:D_up, false, false, false, false), + ParamsMetadata(:fdbd_pnts, false, false, false, false), + ParamsMetadata(:fdbd_pnts, false, false, false, false), + ParamsMetadata(:fe_lim, false, false, false, false), + ParamsMetadata(:fe_lim, false, false, false, false), + ParamsMetadata(:P_lim, false, false, false, false), + ParamsMetadata(:P_lim, false, false, false, false), + ParamsMetadata(:dP_lim, false, false, false, false), + ParamsMetadata(:dP_lim, false, false, false, false), + ParamsMetadata(:Tpord, true, false, false, false), + ParamsMetadata(:Kpg, false, false, false, false), + ParamsMetadata(:Kig, false, false, false, false), + ParamsMetadata(:I_max, false, false, false, false), + ParamsMetadata(:Tg, false, false, false, false), + ParamsMetadata(:rrpwr, false, false, false, false), + ParamsMetadata(:Tv, true, false, false, false), + ParamsMetadata(:Vpr, false, false, false, false), + ParamsMetadata(:Iq_lim, false, false, false, false), + ParamsMetadata(:Iq_lim, false, false, false, false), + ParamsMetadata(:base_power, false, false, false, false), + ParamsMetadata(:Pfa_ref, false, false, true, false), +] -get_n_params(x::PSY.CSVGN1) = 17 get_params(x::PSY.CSVGN1) = [ - 0.0, - 0.0, - 0.0, - 0.0, PSY.get_K(x), PSY.get_T1(x), PSY.get_T2(x), @@ -993,4 +1041,20 @@ get_params(x::PSY.CSVGN1) = [ PSY.get_CBase(x), PSY.get_base_power(x), PSY.get_R_th(x), - PSY.get_X_th(x)] + PSY.get_X_th(x), +] +get_params_metadata(::PSY.CSVGN1) = [ + ParamsMetadata(:K, false, false, false, false), + ParamsMetadata(:T1, false, false, false, false), + ParamsMetadata(:T2, false, false, false, false), + ParamsMetadata(:T3, false, false, false, false), + ParamsMetadata(:T4, false, false, false, false), + ParamsMetadata(:T5, false, false, false, false), + ParamsMetadata(:Rmin, false, false, false, false), + ParamsMetadata(:Vmax, false, false, false, false), + ParamsMetadata(:Vmin, false, false, false, false), + ParamsMetadata(:CBase, false, false, false, false), + ParamsMetadata(:base_power, false, false, false, false), + ParamsMetadata(:R_th, false, false, false, false), + ParamsMetadata(:X_th, false, false, false, false), +] diff --git a/test/Project.toml b/test/Project.toml index 89fcb075f..e3321c8dd 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,5 +1,6 @@ [deps] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DelayDiffEq = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb" DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" @@ -9,6 +10,8 @@ InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" +Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba" +OptimizationOptimisers = "42dfb2eb-d2b4-4451-abcd-913932933ac1" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" PowerFlows = "94fada2c-fd9a-4e89-8d82-81405f5cb4f6" PowerNetworkMatrices = "bed98974-b02a-5e2f-9fe0-a103f5c450dd" @@ -16,9 +19,11 @@ PowerSimulationsDynamics = "398b2ede-47ed-4edc-b52e-69e4a48b4336" PowerSystemCaseBuilder = "f00506e0-b84f-492a-93c2-c0a9afc4364e" PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" Sundials = "c3572dad-4567-51f8-b174-8c6c989267f4" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [compat] SciMLBase = "2" diff --git a/test/test_base.jl b/test/test_base.jl index d1849ea7c..ad6fadeff 100644 --- a/test/test_base.jl +++ b/test/test_base.jl @@ -475,8 +475,8 @@ end p_ix1 = PSID.get_p_range(PSID.get_dynamic_injectors(inputs)[1]) p_ix2 = PSID.get_p_range(PSID.get_dynamic_injectors(inputs)[2]) - @test integrator_for_test.p[p_ix1][PSID.P_ref_ix] == 10.0 - @test integrator_for_test.p[p_ix2][PSID.ω_ref_ix] == 0.9 + @test PSID.get_P_ref(inputs.dynamic_injectors[1]) == 10.0 + @test PSID.get_ω_ref(inputs.dynamic_injectors[2]) == 0.9 inputs = PSID.SimulationInputs( ResidualModel, threebus_sys, diff --git a/test/test_case_sensitivity.jl b/test/test_case_sensitivity.jl index d747b0891..fd342c327 100644 --- a/test/test_case_sensitivity.jl +++ b/test/test_case_sensitivity.jl @@ -3,14 +3,14 @@ Case 1: This case study defines a classical machine against an infinite bus. Sensitivitiy Analysis is performed for the inertia of the generator. The fault is a change in the -source voltage. +source voltage. This test also checks that incorrect user data is handled correctly. """ ################################################## ############### LOAD DATA ###################### ## ################################################## omib_sys = build_system(PSIDTestSystems, "psid_test_omib") - +ieee_9bus_sys = build_system(PSIDTestSystems, "psid_test_ieee_9bus") ################################################## ############### SOLVE PROBLEM #################### ################################################## @@ -19,7 +19,6 @@ s_device = get_component(Source, omib_sys, "InfBus") s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) #using PlotlyJS #for debug only - #NOTES ON SENSITIVITY ALGORITHMS FROM SCIMLSENSITIVITY #ReverseDiffVJP and EnzymeVJP only options compatible with Hybrid DEs (DEs with callbacks) #BacksolveAdjoint prone to instabilities whenever the Lipschitz constant is sufficiently large (stiff equations, PDE discretizations, and many other contexts) @@ -40,7 +39,7 @@ s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) res = read_results(sim) t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) for solver in [FBDF(), Rodas5(), QNDF()] - for tol in [1e-6, 1e-9, 1e-12] + for tol in [1e-6, 1e-9] function f(sim) execute!( sim, @@ -61,6 +60,7 @@ s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) f, ) #p = PSID.get_parameter_sensitivity_values(sim, [("generator-102-1", SingleMass, :H)]) + #@error Zygote.gradient(g, [3.15])[1][1] @test isapprox(Zygote.gradient(g, [3.14])[1][1], -8.0, atol = 1.0) @test isapprox(Zygote.gradient(g, [3.15])[1][1], 8.0, atol = 1.0) end @@ -118,7 +118,7 @@ end callback = callback, maxiters = 3, ) - @test sol.u[1] == 3.144000187737475 + @test isapprox(sol.u[1], 3.144000187737475, atol = 1e-8) #display(plot(scatter(y=H_values))) #display(plot(scatter(y=loss_values))) finally @@ -301,3 +301,31 @@ end rm(path; force = true, recursive = true) end end + +@testset "Test unsupported options" begin + path = mktempdir() + try + sim = Simulation!( + MassMatrixModel, + ieee_9bus_sys, + path, + (0.0, 5.0), + ) + invalid_options = [ + ("Bus 7-Bus 5-i_3", Line, :x), #not a wrapped component + ("generator-1-1", AndersonFouadMachine, :R), #part of initialization + ("generator-1-1", AndersonFouadMachine, :XXX), #incorrect symbol + ] + for option in invalid_options + g = PSID.get_parameter_sensitivity_function!( + sim, + [option], + (sim) -> 0.0, + ) + @test g === nothing + end + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end From cab8e2e814e021731b6f423a95e16e423525fcfe Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 30 Apr 2024 12:39:21 -0400 Subject: [PATCH 08/76] format --- src/utils/psy_utils.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/psy_utils.jl b/src/utils/psy_utils.jl index 08dde1b89..3393703ce 100644 --- a/src/utils/psy_utils.jl +++ b/src/utils/psy_utils.jl @@ -33,7 +33,6 @@ function get_dynamic_branches(sys::PSY.System) return PSY.get_components(x -> PSY.get_available(x), PSY.DynamicBranch, sys) end - function transform_ybus_to_rectangular( ybus::SparseArrays.SparseMatrixCSC{Complex{Float64}, Int}, ) From 94e9f654729e460139468e2adaea1355506665df Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 1 May 2024 11:26:40 -0400 Subject: [PATCH 09/76] add back refs for static and loads --- src/base/device_wrapper.jl | 75 ++++++++++++++++++++++++++++--- src/base/perturbations.jl | 62 +++++++++++++------------ src/base/simulation_inputs.jl | 2 +- src/initialization/init_device.jl | 7 ++- src/models/load_models.jl | 10 +++-- src/models/source_models.jl | 6 +-- src/utils/parameters.jl | 46 +------------------ test/test_base.jl | 8 ++-- test/test_case_sensitivity.jl | 13 +++++- 9 files changed, 133 insertions(+), 96 deletions(-) diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index 2aac2144b..c02a425f2 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -432,6 +432,10 @@ end struct StaticWrapper{T <: PSY.StaticInjection, V} device::T connection_status::Base.RefValue{Float64} + V_ref::Base.RefValue{Float64} + θ_ref::Base.RefValue{Float64} + P_ref::Base.RefValue{Float64} + Q_ref::Base.RefValue{Float64} p_range::Vector{Int} bus_ix::Int ext::Dict{String, Any} @@ -442,6 +446,10 @@ function DynamicWrapper(device::T, bus_ix::Int) where {T <: PSY.Device} StaticWrapper{T, BUS_MAP[PSY.get_bustype(bus)]}( device, Base.Ref(1.0), + Base.Ref(PSY.get_magnitude(bus)), + Base.Ref(PSY.get_angle(bus)), + Base.Ref(PSY.get_active_power(device)), + Base.Ref(PSY.get_reactive_power(device)), Vector{Int}(), bus_ix, Dict{String, Any}(), @@ -453,6 +461,10 @@ function StaticWrapper(device::T, bus_ix::Int, p_range) where {T <: PSY.Source} return StaticWrapper{T, BUS_MAP[PSY.get_bustype(bus)]}( device, Base.Ref(1.0), + Base.Ref(PSY.get_internal_voltage(device)), + Base.Ref(PSY.get_internal_angle(device)), + Base.Ref(PSY.get_active_power(device)), + Base.Ref(PSY.get_reactive_power(device)), p_range, bus_ix, Dict{String, Any}(), @@ -474,6 +486,16 @@ PSY.get_reactive_power(wrapper::StaticWrapper) = PSY.get_reactive_power(wrapper. PSY.get_name(wrapper::StaticWrapper) = PSY.get_name(wrapper.device) PSY.get_ext(wrapper::StaticWrapper) = PSY.get_ext(wrapper.device) +get_P_ref(wrapper::StaticWrapper) = wrapper.P_ref[] +get_Q_ref(wrapper::StaticWrapper) = wrapper.Q_ref[] +get_V_ref(wrapper::StaticWrapper) = wrapper.V_ref[] +get_θ_ref(wrapper::StaticWrapper) = wrapper.θ_ref[] + +set_P_ref(wrapper::StaticWrapper, val::Float64) = wrapper.P_ref[] = val +set_Q_ref(wrapper::StaticWrapper, val::Float64) = wrapper.Q_ref[] = val +set_V_ref(wrapper::StaticWrapper, val::Float64) = wrapper.V_ref[] = val +set_θ_ref(wrapper::StaticWrapper, val::Float64) = wrapper.θ_ref[] = val + mutable struct ExpLoadParams P_exp::Float64 P_coeff::Float64 @@ -482,13 +504,19 @@ mutable struct ExpLoadParams end mutable struct StaticLoadWrapper - loads::Vector{PSY.ElectricLoad} bus::PSY.Bus + V_ref::Float64 + θ_ref::Float64 + P_power::Float64 + P_current::Float64 + P_impedance::Float64 + Q_power::Float64 + Q_current::Float64 + Q_impedance::Float64 exp_params::Vector{ExpLoadParams} exp_names::Dict{String, Int} p_range::Vector{Int} bus_ix::Int - system_base_power::Float64 end function StaticLoadWrapper( @@ -498,6 +526,28 @@ function StaticLoadWrapper( bus_ix::Int, sys_base_power::Float64, ) + P_power = 0.0 + P_current = 0.0 + P_impedance = 0.0 + Q_power = 0.0 + Q_current = 0.0 + Q_impedance = 0.0 + + # Add ZIP Loads + for ld in loads + base_power_conversion = PSY.get_base_power(ld) / sys_base_power + if isa(ld, PSY.PowerLoad) + P_power += PSY.get_active_power(ld) * base_power_conversion + Q_power += PSY.get_reactive_power(ld) * base_power_conversion + elseif isa(ld, PSY.StandardLoad) + P_impedance += PSY.get_impedance_active_power(ld) * base_power_conversion + Q_impedance += PSY.get_impedance_reactive_power(ld) * base_power_conversion + P_current += PSY.get_current_active_power(ld) * base_power_conversion + Q_current += PSY.get_current_reactive_power(ld) * base_power_conversion + P_power += PSY.get_constant_active_power(ld) * base_power_conversion + Q_power += PSY.get_constant_reactive_power(ld) * base_power_conversion + end + end # Add Exponential Loads exp_loads = filter(x -> isa(x, PSY.ExponentialLoad) && PSY.get_available(x), loads) @@ -517,25 +567,38 @@ function StaticLoadWrapper( end return StaticLoadWrapper( - loads, bus, + PSY.get_magnitude(bus), + PSY.get_angle(bus), + P_power, + P_current, + P_impedance, + Q_power, + Q_current, + Q_impedance, exp_params, dict_names, p_range, bus_ix, - sys_base_power, ) end PSY.get_bus(wrapper::StaticLoadWrapper) = wrapper.bus PSY.get_name(wrapper::StaticLoadWrapper) = PSY.get_name(wrapper.bus) -get_loads(wrapper::StaticLoadWrapper) = wrapper.loads +get_V_ref(wrapper::StaticLoadWrapper) = wrapper.V_ref +get_θ_ref(wrapper::StaticLoadWrapper) = wrapper.θ_ref +get_P_power(wrapper::StaticLoadWrapper) = wrapper.P_power +get_P_current(wrapper::StaticLoadWrapper) = wrapper.P_current +get_P_impedance(wrapper::StaticLoadWrapper) = wrapper.P_impedance +get_Q_power(wrapper::StaticLoadWrapper) = wrapper.Q_power +get_Q_current(wrapper::StaticLoadWrapper) = wrapper.Q_current +get_Q_impedance(wrapper::StaticLoadWrapper) = wrapper.Q_impedance + get_p_range(wrapper::StaticLoadWrapper) = wrapper.p_range get_exp_params(wrapper::StaticLoadWrapper) = wrapper.exp_params get_exp_names(wrapper::StaticLoadWrapper) = wrapper.exp_names get_bus_ix(wrapper::StaticLoadWrapper) = wrapper.bus_ix -get_system_base_power(wrapper::StaticLoadWrapper) = wrapper.system_base_power set_V_ref!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.V_ref = val set_θ_ref!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.θ_ref = val diff --git a/src/base/perturbations.jl b/src/base/perturbations.jl index 9a841cdb7..6e4afbf1c 100644 --- a/src/base/perturbations.jl +++ b/src/base/perturbations.jl @@ -510,12 +510,10 @@ function get_affect(inputs::SimulationInputs, ::PSY.System, pert::SourceBusVolta wrapped_device_ix = _find_device_index(inputs, pert.device) return (integrator) -> begin wrapped_device = get_static_injectors(inputs)[wrapped_device_ix] - p_range = get_p_range(wrapped_device) - device_parameters = @view integrator.p[p_range] if pert.signal == :V_ref - device_parameters[3] = pert.ref_value + set_V_ref(wrapped_device, pert.ref_value) elseif pert.signal == :θ_ref - device_parameters[4] = pert.ref_value + set_θ_ref(wrapped_device, pert.ref_value) else error("Signal $signal not accepted as a control reference change in SourceBus") end @@ -640,10 +638,10 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) ) end wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] - p_range = get_p_range(wrapped_zip) - device_parameters = @view integrator.p[p_range] - device_parameters[3] += P_change - device_parameters[6] += Q_change + P_power = get_P_power(wrapped_zip) + Q_power = get_Q_power(wrapped_zip) + set_P_power!(wrapped_zip, P_power + P_change) + set_Q_power!(wrapped_zip, Q_power + Q_change) CRC.@ignore_derivatives @debug "Changing load at bus $(PSY.get_name(wrapped_zip)) $(pert.signal) to $(pert.ref_value)" return end @@ -651,33 +649,37 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) return (integrator) -> begin base_power_conversion = PSY.get_base_power(ld) / sys_base_power wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] - p_range = get_p_range(wrapped_zip) - device_parameters = @view integrator.p[p_range] # List all cases for StandardLoad changes if signal ∈ [:P_ref, :P_ref_impedance] P_old = PSY.get_impedance_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - device_parameters[5] += P_change + P_impedance = get_P_impedance(wrapped_zip) + set_P_impedance!(wrapped_zip, P_impedance + P_change) elseif signal ∈ [:Q_ref, :Q_ref_impedance] Q_old = PSY.get_impedance_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - device_parameters[8] += Q_change + Q_impedance = get_Q_impedance(wrapped_zip) + set_Q_impedance!(wrapped_zip, Q_impedance + Q_change) elseif signal == :P_ref_power P_old = PSY.get_constant_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - device_parameters[3] += P_change + P_power = get_P_power(wrapped_zip) + set_P_power!(wrapped_zip, P_power + P_change) elseif signal == :Q_ref_power Q_old = PSY.get_constant_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - device_parameters[8] += Q_change + Q_power = get_Q_power(wrapped_zip) + set_Q_power!(wrapped_zip, Q_power + Q_change) elseif signal == :P_ref_current P_old = PSY.get_current_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - device_parameters[4] += P_change + P_current = get_P_current(wrapped_zip) + set_P_current!(wrapped_zip, P_current + P_change) elseif signal == :Q_ref_current Q_old = PSY.get_current_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - device_parameters[7] += Q_change + Q_current = get_Q_current(wrapped_zip) + set_Q_current!(wrapped_zip, Q_current + Q_change) else error("It should never be here. Should have failed in the constructor.") end @@ -740,10 +742,10 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) return (integrator) -> begin PSY.set_available!(ld, false) wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] - p_range = get_p_range(wrapped_zip) - device_parameters = @view integrator.p[p_range] - device_parameters[3] -= P_trip - device_parameters[6] -= Q_trip + P_power = get_P_power(wrapped_zip) + Q_power = get_Q_power(wrapped_zip) + set_P_power!(wrapped_zip, P_power - P_trip) + set_Q_power!(wrapped_zip, Q_power - Q_trip) CRC.@ignore_derivatives @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end @@ -758,17 +760,21 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) return (integrator) -> begin PSY.set_available!(ld, false) wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] - p_range = get_p_range(wrapped_zip) - device_parameters = @view integrator.p[p_range] # Update Constant Power - device_parameters[3] -= P_power_trip - device_parameters[6] -= Q_power_trip + P_power = get_P_power(wrapped_zip) + Q_power = get_Q_power(wrapped_zip) + set_P_power!(wrapped_zip, P_power - P_power_trip) + set_Q_power!(wrapped_zip, Q_power - Q_power_trip) # Update Constant Current - device_parameters[4] -= P_current_trip - device_parameters[7] -= Q_current_trip + P_current = get_P_current(wrapped_zip) + Q_current = get_Q_current(wrapped_zip) + set_P_current!(wrapped_zip, P_current - P_current_trip) + set_Q_current!(wrapped_zip, Q_current - Q_current_trip) # Update Constant Impedance - device_parameters[5] -= P_impedance_trip - device_parameters[8] -= Q_impedance_trip + P_impedance = get_P_impedance(wrapped_zip) + Q_impedance = get_Q_impedance(wrapped_zip) + set_P_impedance!(wrapped_zip, P_impedance - P_impedance_trip) + set_Q_impedance!(wrapped_zip, Q_impedance - Q_impedance_trip) CRC.@ignore_derivatives @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index f9510b165..7d7365150 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -350,7 +350,7 @@ function _construct_load_wrapper( for (ix, (bus, loads)) in enumerate(map_bus_load) bus_n = PSY.get_number(bus) bus_ix = lookup[bus_n] - n_params = 8 + n_params = 0 p_range = range(parameter_count; length = n_params) container[ix] = StaticLoadWrapper(bus, loads, p_range, bus_ix, sys_base_power) parameter_count += n_params diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index 0c7f155b9..b1c7d5621 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -71,8 +71,7 @@ function initialize_static_device!( I = conj(S0 / V) I_R = real(I) I_I = imag(I) - R_th = local_parameters[1] - X_th = local_parameters[2] + R_th, X_th = local_parameters Zmag = R_th^2 + X_th^2 function f!(out, x) @@ -95,8 +94,8 @@ function initialize_static_device!( θ_internal = atan(sol_x0[2], sol_x0[1]) PSY.set_internal_voltage!(device.device, V_internal) PSY.set_internal_angle!(device.device, θ_internal) - local_parameters[3] = V_internal - local_parameters[4] = θ_internal + set_V_ref(device, PSY.get_internal_voltage(device.device)) + set_θ_ref(device, PSY.get_internal_angle(device.device)) end return end diff --git a/src/models/load_models.jl b/src/models/load_models.jl index 91df466bb..1fde8359d 100644 --- a/src/models/load_models.jl +++ b/src/models/load_models.jl @@ -44,9 +44,6 @@ function mdl_zip_load!( current_i::AbstractArray{T}, wrapper::StaticLoadWrapper, ) where {T <: ACCEPTED_REAL_TYPES} - # Load device parameters - _, _, P_power, P_current, P_impedance, Q_power, Q_current, Q_impedance = - device_parameters #V0_mag_inv = 1.0 / get_V_ref(wrapper) V0_mag_inv = 1.0 / PSY.get_magnitude(PSY.get_bus(wrapper)) V0_mag_sq_inv = V0_mag_inv^2 @@ -55,6 +52,13 @@ function mdl_zip_load!( V_mag_inv = 1.0 / V_mag V_mag_sq_inv = V_mag_inv^2 + # Load device parameters + P_power = get_P_power(wrapper) + P_current = get_P_current(wrapper) + P_impedance = get_P_impedance(wrapper) + Q_power = get_Q_power(wrapper) + Q_current = get_Q_current(wrapper) + Q_impedance = get_Q_impedance(wrapper) exp_params = get_exp_params(wrapper) Ir_exp = zero(T) Ii_exp = zero(T) diff --git a/src/models/source_models.jl b/src/models/source_models.jl index c9e673409..288ff5c32 100644 --- a/src/models/source_models.jl +++ b/src/models/source_models.jl @@ -7,9 +7,9 @@ function mdl_source!( static_device::StaticWrapper{PSY.Source}, ) where {T <: ACCEPTED_REAL_TYPES} #Load device parameters - R_th, X_th, internal_voltage, internal_angle = device_parameters - V_R = internal_voltage * cos(internal_angle) - V_I = internal_voltage * sin(internal_angle) + R_th, X_th = device_parameters + V_R = get_V_ref(static_device) * cos(get_θ_ref(static_device)) + V_I = get_V_ref(static_device) * sin(get_θ_ref(static_device)) Zmag = R_th^2 + X_th^2 #update current diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index c310cde85..ec1beedf7 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -47,46 +47,8 @@ get_params_metadata(::PSY.Line) = [ ParamsMetadata(:r, false, true, true, true), ParamsMetadata(:x, false, true, true, true), ] - -function get_params(d::StaticLoadWrapper) - loads = get_loads(d) - bus = PSY.get_bus(d) - V_ref = PSY.get_magnitude(bus) - Θ_ref = PSY.get_angle(bus) - sys_base_power = get_system_base_power(d) - P_power = 0.0 - P_current = 0.0 - P_impedance = 0.0 - Q_power = 0.0 - Q_current = 0.0 - Q_impedance = 0.0 - for ld in loads - base_power_conversion = PSY.get_base_power(ld) / sys_base_power - if isa(ld, PSY.PowerLoad) - P_power += PSY.get_active_power(ld) * base_power_conversion - Q_power += PSY.get_reactive_power(ld) * base_power_conversion - elseif isa(ld, PSY.StandardLoad) - P_impedance += PSY.get_impedance_active_power(ld) * base_power_conversion - Q_impedance += PSY.get_impedance_reactive_power(ld) * base_power_conversion - P_current += PSY.get_current_active_power(ld) * base_power_conversion - Q_current += PSY.get_current_reactive_power(ld) * base_power_conversion - P_power += PSY.get_constant_active_power(ld) * base_power_conversion - Q_power += PSY.get_constant_reactive_power(ld) * base_power_conversion - end - end - return [V_ref, Θ_ref, P_power, P_current, P_impedance, Q_power, Q_current, Q_impedance] -end -get_params_metadata(::StaticLoadWrapper) = [ - ParamsMetadata(:V_ref, false, false, true, true), - ParamsMetadata(:Θ_ref, false, false, true, true), - ParamsMetadata(:P_power, false, false, true, true), - ParamsMetadata(:P_current, false, false, true, true), - ParamsMetadata(:P_impedance, false, false, true, true), - ParamsMetadata(:Q_power, false, false, true, true), - ParamsMetadata(:Q_current, false, false, true, true), - ParamsMetadata(:Q_impedance, false, false, true, true), -] - +get_params(::StaticLoadWrapper) = Float64[] +get_params_metadata(::StaticLoadWrapper) = ParamsMetadata[] ########### INVERTERS ############# function get_params(g::PSY.DynamicInverter) vcat( @@ -857,14 +819,10 @@ get_params_metadata(::PSY.STAB1) = [ get_params(x::PSY.Source) = [ PSY.get_R_th(x), PSY.get_X_th(x), - PSY.get_internal_voltage(x), - PSY.get_internal_angle(x), ] get_params_metadata(::PSY.Source) = [ ParamsMetadata(:R_th, false, false, true, false), ParamsMetadata(:X_th, false, false, true, false), - ParamsMetadata(:internal_voltage, false, false, true, false), #set during initialization -- incompatible with sensitivity analysis? - ParamsMetadata(:internal_angle, false, false, true, false), #set during initialization -- incompatible with sensitivity analysis? ] #Parameters not implemented for PeriodicVariableSource - requires change in PSY Struct to have information required to construct and deconstruct parameter vector diff --git a/test/test_base.jl b/test/test_base.jl index ad6fadeff..3b209c991 100644 --- a/test/test_base.jl +++ b/test/test_base.jl @@ -533,14 +533,12 @@ end lref_affect_f(integrator_for_test) zip_load1 = first(filter(x -> PSY.get_name(x) == "BUS 1", PSID.get_static_loads(inputs))) - p_ix1 = PSID.get_p_range(zip_load1) - @test integrator_for_test.p[p_ix1][5] == 10.0 + @test PSID.get_P_impedance(zip_load1) == 10.0 ltrip_affect_f(integrator_for_test) zip_load2 = first(filter(x -> PSY.get_name(x) == "BUS 2", PSID.get_static_loads(inputs))) - p_ix2 = PSID.get_p_range(zip_load2) - @test integrator_for_test.p[p_ix2][5] == 0.0 - @test integrator_for_test.p[p_ix2][8] == 0.0 + @test PSID.get_P_impedance(zip_load2) == 0.0 + @test PSID.get_Q_impedance(zip_load2) == 0.0 end @testset "Global Index" begin diff --git a/test/test_case_sensitivity.jl b/test/test_case_sensitivity.jl index fd342c327..05a2e14c6 100644 --- a/test/test_case_sensitivity.jl +++ b/test/test_case_sensitivity.jl @@ -44,6 +44,7 @@ s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) execute!( sim, solver; + sensealg = ForwardDiffSensitivity(), abstol = tol, reltol = tol, dtmax = 0.005, @@ -88,7 +89,13 @@ end t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) function f(sim) - execute!(sim, FBDF(; autodiff = true); dtmax = 0.005, saveat = 0.005) + execute!( + sim, + FBDF(; autodiff = true); + sensealg = ForwardDiffSensitivity(), + dtmax = 0.005, + saveat = 0.005, + ) res = read_results(sim) t, δ = get_state_series(res, ("generator-102-1", :δ)) #display(plot(scatter(x=t, y = δ))) @@ -182,6 +189,7 @@ end execute!( sim, solver; + sensealg = ForwardDiffSensitivity(), abstol = tol, reltol = tol, dtmax = 0.005, @@ -259,6 +267,7 @@ end execute!( sim, MethodOfSteps(Rodas5(; autodiff = true)); + sensealg = ForwardDiffSensitivity(), abstol = 1e-6, reltol = 1e-6, dtmax = 0.005, @@ -293,7 +302,7 @@ end callback = callback, maxiters = 3, ) - @test sol.u[1] == 3.1440015515797763 + @test isapprox(sol.u[1], 3.144001551579776, atol = 1e-8) #display(plot(scatter(y=H_values))) #display(plot(scatter(y=loss_values))) finally From 37d9ff99f9fe0e5ffce3d4db1a24bcffc6723741 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 2 May 2024 17:25:14 -0400 Subject: [PATCH 10/76] add additional input in sensitivity api --- src/base/sensitivity_analysis.jl | 6 ++--- test/test_case_sensitivity.jl | 38 +++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index dc056c026..c9e762cae 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -9,7 +9,7 @@ Gets a function for taking gradients with respect to parameters. # Arguments - `sim::Simulation` : Initialized simulation object - `device_parameter_pairs::Vector{Tuple{String, Type{T}, Symbol}}` : Tuple used to identify the parameter, via the device name, as a `String`, the type of the Device or DynamicComponent, and the parameter as a `Symbol`. -- `f::function` : User provided function with input a simulation and output a scalar value. This function can include executing the simulation and post-processing of results +- `f::function` : User provided function with two inputs: a simulation and an additional input which can be used for data (```f(sim::Simulation, data::Any)```) The output must be a scalar value. This function can include executing the simulation and post-processing of results. # Example ```julia @@ -36,12 +36,12 @@ function get_parameter_sensitivity_function!(sim, device_param_pairs, f) @assert sim.status == BUILT sim.initialize_level = sim_level sim.enable_sensitivity = true - sensitivity_function = (p) -> + sensitivity_function = (p, data) -> begin sim.inputs = deepcopy(sim.inputs_init) set_parameters!(sim, indices, p) reset!(sim) - return f(sim) + return f(sim, data) end return sensitivity_function end diff --git a/test/test_case_sensitivity.jl b/test/test_case_sensitivity.jl index 05a2e14c6..5b81c245f 100644 --- a/test/test_case_sensitivity.jl +++ b/test/test_case_sensitivity.jl @@ -17,7 +17,7 @@ ieee_9bus_sys = build_system(PSIDTestSystems, "psid_test_ieee_9bus") s_device = get_component(Source, omib_sys, "InfBus") s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) -#using PlotlyJS #for debug only +#using PlotlyJS #NOTES ON SENSITIVITY ALGORITHMS FROM SCIMLSENSITIVITY #ReverseDiffVJP and EnzymeVJP only options compatible with Hybrid DEs (DEs with callbacks) @@ -40,7 +40,7 @@ s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) for solver in [FBDF(), Rodas5(), QNDF()] for tol in [1e-6, 1e-9] - function f(sim) + function f(sim, δ_gt) execute!( sim, solver; @@ -62,8 +62,16 @@ s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) ) #p = PSID.get_parameter_sensitivity_values(sim, [("generator-102-1", SingleMass, :H)]) #@error Zygote.gradient(g, [3.15])[1][1] - @test isapprox(Zygote.gradient(g, [3.14])[1][1], -8.0, atol = 1.0) - @test isapprox(Zygote.gradient(g, [3.15])[1][1], 8.0, atol = 1.0) + @test isapprox( + Zygote.gradient((p) -> g(p, δ_gt), [3.14])[1][1], + -8.0, + atol = 1.0, + ) + @test isapprox( + Zygote.gradient((p) -> g(p, δ_gt), [3.15])[1][1], + 8.0, + atol = 1.0, + ) end end finally @@ -88,7 +96,7 @@ end res = read_results(sim) t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) - function f(sim) + function f(sim, δ_gt) execute!( sim, FBDF(; autodiff = true); @@ -117,7 +125,7 @@ end #push!(loss_values, l) return false end - optfun = OptimizationFunction((u, _) -> g(u), Optimization.AutoZygote()) + optfun = OptimizationFunction((u, _) -> g(u, δ_gt), Optimization.AutoZygote()) optprob = OptimizationProblem(optfun, [3.14]) sol = Optimization.solve( optprob, @@ -185,7 +193,7 @@ end MethodOfSteps(QNDF(; autodiff = true)), ] for tol in [1e-6] - function f(sim) + function f(sim, δ_gt) execute!( sim, solver; @@ -207,8 +215,16 @@ end ) #p = PSID.get_parameter_sensitivity_values(sim, [("generator-102-1", SingleMass, :H)]) #display(Zygote.gradient(g, [3.14])) - @test isapprox(Zygote.gradient(g, [3.14])[1][1], -10.0, atol = 1.0) - @test isapprox(Zygote.gradient(g, [3.15])[1][1], 10.0, atol = 1.0) + @test isapprox( + Zygote.gradient((p) -> g(p, δ_gt), [3.14])[1][1], + -10.0, + atol = 1.0, + ) + @test isapprox( + Zygote.gradient((p) -> g(p, δ_gt), [3.15])[1][1], + 10.0, + atol = 1.0, + ) end end finally @@ -263,7 +279,7 @@ end res = read_results(sim) t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) - function f(sim) + function f(sim, δ_gt) execute!( sim, MethodOfSteps(Rodas5(; autodiff = true)); @@ -294,7 +310,7 @@ end #push!(loss_values, l) return false end - optfun = OptimizationFunction((u, _) -> g(u), Optimization.AutoZygote()) + optfun = OptimizationFunction((u, _) -> g(u, δ_gt), Optimization.AutoZygote()) optprob = OptimizationProblem(optfun, [3.14]) sol = Optimization.solve( optprob, From 2b469adeecfa2451d0f9a8f5e1a1abcff9c862cc Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 2 May 2024 17:25:30 -0400 Subject: [PATCH 11/76] loosen tolerance on optimization result --- test/test_case_sensitivity.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_case_sensitivity.jl b/test/test_case_sensitivity.jl index 5b81c245f..dca5945b9 100644 --- a/test/test_case_sensitivity.jl +++ b/test/test_case_sensitivity.jl @@ -133,7 +133,7 @@ end callback = callback, maxiters = 3, ) - @test isapprox(sol.u[1], 3.144000187737475, atol = 1e-8) + @test isapprox(sol.u[1], 3.144000187737475, atol = 1e-7) #display(plot(scatter(y=H_values))) #display(plot(scatter(y=loss_values))) finally @@ -318,7 +318,7 @@ end callback = callback, maxiters = 3, ) - @test isapprox(sol.u[1], 3.144001551579776, atol = 1e-8) + @test isapprox(sol.u[1], 3.144001551579776, atol = 1e-7) #display(plot(scatter(y=H_values))) #display(plot(scatter(y=loss_values))) finally From 561954d2103c20a6816ca1650d0b13d0075b1ed9 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sat, 4 May 2024 08:47:35 -0400 Subject: [PATCH 12/76] reduce tolerance on sensitivity test --- test/test_case_sensitivity.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_case_sensitivity.jl b/test/test_case_sensitivity.jl index dca5945b9..ddf6ec665 100644 --- a/test/test_case_sensitivity.jl +++ b/test/test_case_sensitivity.jl @@ -133,7 +133,7 @@ end callback = callback, maxiters = 3, ) - @test isapprox(sol.u[1], 3.144000187737475, atol = 1e-7) + @test isapprox(sol.u[1], 3.144000187737475, atol = 1e-6) #display(plot(scatter(y=H_values))) #display(plot(scatter(y=loss_values))) finally @@ -318,7 +318,7 @@ end callback = callback, maxiters = 3, ) - @test isapprox(sol.u[1], 3.144001551579776, atol = 1e-7) + @test isapprox(sol.u[1], 3.144001551579776, atol = 1e-6) #display(plot(scatter(y=H_values))) #display(plot(scatter(y=loss_values))) finally From a80a9ce01374b77ae8b2bb9ac1476855ceb8630f Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 30 May 2024 08:24:08 -0400 Subject: [PATCH 13/76] not complete; start clean to revert some changes --- Project.toml | 14 +- src/PowerSimulationsDynamics.jl | 22 +- src/base/definitions.jl | 1 - src/base/device_wrapper.jl | 67 +- src/base/jacobian.jl | 29 +- src/base/nlsolve_wrapper.jl | 83 ++- src/base/perturbations.jl | 6 +- src/base/simulation.jl | 4 +- src/base/simulation_initialization.jl | 178 ++---- src/base/simulation_inputs.jl | 62 +- src/base/small_signal.jl | 2 +- .../generator_components/init_avr.jl | 26 +- .../generator_components/init_machine.jl | 91 ++- .../generator_components/init_tg.jl | 48 +- src/initialization/init_device.jl | 28 +- .../inverter_components/init_filter.jl | 21 +- .../inverter_components/init_outer.jl | 63 +- src/models/device.jl | 29 +- src/models/generator_models/avr_models.jl | 15 +- src/models/generator_models/machine_models.jl | 48 +- src/models/generator_models/pss_models.jl | 8 +- src/models/generator_models/shaft_models.jl | 7 +- src/models/generator_models/tg_models.jl | 31 +- src/models/inverter_models/filter_models.jl | 14 +- .../inverter_models/outer_control_models.jl | 86 +-- src/models/source_models.jl | 13 +- src/models/system.jl | 16 +- src/utils/parameters.jl | 570 +++++++++--------- test/Project.toml | 1 + test/runtests.jl | 5 + 30 files changed, 756 insertions(+), 832 deletions(-) diff --git a/Project.toml b/Project.toml index 050949752..c656355a5 100644 --- a/Project.toml +++ b/Project.toml @@ -4,17 +4,18 @@ authors = ["Jose Daniel Lara, Rodrigo Henriquez"] version = "0.14.1" [deps] -Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" FastClosures = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" -NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" +NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" PowerFlows = "94fada2c-fd9a-4e89-8d82-81405f5cb4f6" PowerNetworkMatrices = "bed98974-b02a-5e2f-9fe0-a103f5c450dd" PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd" @@ -23,27 +24,26 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" -Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [compat] -Accessors = "0.1.36" ChainRulesCore = "1.23" +ComponentArrays = "0.15" DataFrames = "1" DataStructures = "~0.18" DocStringExtensions = "~0.9" +Enzyme = "0.12" FastClosures = "^0.3" ForwardDiff = "~v0.10" InfrastructureSystems = "^1.21" LinearAlgebra = "1" Logging = "1" -NLsolve = "4" +NonlinearSolve = "3.11" PowerFlows = "^0.6" -PowerNetworkMatrices = "^0.9" +PowerNetworkMatrices = "^0.10" PowerSystems = "^3.1.2" PrettyTables = "1, 2" Random = "1" SciMLBase = "2" SparseArrays = "1" TimerOutputs = "~0.5" -Zygote = "0.6" julia = "^1.6" diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index b6e4645d3..9051b968b 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -61,8 +61,9 @@ export is_valid export transform_load_to_constant_impedance export transform_load_to_constant_current export transform_load_to_constant_power -export get_parameter_sensitivity_function! -export get_parameter_sensitivity_values +export get_parameter_values +export get_forward_function +export get_gradient_function ####################################### Package Imports #################################### import Logging @@ -75,7 +76,7 @@ import ForwardDiff import SparseArrays import LinearAlgebra import Base.to_index -import NLsolve +import NonlinearSolve import PrettyTables import Base.ImmutableDict import PowerSystems @@ -83,9 +84,20 @@ import PowerFlows import PowerNetworkMatrices import TimerOutputs import FastClosures: @closure -import Zygote +import Enzyme +Enzyme.API.runtimeActivity!(true) +Enzyme.API.looseTypeAnalysis!(true) #Required for using component arrays with Enzyme +Enzyme.API.maxtypeoffset!(1024) +Enzyme.API.maxtypedepth!(20) +#Enzyme.API.runtimeActivity!(true) +#= Generally, the preferred solution to these type of activity unstable codes should be to make +your variables all activity-stable (e.g. always containing differentiable memory or always + containing non-differentiable memory). However, with care, Enzyme does support "Runtime Activity" + as a way to differentiate these programs without having to modify your code. =# +#Enzyme.API.looseTypeAnalysis!(true) #Best guess if it cannot determine the type; this was needed for using ComponentArrays/ODEFunction +#Enzyme.API.maxtypedepth!(20) import ChainRulesCore -import Accessors +import ComponentArrays const PSY = PowerSystems const IS = InfrastructureSystems diff --git a/src/base/definitions.jl b/src/base/definitions.jl index 3c8551003..33b935b06 100644 --- a/src/base/definitions.jl +++ b/src/base/definitions.jl @@ -126,7 +126,6 @@ get_vars_ix() = Dict{Int, Int}(GLOBAL_VAR_SYS_FREQ_INDEX => -1) const RELAXED_NLSOLVE_F_TOLERANCE = :1e-6 const STRICT_NLSOLVE_F_TOLERANCE = :1e-9 -const NLSOLVE_X_TOLERANCE = :1e-9 const MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE = :1e-4 const MAX_INIT_RESIDUAL = 10.0 const MAX_NLSOLVE_INTERATIONS = 10 diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index c02a425f2..22cd85b18 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -44,11 +44,9 @@ struct DynamicWrapper{T <: PSY.DynamicInjection} inner_vars_index::Vector{Int} ix_range::Vector{Int} ode_range::Vector{Int} - p_range::Vector{Int} bus_ix::Int global_index::Base.ImmutableDict{Symbol, Int} component_state_mapping::Base.ImmutableDict{Int, Vector{Int}} - component_parameter_mapping::Base.ImmutableDict{Int, Vector{Int}} input_port_mapping::Base.ImmutableDict{Int, Vector{Int}} ext::Dict{String, Any} @@ -66,11 +64,9 @@ struct DynamicWrapper{T <: PSY.DynamicInjection} inner_vars_index, ix_range, ode_range, - p_range, bus_ix::Int, global_index::Base.ImmutableDict{Symbol, Int}, component_state_mapping::Base.ImmutableDict{Int, Vector{Int}}, - component_parameter_mapping::Base.ImmutableDict{Int, Vector{Int}}, input_port_mapping::Base.ImmutableDict{Int, Vector{Int}}, ext::Dict{String, Any}, ) where {T <: PSY.DynamicInjection} @@ -90,11 +86,9 @@ struct DynamicWrapper{T <: PSY.DynamicInjection} Vector{Int}(inner_vars_index), Vector{Int}(ix_range), Vector{Int}(ode_range), - Vector{Int}(p_range), bus_ix, global_index, component_state_mapping, - component_parameter_mapping, input_port_mapping, ext, ) @@ -121,29 +115,6 @@ function state_port_mappings(dynamic_device::PSY.DynamicInjection, device_states return (component_state_mapping, input_port_mapping) end -function parameter_mappings( - dynamic_device::T, - device_parameters, -) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} - component_parameter_mapping = Dict{Int, Vector{Int}}() - for c in PSY.get_dynamic_components(dynamic_device) - ix = index(typeof(c)) - component_parameter_mapping[ix] = _index_local_parameters(c, device_parameters) - end - return component_parameter_mapping -end - -function parameter_mappings(dynamic_device::PSY.DynamicInjection, device_parameters) - return Dict{Int, Vector{Int}}() -end - -function _get_parameter_symbols( - dynamic_device::PSY.DynamicInjection, - static_device::PSY.StaticInjection, -) - return get_params_symbol(dynamic_device) -end - function DynamicWrapper( static_device::T, dynamic_device::D, @@ -156,13 +127,8 @@ function DynamicWrapper( sys_base_freq, ) where {T <: PSY.StaticInjection, D <: PSY.DynamicInjection} device_states = PSY.get_states(dynamic_device) - device_parameters = _get_parameter_symbols(dynamic_device, static_device) - #Parameter mappings depend on unique parameters per device - @assert allunique(device_parameters) - component_state_mapping, input_port_mapping = state_port_mappings(dynamic_device, device_states) - component_parameter_mapping = parameter_mappings(dynamic_device, device_parameters) # Consider the special case when the static device is StandardLoad if isa(static_device, PSY.StandardLoad) reactive_power = PF.get_total_q(static_device) @@ -183,7 +149,6 @@ function DynamicWrapper( inner_var_range, ix_range, ode_range, - p_range, bus_ix, Base.ImmutableDict( sort!(device_states .=> ix_range; by = x -> x.second, rev = true)..., @@ -193,11 +158,6 @@ function DynamicWrapper( else Base.ImmutableDict(component_state_mapping...) end, - if isempty(component_parameter_mapping) - Base.ImmutableDict{Int, Vector{Int}}() - else - Base.ImmutableDict(component_parameter_mapping...) - end, if isempty(input_port_mapping) Base.ImmutableDict{Int, Vector{Int}}() else @@ -213,7 +173,6 @@ function DynamicWrapper( bus_ix::Int, ix_range, ode_range, - p_range, inner_var_range, sys_base_power, sys_base_freq, @@ -238,7 +197,6 @@ function DynamicWrapper( inner_var_range, ix_range, ode_range, - p_range, bus_ix, Base.ImmutableDict( sort!(device_states .=> ix_range; by = x -> x.second, rev = true)..., @@ -248,7 +206,6 @@ function DynamicWrapper( else Base.ImmutableDict(component_state_mapping...) end, - Base.ImmutableDict{Int, Vector{Int}}(), if isempty(input_port_mapping) Base.ImmutableDict{Int, Vector{Int}}() else @@ -264,7 +221,6 @@ function DynamicWrapper( bus_ix::Int, ix_range, ode_range, - p_range, inner_var_range, sys_base_power, sys_base_freq, @@ -287,28 +243,14 @@ function DynamicWrapper( collect(inner_var_range), collect(ix_range), collect(ode_range), - collect(p_range), bus_ix, Base.ImmutableDict(Dict(device_states .=> ix_range)...), Base.ImmutableDict{Int, Vector{Int}}(), Base.ImmutableDict{Int, Vector{Int}}(), - Base.ImmutableDict{Int, Vector{Int}}(), Dict{String, Any}(), ) end -function _index_local_parameters( - component::PSY.DynamicComponent, - device_parameters::Vector{Symbol}, -) - component_paramter_index = Vector{Int}(undef, length(get_params(component))) - component_parameters = get_params_symbol(component) - for (ix, s) in enumerate(component_parameters) - component_paramter_index[ix] = findfirst(x -> x == s, device_parameters) - end - return component_paramter_index -end - function _index_local_states(component::PSY.DynamicComponent, device_states::Vector{Symbol}) component_state_index = Vector{Int}(undef, PSY.get_n_states(component)) component_states = PSY.get_states(component) @@ -338,12 +280,9 @@ get_bus_category(wrapper::DynamicWrapper) = wrapper.bus_category get_inner_vars_index(wrapper::DynamicWrapper) = wrapper.inner_vars_index get_ix_range(wrapper::DynamicWrapper) = wrapper.ix_range get_ode_ouput_range(wrapper::DynamicWrapper) = wrapper.ode_range -get_p_range(wrapper::DynamicWrapper) = wrapper.p_range get_bus_ix(wrapper::DynamicWrapper) = wrapper.bus_ix get_global_index(wrapper::DynamicWrapper) = wrapper.global_index get_component_state_mapping(wrapper::DynamicWrapper) = wrapper.component_state_mapping -get_component_parameter_mapping(wrapper::DynamicWrapper) = - wrapper.component_parameter_mapping get_input_port_mapping(wrapper::DynamicWrapper) = wrapper.input_port_mapping get_ext(wrapper::DynamicWrapper) = wrapper.ext @@ -436,7 +375,7 @@ struct StaticWrapper{T <: PSY.StaticInjection, V} θ_ref::Base.RefValue{Float64} P_ref::Base.RefValue{Float64} Q_ref::Base.RefValue{Float64} - p_range::Vector{Int} + #p_range::Vector{Int} bus_ix::Int ext::Dict{String, Any} end @@ -465,7 +404,7 @@ function StaticWrapper(device::T, bus_ix::Int, p_range) where {T <: PSY.Source} Base.Ref(PSY.get_internal_angle(device)), Base.Ref(PSY.get_active_power(device)), Base.Ref(PSY.get_reactive_power(device)), - p_range, + #p_range, bus_ix, Dict{String, Any}(), ) @@ -476,7 +415,7 @@ get_bus_category(::StaticWrapper{<:PSY.StaticInjection, U}) where {U} = U # TODO: something smart to forward fields get_device(wrapper::StaticWrapper) = wrapper.device -get_p_range(wrapper::StaticWrapper) = wrapper.p_range +#get_p_range(wrapper::StaticWrapper) = wrapper.p_range get_bus_ix(wrapper::StaticWrapper) = wrapper.bus_ix get_ext(wrapper::StaticWrapper) = wrapper.ext diff --git a/src/base/jacobian.jl b/src/base/jacobian.jl index f9c724b71..67a7c30b2 100644 --- a/src/base/jacobian.jl +++ b/src/base/jacobian.jl @@ -22,12 +22,33 @@ end function (J::JacobianFunctionWrapper{NoDelays})( JM::U, x::AbstractVector{Float64}, + p, ) where {U <: Union{Matrix{Float64}, SparseArrays.SparseMatrixCSC{Float64, Int64}}} J.x .= x J.Jf(JM, x) return end +function (J::JacobianFunctionWrapper{NoDelays})( + JM::U, + x::AbstractVector{Float64}, +) where {U <: Union{Matrix{Float64}, SparseArrays.SparseMatrixCSC{Float64, Int64}}} + J.x .= x + J.Jf(JM, x) + return +end + +function (J::JacobianFunctionWrapper{HasDelays})( + JM::U, + x::AbstractVector{Float64}, + p, +) where {U <: Union{Matrix{Float64}, SparseArrays.SparseMatrixCSC{Float64, Int64}}} + h(p, t; idxs = nothing) = typeof(idxs) <: Number ? x[idxs] : x + J.x .= x + J.Jf(JM, x, h, 0.0) + return +end + function (J::JacobianFunctionWrapper{HasDelays})( JM::U, x::AbstractVector{Float64}, @@ -88,7 +109,7 @@ end function JacobianFunctionWrapper( m!::SystemModel{MassMatrixModel, NoDelays}, x0_guess::Vector{Float64}, - p::Vector{Float64}; + p::AbstractArray{Float64}; # Improve the heuristic to do sparsity detection sparse_retrieve_loop::Int = 0, #max(3, length(x0_guess) ÷ 100), ) @@ -129,7 +150,7 @@ end function JacobianFunctionWrapper( m!::SystemModel{ResidualModel}, x0::Vector{Float64}, - p::Vector{Float64}; + p::AbstractArray{Float64}; # Improve the heuristic to do sparsity detection sparse_retrieve_loop::Int = max(3, length(x0) ÷ 100), ) @@ -170,7 +191,7 @@ end function JacobianFunctionWrapper( m!::SystemModel{MassMatrixModel, HasDelays}, x0_guess::Vector{Float64}, - p::Vector{Float64}; + p::AbstractArray{Float64}; # Improve the heuristic to do sparsity detection sparse_retrieve_loop::Int = 0, #max(3, length(x0_guess) ÷ 100), ) @@ -213,7 +234,7 @@ function get_jacobian( ::Type{T}, inputs::SimulationInputs, x0_init::Vector{Float64}, - p::Vector{Float64}, + p::AbstractArray{Float64}, sparse_retrieve_loop::Int, ) where {T <: SimulationModel} return JacobianFunctionWrapper( diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index cf2d90f1c..98bfbd7d9 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -11,78 +11,58 @@ failed(sol::NLsolveWrapper) = sol.failed function _get_model_closure( model::SystemModel{MassMatrixModel, NoDelays}, ::Vector{Float64}, - p::Vector{Float64}, + p::AbstractArray{Float64}, ) - return (residual, x) -> model(residual, x, p, 0.0) + return (residual, x, p) -> model(residual, x, p, 0.0) end function _get_model_closure( model::SystemModel{MassMatrixModel, HasDelays}, x0::Vector{Float64}, - p::Vector{Float64}, + p::AbstractArray{Float64}, ) h(p, t; idxs = nothing) = typeof(idxs) <: Number ? x0[idxs] : x0 - return (residual, x) -> model(residual, x, h, p, 0.0) + return (residual, x, p) -> model(residual, x, h, p, 0.0) end function _get_model_closure( model::SystemModel{ResidualModel, NoDelays}, x0::Vector{Float64}, - p::Vector{Float64}, + p::AbstractArray{Float64}, ) dx0 = zeros(length(x0)) - return (residual, x) -> model(residual, dx0, x, p, 0.0) + return (residual, x, p) -> model(residual, dx0, x, p, 0.0) end function _nlsolve_call( initial_guess::Vector{Float64}, + p::AbstractArray, f_eval::Function, jacobian::JacobianFunctionWrapper, f_tolerance::Float64, - solver::Symbol, + solver::NonlinearSolve.AbstractNonlinearSolveAlgorithm, show_trace::Bool, ) - df = NLsolve.OnceDifferentiable( - f_eval, - jacobian, - initial_guess, - similar(initial_guess), - jacobian.Jv, + f = SciMLBase.NonlinearFunction(f_eval; jac = jacobian) + prob = NonlinearSolve.NonlinearProblem(f, initial_guess, p) + sol = NonlinearSolve.solve( + prob, + solver; + abstol = f_tolerance, + reltol = f_tolerance, + maxiters = MAX_NLSOLVE_INTERATIONS, + show_trace = Val(show_trace), ) - sys_solve = NLsolve.nlsolve( - df, - initial_guess; - xtol = NLSOLVE_X_TOLERANCE, - ftol = f_tolerance, - method = solver, - iterations = MAX_NLSOLVE_INTERATIONS, - show_trace = show_trace, - ) # Solve using initial guess x0 - return NLsolveWrapper(sys_solve.zero, NLsolve.converged(sys_solve), false) + return NLsolveWrapper(sol.u, SciMLBase.successful_retcode(sol), false) end -function _nlsolve_call( - initial_guess::Vector{Float64}, - f_eval::Function, - f_tolerance::Float64, - solver::Symbol, - show_trace::Bool, +function _convergence_check( + sys_solve::NLsolveWrapper, + tol::Float64, + solv::NonlinearSolve.AbstractNonlinearSolveAlgorithm, ) - sys_solve = NLsolve.nlsolve( - f_eval, - initial_guess; - xtol = NLSOLVE_X_TOLERANCE, - ftol = f_tolerance, - iterations = MAX_NLSOLVE_INTERATIONS, - method = solver, - show_trace = show_trace, - ) # Solve using initial guess x0 - return NLsolveWrapper(sys_solve.zero, NLsolve.converged(sys_solve), false) -end - -function _convergence_check(sys_solve::NLsolveWrapper, tol::Float64, solv::Symbol) if converged(sys_solve) - CRC.@ignore_derivatives @info( + CRC.@ignore_derivatives @warn( "Initialization non-linear solve succeeded with a tolerance of $(tol) using solver $(solv). Saving solution." ) else @@ -162,17 +142,24 @@ function refine_initial_condition!( powerflow_solution = deepcopy(initial_guess[bus_range]) f! = _get_model_closure(model, initial_guess, parameters) residual = similar(initial_guess) - f!(residual, initial_guess) + f!(residual, initial_guess, parameters) _check_residual(residual, inputs, MAX_INIT_RESIDUAL) for tol in [STRICT_NLSOLVE_F_TOLERANCE, RELAXED_NLSOLVE_F_TOLERANCE] if converged break end - for solv in [:trust_region, :newton] + for solv in [NonlinearSolve.TrustRegion(), NonlinearSolve.NewtonRaphson()] CRC.@ignore_derivatives @debug "Start NLSolve System Run with $(solv) and F_tol = $tol" show_trace = sim.console_level <= Logging.Info - sys_solve = _nlsolve_call(initial_guess, f!, jacobian, tol, solv, show_trace) - #sys_solve = _nlsolve_call(initial_guess, f!, tol, solv, show_trace) + sys_solve = _nlsolve_call( + initial_guess, + parameters, + f!, + jacobian, + tol, + solv, + show_trace, + ) failed(sys_solve) && return BUILD_FAILED converged = _convergence_check(sys_solve, tol, solv) CRC.@ignore_derivatives @debug "Write initial guess vector using $solv with tol = $tol convergence = $converged" @@ -190,7 +177,7 @@ function refine_initial_condition!( ) end - f!(residual, initial_guess) + f!(residual, initial_guess, parameters) if !converged || (sum(residual) > MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE) _check_residual(residual, inputs, MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE) CRC.@ignore_derivatives @warn( diff --git a/src/base/perturbations.jl b/src/base/perturbations.jl index 6e4afbf1c..a0a4a2b8e 100644 --- a/src/base/perturbations.jl +++ b/src/base/perturbations.jl @@ -510,10 +510,12 @@ function get_affect(inputs::SimulationInputs, ::PSY.System, pert::SourceBusVolta wrapped_device_ix = _find_device_index(inputs, pert.device) return (integrator) -> begin wrapped_device = get_static_injectors(inputs)[wrapped_device_ix] + wrapped_device_name = _get_wrapper_name(wrapped_device) + refs = @view(@view(integrator.p[wrapped_device_name])[:refs]) if pert.signal == :V_ref - set_V_ref(wrapped_device, pert.ref_value) + refs[:V_ref] = pert.ref_value elseif pert.signal == :θ_ref - set_θ_ref(wrapped_device, pert.ref_value) + refs[:θ_ref] = pert.ref_value else error("Signal $signal not accepted as a control reference change in SourceBus") end diff --git a/src/base/simulation.jl b/src/base/simulation.jl index 0443a656e..4a8f7664a 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -1,5 +1,5 @@ mutable struct Simulation{T <: SimulationModel} - status::STATUS + status::STATUS problem::Union{Nothing, SciMLBase.DEProblem} tspan::NTuple{2, Float64} sys::PSY.System @@ -252,7 +252,7 @@ function _get_flat_start(inputs::SimulationInputs) end function _pre_initialize_simulation!(sim::Simulation) - _initialize_state_space(sim, Val(sim.initialize_level)) + _initialize_state_space(sim, Val(sim.initialize_level), Val(sim.enable_sensitivity)) return end diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index 40a72a260..d3499b532 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -25,76 +25,39 @@ function initialize_static_injection!(inputs::SimulationInputs) static_injection_devices = get_static_injectors(inputs) parameters = get_parameters(inputs) if !isempty(static_injection_devices) - try - for s in static_injection_devices - p_range = get_p_range(s) - local_parameters = @view parameters[p_range] - initialize_static_device!(s, local_parameters) - end - catch e - bt = catch_backtrace() - CRC.@ignore_derivatives @error "Static Injection Failed to Initialize" exception = - e, bt - return BUILD_FAILED + for s in static_injection_devices + local_parameters = @view parameters[_get_wrapper_name(s)] + initialize_static_device!(s, local_parameters) end end return BUILD_INCOMPLETE end -function _initialization_debug(dynamic_device, static, x0_device::Vector{Float64}) - residual = similar(x0_device) - Vm = PSY.get_magnitude(PSY.get_bus(static)) - θ = PSY.get_angle(PSY.get_bus(static)) - device!( - x0_device, - residual, - Vm * cos(θ), - Vm * sin(θ), - zeros(10), - zeros(10), - [1.0], - zeros(100), - dynamic_device, - 0, - ) - for (ix, state) in enumerate(PSY.get_states(dynamic_device)) - CRC.@ignore_derivatives @debug state residual[ix] - end - return -end - function initialize_dynamic_injection!( - initial_guess::Vector{Float64}, + initial_guess::AbstractArray, inputs::SimulationInputs, system::PSY.System, ) CRC.@ignore_derivatives @debug "Updating Dynamic Injection Component Initial Guess" initial_inner_vars = zeros(get_inner_vars_count(inputs)) parameters = get_parameters(inputs) - try - for dynamic_device in get_dynamic_injectors(inputs) - static = PSY.get_component( - dynamic_device.static_type, - system, - PSY.get_name(dynamic_device), - ) - CRC.@ignore_derivatives @debug "Initializing $(PSY.get_name(dynamic_device)) - $(typeof(dynamic_device.device))" - _inner_vars = @view initial_inner_vars[get_inner_vars_index(dynamic_device)] - _parameters = @view parameters[get_p_range(dynamic_device)] - _states = @view initial_guess[get_ix_range(dynamic_device)] - initialize_dynamic_device!( - dynamic_device, - static, - _inner_vars, - _parameters, - _states, - ) - end - catch e - bt = catch_backtrace() - CRC.@ignore_derivatives @error "Dynamic Injection Failed to Initialize" exception = - e, bt - return BUILD_FAILED + for dynamic_device in get_dynamic_injectors(inputs) + static = CRC.@ignore_derivatives PSY.get_component( + dynamic_device.static_type, + system, + PSY.get_name(dynamic_device), + ) + CRC.@ignore_derivatives @debug "Initializing $(PSY.get_name(dynamic_device)) - $(typeof(dynamic_device.device))" + _inner_vars = @view initial_inner_vars[get_inner_vars_index(dynamic_device)] + _parameters = @view parameters[_get_wrapper_name(dynamic_device)] + _states = @view initial_guess[get_ix_range(dynamic_device)] + initialize_dynamic_device!( + dynamic_device, + static, + _inner_vars, + _parameters, + _states, + ) end return BUILD_INCOMPLETE end @@ -104,19 +67,12 @@ function initialize_dynamic_branches!( inputs::SimulationInputs, ) parameters = get_parameters(inputs) - try - CRC.@ignore_derivatives @debug "Initializing Dynamic Branches" - for br in get_dynamic_branches(inputs) - CRC.@ignore_derivatives @debug "$(PSY.get_name(br)) - $(typeof(br))" - _parameters = @view parameters[get_p_range(br)] - _states = @view initial_guess[get_ix_range(br)] - initialize_dynamic_device!(br, _parameters, _states) - end - catch e - bt = catch_backtrace() - CRC.@ignore_derivatives @error "Dynamic Branches Failed to Initialize" exception = - e, bt - return BUILD_FAILED + CRC.@ignore_derivatives @debug "Initializing Dynamic Branches" + for br in get_dynamic_branches(inputs) + CRC.@ignore_derivatives @debug "$(PSY.get_name(br)) - $(typeof(br))" + _parameters = @view parameters[get_p_range(br)] + _states = @view initial_guess[get_ix_range(br)] + initialize_dynamic_device!(br, _parameters, _states) end return BUILD_INCOMPLETE end @@ -155,38 +111,30 @@ function check_valid_values(initial_guess::Vector{Float64}, inputs::SimulationIn return BUILD_IN_PROGRESS end -# Default implementation for both models. This implementation is to future proof if there is -# a divergence between the required build methods -function _calculate_initial_guess!(sim::Simulation, ::Val{POWERFLOW_AND_DEVICES}) - CRC.@ignore_derivatives @info("Pre-Initializing Simulation States") - inputs = get_simulation_inputs(sim) - @assert sim.status == BUILD_INCOMPLETE - while sim.status == BUILD_INCOMPLETE - CRC.@ignore_derivatives @debug "Start state intialization routine" - TimerOutputs.@timeit BUILD_TIMER "Power Flow solution" begin - sim.status = power_flow_solution!(sim.x0, get_system(sim), inputs) - end - TimerOutputs.@timeit BUILD_TIMER "Initialize Static Injectors" begin - sim.status = initialize_static_injection!(inputs) - end - TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Injectors" begin - sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) - end - if has_dyn_lines(inputs) - TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Branches" begin - sim.status = initialize_dynamic_branches!(sim.x0, inputs) - end - else - CRC.@ignore_derivatives @debug "No Dynamic Branches in the system" - end - sim.status = check_valid_values(sim.x0, inputs) - end - return +#Setter functions for CA +function set_V_ref!(array, value) + @view(array["refs"])["V_ref"] = value +end +function set_ω_ref!(array, value) + @view(array["refs"])["ω_ref"] = value +end +function set_θ_ref!(array, value) + @view(array["refs"])["θ_ref"] = value +end +function set_P_ref!(array, value) + @view(array["refs"])["P_ref"] = value +end +function set_Q_ref!(array, value) + @view(array["refs"])["Q_ref"] = value end +# Default implementation for both models. This implementation is to future proof if there is +# a divergence between the required build methods +#PASS x0, not sim....? function _initialize_state_space( sim::Simulation{T}, ::Val{POWERFLOW_AND_DEVICES}, + ::Val{false}, #not yet supported with sensitivity analysis ) where {T <: SimulationModel} inputs = get_simulation_inputs(sim) sim.x0 = _get_flat_start(inputs) @@ -194,19 +142,11 @@ function _initialize_state_space( @assert sim.status == BUILD_INCOMPLETE while sim.status == BUILD_INCOMPLETE CRC.@ignore_derivatives @debug "Start state intialization routine" - TimerOutputs.@timeit BUILD_TIMER "Power Flow solution" begin - sim.status = power_flow_solution!(sim.x0, get_system(sim), inputs) - end - TimerOutputs.@timeit BUILD_TIMER "Initialize Static Injectors" begin - sim.status = initialize_static_injection!(inputs) - end - TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Injectors" begin - sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) - end + sim.status = power_flow_solution!(sim.x0, get_system(sim), inputs) + sim.status = initialize_static_injection!(inputs) + sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) if has_dyn_lines(inputs) - TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Branches" begin - sim.status = initialize_dynamic_branches!(sim.x0, inputs) - end + sim.status = initialize_dynamic_branches!(sim.x0, inputs) else CRC.@ignore_derivatives @debug "No Dynamic Branches in the system" end @@ -214,25 +154,23 @@ function _initialize_state_space( end end +#GET rid of try catch at that level. +#GET rid of timing at that level function _initialize_state_space( sim::Simulation{T}, ::Val{DEVICES_ONLY}, + ::Val{false}, #not yet supported with sensitivity analysis ) where {T <: SimulationModel} CRC.@ignore_derivatives @info("Pre-Initializing Simulation States") inputs = get_simulation_inputs(sim) + #GET INNER VARS, PARAMETERS, AND STATES AT THIS LEVEL ... @assert sim.status == BUILD_INCOMPLETE while sim.status == BUILD_INCOMPLETE CRC.@ignore_derivatives @debug "Start state intialization routine" - TimerOutputs.@timeit BUILD_TIMER "Initialize Static Injectors" begin - sim.status = initialize_static_injection!(inputs) - end - TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Injectors" begin - sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) - end + sim.status = initialize_static_injection!(inputs) + sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) if has_dyn_lines(inputs) - TimerOutputs.@timeit BUILD_TIMER "Initialize Dynamic Branches" begin - sim.status = initialize_dynamic_branches!(sim.x0, inputs) - end + sim.status = initialize_dynamic_branches!(sim.x0, inputs) else CRC.@ignore_derivatives @debug "No Dynamic Branches in the system" end @@ -243,6 +181,7 @@ end function _initialize_state_space( sim::Simulation{T}, ::Val{FLAT_START}, + ::Union{Val{true}, Val{false}}, ) where {T <: SimulationModel} simulation_inputs = get_simulation_inputs(sim) sim.x0 = _get_flat_start(simulation_inputs) @@ -251,6 +190,7 @@ end function _initialize_state_space( sim::Simulation{T}, ::Val{INITIALIZED}, + ::Union{Val{true}, Val{false}}, ) where {T <: SimulationModel} simulation_inputs = get_simulation_inputs(sim) @assert sim.status == BUILD_INCOMPLETE diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index 7d7365150..de5449f45 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -1,4 +1,4 @@ -struct SimulationInputs +mutable struct SimulationInputs dynamic_injectors::Vector{DynamicWrapper{<:PSY.DynamicInjection}} static_injectors::Vector static_loads::Vector @@ -19,7 +19,7 @@ struct SimulationInputs total_shunts::SparseArrays.SparseMatrixCSC{Float64, Int} DAE_vector::Vector{Bool} mass_matrix::LinearAlgebra.Diagonal{Float64} - parameters::Vector{Float64} + parameters::ComponentArrays.ComponentVector{Float64} constant_lags::Vector end @@ -65,11 +65,11 @@ function SimulationInputs( total_shunts = _make_total_shunts(wrapped_branches, n_buses) TimerOutputs.@timeit BUILD_TIMER "Build initial parameters" begin parameter_count = n_parameters - initial_parameters = zeros(parameter_count) - _update_initial_parameters!(initial_parameters, wrapped_branches) - _update_initial_parameters!(initial_parameters, wrapped_injectors) - _update_initial_parameters!(initial_parameters, wrapped_loads) - _update_initial_parameters!(initial_parameters, wrapped_static_injectors) + initial_parameters = ComponentArrays.ComponentVector{Float64}() + initial_parameters = _add_parameters(initial_parameters, wrapped_branches) + initial_parameters = _add_parameters(initial_parameters, wrapped_injectors) + initial_parameters = _add_parameters(initial_parameters, wrapped_loads) + initial_parameters = _add_parameters(initial_parameters, wrapped_static_injectors) end mass_matrix = _make_mass_matrix(wrapped_injectors, n_vars, n_buses) @@ -175,26 +175,63 @@ function SimulationInputs( return SimulationInputs(sys, frequency_reference) end -function _update_initial_parameters!(initial_parameters, wrapped_devices) +function _get_wrapper_name(wrapped_device::Union{DynamicWrapper, StaticWrapper}) + Symbol(PSY.get_name(get_device(wrapped_device))) +end +function _get_wrapper_name(wrapped_device::StaticLoadWrapper) + Symbol(PSY.get_name(PSY.get_bus(wrapped_device))) +end +function _get_wrapper_name(wrapped_device::BranchWrapper) + Symbol(PSY.get_name(PSY.get_branch(wrapped_device))) +end + +#Eventually remove references from wrapper and get the values here from static/dynamic devices +#This would require having the static device included in the dynamic wrapper (in order to get reactive power...) +#For now, the wrappers get the references correctly already, so can just put those values directly into p +function _add_parameters(initial_parameters, wrapped_devices) for wrapped_device in wrapped_devices p = get_params(wrapped_device) - p_range = get_p_range(wrapped_device) - initial_parameters[p_range] .= p + name = _get_wrapper_name(wrapped_device) + if isa(wrapped_device, DynamicWrapper) + refs = ( + V_ref = get_V_ref(wrapped_device), + ω_ref = get_ω_ref(wrapped_device), + P_ref = get_P_ref(wrapped_device), + Q_ref = get_Q_ref(wrapped_device), + ) + elseif isa(wrapped_device, StaticWrapper) + refs = ( + V_ref = get_V_ref(wrapped_device), + θ_ref = get_θ_ref(wrapped_device), + P_ref = get_P_ref(wrapped_device), + Q_ref = get_Q_ref(wrapped_device), + ) + else + refs = (;) + end + initial_parameters = ComponentArrays.ComponentVector( + initial_parameters; + name => ( + params = p, + refs = refs, + ), + ) end + return initial_parameters end function _get_n_params( dynamic_device::PSY.DynamicInjection, static_device::PSY.StaticInjection, ) - return length(get_params(dynamic_device)) + return length(ComponentArrays.ComponentVector(get_params(dynamic_device))) end function _get_n_params( dynamic_device::T, static_device::PSY.StaticInjection, ) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} - return length(get_params(dynamic_device)) + return length(ComponentArrays.ComponentVector(get_params(dynamic_device))) end function _wrap_dynamic_injector_data( @@ -227,6 +264,7 @@ function _wrap_dynamic_injector_data( @debug "ix_range=$ix_range ode_range=$ode_range inner_vars_range= $inner_vars_range p_range=$p_range" dynamic_device = PSY.get_dynamic_injector(device) @assert dynamic_device !== nothing + #TODO - add check if name of device is unique? wrapped_injector[ix] = DynamicWrapper( device, dynamic_device, diff --git a/src/base/small_signal.jl b/src/base/small_signal.jl index e8d322e82..3412db1f2 100644 --- a/src/base/small_signal.jl +++ b/src/base/small_signal.jl @@ -151,7 +151,7 @@ function _small_signal_analysis( ::Type{T}, inputs::SimulationInputs, x_eval::Vector{Float64}, - p::Vector{Float64}, + p::AbstractArray{Float64}, multimachine = true, ) where {T <: SimulationModel} jacwrapper = get_jacobian(T, inputs, x_eval, p, 0) diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index 31bd43661..da40e472d 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -284,7 +284,7 @@ end function initialize_avr!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.SEXS, TG, P}}, inner_vars::AbstractVector, @@ -296,15 +296,17 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SEXS) - internal_params = @view device_parameters[local_ix_params] - Ta_Tb, _, K, _, V_min, V_max = internal_params + params = p[:params][:AVR] + V_min = params[:V_lim][:min] + V_max = params[:V_lim][:max] #States of AVRTypeI are Vf, Vr1, Vr2, Vm #To solve V_ref, Vr - function f!(out, x) + function f!(out, x, params) V_ref = x[1] Vr = x[2] + Ta_Tb = params[:Ta_Tb] + K = params[:K] V_in = V_ref - Vm V_LL = Vr + Ta_Tb * V_in @@ -313,13 +315,19 @@ function initialize_avr!( out[2] = V_in * (1 - Ta_Tb) - Vr end x0 = [1.0, Vf0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) CRC.@ignore_derivatives @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u if (sol_x0[2] >= V_max + BOUNDS_TOLERANCE) || (sol_x0[2] <= V_min - BOUNDS_TOLERANCE) CRC.@ignore_derivatives @error( @@ -328,7 +336,7 @@ function initialize_avr!( end #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - set_V_ref(dynamic_device, sol_x0[1]) + set_V_ref!(p, sol_x0[1]) #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.SEXS) diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index 3ed0b5c78..8b5b32068 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -4,7 +4,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{PSY.BaseMachine, S, A, TG, P}}, inner_vars::AbstractVector, @@ -22,20 +22,22 @@ function initialize_mach_shaft!( #Machine Data machine = PSY.get_machine(dynamic_device) - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.BaseMachine) - internal_params = @view device_parameters[local_ix_params] - R, Xd_p, _ = internal_params + params = p[:params][:Machine] + R = params[:R] + Xd_p = params[:Xd_p] δ0 = angle(V + (R + Xd_p * 1im) * I) ω0 = 1.0 τm0 = real(V * conj(I)) @assert isapprox(τm0, P0; atol = STRICT_NLSOLVE_F_TOLERANCE) τm0, P0 #To solve: δ, τm, Vf0 - function f!(out, x) + function f!(out, x, params) δ = x[1] τm = x[2] Vf0 = x[3] + R = params[:R] + Xd_p = params[:Xd_p] V_dq = ri_dq(δ) * [V_R; V_I] i_d = (1.0 / (R^2 + Xd_p^2)) * (Xd_p * (Vf0 - V_dq[2]) - R * V_dq[1]) #15.36 i_q = (1.0 / (R^2 + Xd_p^2)) * (Xd_p * V_dq[1] + R * (Vf0 - V_dq[2])) #15.36 @@ -45,13 +47,19 @@ function initialize_mach_shaft!( out[3] = Q0 - (V_dq[2] * i_d - V_dq[1] * i_q) #Output Reactive Power end x0 = [δ0, τm0, 1.0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) CRC.@ignore_derivatives @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages inner_vars[VR_gen_var] = V_R inner_vars[VI_gen_var] = V_I @@ -65,7 +73,7 @@ function initialize_mach_shaft!( inner_vars[τm_var] = sol_x0[2] #Not necessary to update Vf for AVR in Base Machine. Update eq_p: PSY.set_eq_p!(machine, sol_x0[3]) - internal_params[3] = sol_x0[3] + params[:eq_p] = sol_x0[3] #eq_p should not be a parameter. inner_vars[Vf_var] = sol_x0[3] end return @@ -675,7 +683,7 @@ end function initialize_mach_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, P}}, inner_vars::AbstractVector, @@ -700,24 +708,19 @@ function initialize_mach_shaft!( #Get parameters machine = PSY.get_machine(dynamic_device) - local_ix_params = get_local_parameter_ix(dynamic_device, typeof(machine)) - internal_params = @view device_parameters[local_ix_params] - R, - Td0_p, - Td0_pp, - Tq0_p, - Tq0_pp, - Xd, - Xq, - Xd_p, - Xq_p, - Xd_pp, - Xl, - γ_d1, - γ_q1, - γ_d2, - γ_q2, - γ_qd = internal_params + params = p[:params][:Machine] + #parameters needed for initial guess: + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_q1 = params[:γ_q1] + γ_q2 = params[:γ_q2] + γ_qd = params[:γ_qd] + Xq_pp = Xd_pp # Initialization doesn't consider saturation #Sat_A, Sat_B = PSY.get_saturation_coeffs(machine) @@ -758,7 +761,7 @@ function initialize_mach_shaft!( (Xq - Xq_p) * (γ_q2 * ed_p0 - γ_q2 * ψ_kq0 - γ_q1 * I_q0) + Se0 * ψq_pp0 * γ_qd - function f!(out, x) + function f!(out, x, params) δ = x[1] τm = x[2] Vf = x[3] @@ -768,6 +771,23 @@ function initialize_mach_shaft!( ψ_kq = x[7] Xad_Ifd_aux = x[8] + R = params[:R] + Td0_p = params[:Td0_p] + Td0_pp = params[:Td0_pp] + Tq0_p = params[:Tq0_p] + Tq0_pp = params[:Tq0_pp] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] + γ_q2 = params[:γ_q2] + γ_qd = params[:γ_qd] + V_dq = ri_dq(δ) * [V_R; V_I] ψq_pp = γ_q1 * ed_p + ψ_kq * (1 - γ_q1) ψd_pp = γ_d1 * eq_p + γ_d2 * (Xd_p - Xl) * ψ_kd @@ -796,13 +816,20 @@ function initialize_mach_shaft!( out[8] = Xad_Ifd_aux - Xad_Ifd end x0 = [δ0, τm0, Vf0, eq_p0, ed_p0, ψ_kd0, ψ_kq0, Xad_Ifd0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + + prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) CRC.@ignore_derivatives @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages inner_vars[VR_gen_var] = V_R inner_vars[VI_gen_var] = V_I diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index eed605a8a..f07f8ab9f 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -1,20 +1,18 @@ function initialize_tg!( device_states, - device_parameters, + p, ::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGFixed, P}}, inner_vars::AbstractVector, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} tg = PSY.get_prime_mover(dynamic_device) - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.TGFixed) - internal_params = @view device_parameters[local_ix_params] - eff = internal_params[1] + eff = p[:params][:TurbineGov][:efficiency] τm0 = inner_vars[τm_var] P_ref = τm0 / eff #Update Control Refs PSY.set_P_ref!(tg, P_ref) - set_P_ref(dynamic_device, P_ref) + set_P_ref!(p, P_ref) return end @@ -206,7 +204,7 @@ end function initialize_tg!( device_states, - device_parameters, + p, ::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.SteamTurbineGov1, P}}, inner_vars::AbstractVector, @@ -218,22 +216,26 @@ function initialize_tg!( tg = PSY.get_prime_mover(dynamic_device) #Get Parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SteamTurbineGov1) - internal_params = @view device_parameters[local_ix_params] - R, - T1, - V_min, - V_max, - T2, - T3, - D_T = internal_params + params = p[:params][:TurbineGov] + R = params[:R] + V_min = params[:valve_position_limits][:min] + V_max = params[:valve_position_limits][:max] inv_R = R < eps() ? 0.0 : (1.0 / R) - function f!(out, x) + function f!(out, x, params) P_ref = x[1] x_g1 = x[2] x_g2 = x[3] + R = params[:R] + T1 = params[:T1] + V_min = params[:valve_position_limits][:min] + V_max = params[:valve_position_limits][:max] + T2 = params[:T2] + T3 = params[:T3] + D_T = params[:D_T] + inv_R = R < eps() ? 0.0 : (1.0 / R) + ref_in = inv_R * (P_ref - Δω) Pm = x_g2 + (T2 / T3) * x_g1 @@ -243,11 +245,17 @@ function initialize_tg!( out[3] = (Pm - D_T * Δω) - τm0 end x0 = [1.0 / inv_R, τm0, τm0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) CRC.@ignore_derivatives @warn("Initialization in TG failed") else - sol_x0 = sol.zero + sol_x0 = sol.u if (sol_x0[2] >= V_max + BOUNDS_TOLERANCE) || (sol_x0[2] <= V_min - BOUNDS_TOLERANCE) CRC.@ignore_derivatives @error( @@ -256,7 +264,7 @@ function initialize_tg!( end #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - set_P_ref(dynamic_device, sol_x0[1]) + set_P_ref!(p, sol_x0[1]) #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index b1c7d5621..02bb8b33b 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -57,7 +57,7 @@ end function initialize_static_device!( device::StaticWrapper{PSY.Source, T}, - local_parameters::AbstractArray{U}, + p::AbstractArray{U}, ) where {T <: BusCategory, U <: ACCEPTED_REAL_TYPES} #PowerFlow Data P0 = PSY.get_active_power(device) @@ -71,12 +71,13 @@ function initialize_static_device!( I = conj(S0 / V) I_R = real(I) I_I = imag(I) - R_th, X_th = local_parameters - Zmag = R_th^2 + X_th^2 - - function f!(out, x) + params = p[:params] + function f!(out, x, params) V_R_internal = x[1] V_I_internal = x[2] + R_th = params[:R_th] + X_th = params[:X_th] + Zmag = R_th^2 + X_th^2 out[1] = R_th * (V_R_internal - V_R) / Zmag + X_th * (V_I_internal - V_I) / Zmag - I_R @@ -84,18 +85,25 @@ function initialize_static_device!( R_th * (V_I_internal - V_I) / Zmag - X_th * (V_R_internal - V_R) / Zmag - I_I end x0 = [V_R, V_I] - sol = NLsolve.nlsolve(f!, x0) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + + if !SciMLBase.successful_retcode(sol) CRC.@ignore_derivatives @warn("Initialization in Source failed") else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages V_internal = sqrt(sol_x0[1]^2 + sol_x0[2]^2) θ_internal = atan(sol_x0[2], sol_x0[1]) PSY.set_internal_voltage!(device.device, V_internal) PSY.set_internal_angle!(device.device, θ_internal) - set_V_ref(device, PSY.get_internal_voltage(device.device)) - set_θ_ref(device, PSY.get_internal_angle(device.device)) + set_V_ref!(p, PSY.get_internal_voltage(device.device)) + set_θ_ref!(p, PSY.get_internal_angle(device.device)) end return end diff --git a/src/initialization/inverter_components/init_filter.jl b/src/initialization/inverter_components/init_filter.jl index 1b09074ac..b33eb149c 100644 --- a/src/initialization/inverter_components/init_filter.jl +++ b/src/initialization/inverter_components/init_filter.jl @@ -1,6 +1,6 @@ function initialize_filter!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicInverter{C, O, IC, DC, P, PSY.LCLFilter, L}}, inner_vars::AbstractVector, @@ -26,10 +26,12 @@ function initialize_filter!( Ii_filter = imag(I) #Get Parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.LCLFilter) - internal_params = @view device_parameters[local_ix_params] - lf, rf, cf, lg, rg = internal_params - + params = p[:params][:Filter] + lf = params[:lf] + rf = params[:rf] + cf = params[:cf] + lg = params[:lg] + rg = params[:rg] #Set parameters ω_sys = get_ω_ref(dynamic_device) @@ -92,7 +94,7 @@ end function initialize_filter!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -130,10 +132,9 @@ function initialize_filter!( I_I = imag(I) #Get Parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.RLFilter) - internal_params = @view device_parameters[local_ix_params] - rf, lf = internal_params - + params = p[:params][:Filter] + rf = params[:rf] + lf = params[:lf] converter = PSY.get_converter(dynamic_device) R_source = PSY.get_R_source(converter) X_source = PSY.get_X_source(converter) diff --git a/src/initialization/inverter_components/init_outer.jl b/src/initialization/inverter_components/init_outer.jl index 90177f910..56ff29cc7 100644 --- a/src/initialization/inverter_components/init_outer.jl +++ b/src/initialization/inverter_components/init_outer.jl @@ -367,60 +367,15 @@ function initialize_outer!( ) internal_states = @view device_states[local_ix] - #Get all parameters once - local_ix_params = get_local_parameter_ix( - dynamic_device, - PSY.OuterControl{ - PSY.ActiveRenewableControllerAB, - PSY.ReactiveRenewableControllerAB, - }, - ) - internal_params = @view device_parameters[local_ix_params] - active_n_params = length(get_params(active_power_control)) - active_ix_range_params = 1:active_n_params - active_params = @view internal_params[active_ix_range_params] - reactive_n_params = length(get_params(reactive_power_control)) - reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) - reactive_params = @view internal_params[reactive_ix_range_params] - K_pg, - K_ig, - T_p, - fdbd1, - fdbd2, - fe_min, - fe_max, - P_min, - P_max, - T_g, - D_dn, - D_up, - dP_min, - dP_max, - P_min_inner, - P_max_inner, - T_pord = active_params - T_fltr, - K_p, - K_i, - T_ft, - T_fv, - V_frz, # V_frz not implemented yet - R_c, - X_c, - K_c, - e_min, - e_max, - dbd1, - dbd2, - Q_min, - Q_max, - T_p, - Q_min_inner, - Q_max_inner, - V_min, - V_max, - K_qp, - K_qi = reactive_params + #Get parameters + K_ig = device_parameters[:OuterControl][:ActivePowerControl][:K_ig] + T_p = device_parameters[:OuterControl][:ActivePowerControl][:T_p] + K_i = device_parameters[:OuterControl][:ReactivePowerControl][:K_i] + R_c = device_parameters[:OuterControl][:ReactivePowerControl][:R_c] + X_c = device_parameters[:OuterControl][:ReactivePowerControl][:X_c] + K_c = device_parameters[:OuterControl][:ReactivePowerControl][:K_c] + T_p = device_parameters[:OuterControl][:ReactivePowerControl][:T_p] + K_qi = device_parameters[:OuterControl][:ReactivePowerControl][:K_qi] if Freq_Flag == 1 #Update States diff --git a/src/models/device.jl b/src/models/device.jl index 320de43a5..c7167dfcd 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -374,7 +374,7 @@ end function _update_inner_vars!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, P}}, @@ -405,24 +405,15 @@ function _update_inner_vars!( V_tI = inner_vars[VI_gen_var] #Get parameters - machine_ix_params = get_local_parameter_ix(dynamic_device, typeof(machine)) - machine_params = @view device_parameters[machine_ix_params] - R, - Td0_p, - Td0_pp, - Tq0_p, - Tq0_pp, - Xd, - Xq, - Xd_p, - Xq_p, - Xd_pp, - Xl, - γ_d1, - γ_q1, - γ_d2, - γ_q2, - γ_qd = machine_params #RoundRotorQuadratic and RoundRotorExponential have same params; otherwise would need separate methods + params = p[:params][:Machine] + R = params[:R] + Xd = params[:Xd] + Xd_p = params[:Xd_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] Xq_pp = Xd_pp #RI to dq transformation V_dq = ri_dq(δ) * [V_tR; V_tI] diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index d75eeefd0..c2b149baa 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -318,15 +318,14 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.SEXS, TG, P}}, h, t, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) - + V0_ref = p[:refs][:V_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.SEXS) @@ -340,9 +339,13 @@ function mdl_avr_ode!( Vs = inner_vars[V_pss_var] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SEXS) - internal_params = @view device_parameters[local_ix_params] - Ta_Tb, Tb, K, Te, V_min, V_max = internal_params + params = @view(p[:params][:AVR]) + Ta_Tb = params[:Ta_Tb] + Tb = params[:Tb] + K = params[:K] + Te = params[:Te] + V_min = params[:V_lim][:min] + V_max = params[:V_lim][:max] Ta = Tb * Ta_Tb #Compute auxiliary parameters diff --git a/src/models/generator_models/machine_models.jl b/src/models/generator_models/machine_models.jl index 4532a8fba..57a56f4b7 100644 --- a/src/models/generator_models/machine_models.jl +++ b/src/models/generator_models/machine_models.jl @@ -13,7 +13,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -30,10 +30,11 @@ function mdl_machine_ode!( V_tR = inner_vars[VR_gen_var] V_tI = inner_vars[VI_gen_var] - #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.BaseMachine) - internal_params = @view device_parameters[local_ix_params] - R, Xd_p, eq_p = internal_params + params = p[:params][:Machine] + R = params[:R] + Xd_p = params[:Xd_p] + eq_p = PSY.get_eq_p(PSY.get_machine(get_device(dynamic_device))) + basepower = PSY.get_base_power(dynamic_device) #RI to dq transformation @@ -554,7 +555,7 @@ end function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -592,24 +593,23 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #E_fd: Field voltage #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, typeof(machine)) - internal_params = @view device_parameters[local_ix_params] - R, - Td0_p, - Td0_pp, - Tq0_p, - Tq0_pp, - Xd, - Xq, - Xd_p, - Xq_p, - Xd_pp, - Xl, - γ_d1, - γ_q1, - γ_d2, - γ_q2, - γ_qd = internal_params + params = @view(p[:params][:Machine]) + R = params[:R] + Td0_p = params[:Td0_p] + Td0_pp = params[:Td0_pp] + Tq0_p = params[:Tq0_p] + Tq0_pp = params[:Tq0_pp] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] + γ_q2 = params[:γ_q2] + γ_qd = params[:γ_qd] Xq_pp = Xd_pp basepower = PSY.get_base_power(dynamic_device) diff --git a/src/models/generator_models/pss_models.jl b/src/models/generator_models/pss_models.jl index 018facbc8..f9af17568 100644 --- a/src/models/generator_models/pss_models.jl +++ b/src/models/generator_models/pss_models.jl @@ -115,20 +115,16 @@ end function mdl_pss_ode!( ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSSFixed}}, h, t, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, TG <: PSY.TurbineGov} - #Update V_pss on inner vars - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.PSSFixed) - internal_params = @view device_parameters[local_ix_params] - V_pss = internal_params[1] + V_pss = p[:params][:PSS][:V_pss] inner_vars[V_pss_var] = V_pss - return end diff --git a/src/models/generator_models/shaft_models.jl b/src/models/generator_models/shaft_models.jl index 8e5ad581e..5a17cd5e2 100644 --- a/src/models/generator_models/shaft_models.jl +++ b/src/models/generator_models/shaft_models.jl @@ -9,7 +9,7 @@ end function mdl_shaft_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, PSY.SingleMass, A, TG, P}}, @@ -29,9 +29,8 @@ function mdl_shaft_ode!( τm = inner_vars[τm_var] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SingleMass) - internal_params = @view device_parameters[local_ix_params] - H, D = internal_params + H = p[:params][:Shaft][:H] + D = p[:params][:Shaft][:D] #Compute 2 states ODEs output_ode[local_ix[1]] = 2 * π * f0 * (ω - ω_sys) #15.5 diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index 41cee7d33..00f67b420 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -30,19 +30,15 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGFixed, P}}, h, t, ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} - - #Update inner vars - local_ix_params = get_local_parameter_ix(device, PSY.TGFixed) - internal_params = @view device_parameters[local_ix_params] - efficiency = internal_params[1] - P_ref = get_P_ref(device) + efficiency = p[:params][:TurbineGov][:efficiency] + P_ref = p[:refs][:P_ref] inner_vars[τm_var] = P_ref * efficiency return end @@ -148,7 +144,7 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.SteamTurbineGov1, P}}, @@ -159,7 +155,7 @@ function mdl_tg_ode!( #Obtain TG tg = PSY.get_prime_mover(device) #Obtain references - P_ref = get_P_ref(device) + P_ref = p[:refs][:P_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, typeof(tg)) @@ -174,15 +170,14 @@ function mdl_tg_ode!( ω = @view device_states[external_ix] #Get Parameters - local_ix_params = get_local_parameter_ix(device, PSY.SteamTurbineGov1) - internal_params = @view device_parameters[local_ix_params] - R, - T1, - V_min, - V_max, - T2, - T3, - D_T = internal_params + params = @view(p[:params][:TurbineGov]) + R = params[:R] + T1 = params[:T1] + V_min = params[:valve_position_limits][:min] + V_max = params[:valve_position_limits][:max] + T2 = params[:T2] + T3 = params[:T3] + D_T = params[:D_T] inv_R = R < eps() ? 0.0 : (1.0 / R) #Compute auxiliary parameters diff --git a/src/models/inverter_models/filter_models.jl b/src/models/inverter_models/filter_models.jl index 0d4aa940f..395a3e8ae 100644 --- a/src/models/inverter_models/filter_models.jl +++ b/src/models/inverter_models/filter_models.jl @@ -64,10 +64,11 @@ function mdl_filter_ode!( #Get parameters f0 = get_system_base_frequency(dynamic_device) ωb = 2 * pi * f0 - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.LCLFilter) - internal_params = @view device_parameters[local_ix_params] - lf, rf, cf, lg, rg = internal_params - + lf = device_parameters[:Filter][:lf] + rf = device_parameters[:Filter][:rf] + cf = device_parameters[:Filter][:cf] + lg = device_parameters[:Filter][:lg] + rg = device_parameters[:Filter][:rg] basepower = PSY.get_base_power(dynamic_device) sys_Sbase = get_system_base_power(dynamic_device) @@ -140,9 +141,8 @@ function mdl_filter_ode!( ratio_power = basepower / sys_Sbase #Obtain parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.RLFilter) - internal_params = @view device_parameters[local_ix_params] - rf, lf = internal_params + rf = device_parameters[:Filter][:rf] + lf = device_parameters[:Filter][:lf] Vr_cnv = inner_vars[Vr_cnv_var] Vi_cnv = inner_vars[Vi_cnv_var] diff --git a/src/models/inverter_models/outer_control_models.jl b/src/models/inverter_models/outer_control_models.jl index bc18a6c06..05b9789a8 100644 --- a/src/models/inverter_models/outer_control_models.jl +++ b/src/models/inverter_models/outer_control_models.jl @@ -53,34 +53,24 @@ function _mdl_ode_RE_active_controller_AB!( ω_plant = ω_sys #Obtain additional Active Power Controller parameters - local_ix_params = get_local_parameter_ix( - dynamic_device, - PSY.OuterControl{ - PSY.ActiveRenewableControllerAB, - PSY.ReactiveRenewableControllerAB, - }, - ) - internal_params = @view device_parameters[local_ix_params] - active_n_params = length(get_params(active_power_control)) - active_ix_range_params = 1:active_n_params - active_params = @view internal_params[active_ix_range_params] - K_pg, - K_ig, - T_p, - fdbd1, - fdbd2, - fe_min, - fe_max, - P_min, - P_max, - T_g, - D_dn, - D_up, - dP_min, - dP_max, - P_min_inner, - P_max_inner, - T_pord = active_params + K_pg = device_parameters[:OuterControl][:ActivePowerControl][:K_pg] + K_ig = device_parameters[:OuterControl][:ActivePowerControl][:K_ig] + T_p = device_parameters[:OuterControl][:ActivePowerControl][:T_p] + fe_min = device_parameters[:OuterControl][:ActivePowerControl][:fe_lim][:min] + fe_max = device_parameters[:OuterControl][:ActivePowerControl][:fe_lim][:max] + P_min = device_parameters[:OuterControl][:ActivePowerControl][:P_lim][:min] + P_max = device_parameters[:OuterControl][:ActivePowerControl][:P_lim][:max] + T_g = device_parameters[:OuterControl][:ActivePowerControl][:T_g] + D_dn = device_parameters[:OuterControl][:ActivePowerControl][:D_dn] + D_up = device_parameters[:OuterControl][:ActivePowerControl][:D_up] + dP_min = device_parameters[:OuterControl][:ActivePowerControl][:dP_lim][:min] + dP_max = device_parameters[:OuterControl][:ActivePowerControl][:dP_lim][:max] + P_min_inner = device_parameters[:OuterControl][:ActivePowerControl][:P_lim_inner][:min] + P_max_inner = device_parameters[:OuterControl][:ActivePowerControl][:P_lim_inner][:max] + T_pord = device_parameters[:OuterControl][:ActivePowerControl][:T_pord] + + # Not considered parameters because not named tuple + fdbd1, fdbd2 = PSY.get_fdbd_pnts(active_power_control) #Define internal states for outer control p_flt = active_controller_states[1] @@ -158,34 +148,7 @@ function _mdl_ode_RE_active_controller_AB!( #Obtain external parameters p_ref = get_P_ref(dynamic_device) #Obtain additional Active Power Controller parameters - local_ix_params = get_local_parameter_ix( - dynamic_device, - PSY.OuterControl{ - PSY.ActiveRenewableControllerAB, - PSY.ReactiveRenewableControllerAB, - }, - ) - internal_params = @view device_parameters[local_ix_params] - active_n_params = length(get_params(active_power_control)) - active_ix_range_params = 1:active_n_params - active_params = @view internal_params[active_ix_range_params] - K_pg, - K_ig, - T_p, - fdbd1, - fdbd2, - fe_min, - fe_max, - P_min, - P_max, - T_g, - D_dn, - D_up, - dP_min, - dP_max, - P_min_inner, - P_max_inner, - T_pord = active_params + T_pord = device_parameters[:OuterControl][:ActivePowerControl][:T_pord] #Define internal states for outer control p_ord = active_controller_states[1] @@ -711,12 +674,11 @@ function mdl_outer_ode!( #Obtain inner variables for component ω_pll = inner_vars[ω_freq_estimator_var] - local_ix_params = get_local_parameter_ix( - dynamic_device, - PSY.OuterControl{PSY.VirtualInertia, PSY.ReactivePowerDroop}, - ) - internal_params = @view device_parameters[local_ix_params] - Ta, kd, kω, kq, ωf = internal_params + Ta = device_parameters[:OuterControl][:ActivePowerControl][:Ta] + kd = device_parameters[:OuterControl][:ActivePowerControl][:kd] + kω = device_parameters[:OuterControl][:ActivePowerControl][:kω] + kq = device_parameters[:OuterControl][:ReactivePowerControl][:kq] + ωf = device_parameters[:OuterControl][:ReactivePowerControl][:ωf] q_ref = get_Q_ref(dynamic_device) V_ref = get_V_ref(dynamic_device) diff --git a/src/models/source_models.jl b/src/models/source_models.jl index 288ff5c32..17d3d8760 100644 --- a/src/models/source_models.jl +++ b/src/models/source_models.jl @@ -1,5 +1,5 @@ function mdl_source!( - device_parameters, + p, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -7,9 +7,14 @@ function mdl_source!( static_device::StaticWrapper{PSY.Source}, ) where {T <: ACCEPTED_REAL_TYPES} #Load device parameters - R_th, X_th = device_parameters - V_R = get_V_ref(static_device) * cos(get_θ_ref(static_device)) - V_I = get_V_ref(static_device) * sin(get_θ_ref(static_device)) + R_th = p[:params][:R_th] + X_th = p[:params][:X_th] + #Load device references + V_ref = p[:refs][:V_ref] + θ_ref = p[:refs][:θ_ref] + #@error V_ref + V_R = V_ref * cos(θ_ref) + V_I = V_ref * sin(θ_ref) Zmag = R_th^2 + X_th^2 #update current diff --git a/src/models/system.jl b/src/models/system.jl index 01609aba7..3248fa741 100644 --- a/src/models/system.jl +++ b/src/models/system.jl @@ -89,8 +89,8 @@ function system_residual!( device_inner_vars = @view inner_vars[get_inner_vars_index(dynamic_device)] device_states = @view x[ix_range] bus_ix = get_bus_ix(dynamic_device) - p_ix = get_p_range(dynamic_device) - device_parameters = view(p, p_ix) + device_name = _get_wrapper_name(dynamic_device) + device_parameters = p[device_name] device!( device_states, device_ode_output, @@ -128,8 +128,8 @@ function system_residual!( for static_device in get_static_injectors(inputs) bus_ix = get_bus_ix(static_device) - p_ix = get_p_range(static_device) - device_parameters = view(p, p_ix) + device_name = _get_wrapper_name(static_device) + device_parameters = p[device_name] device!( device_parameters, voltage_r[bus_ix], @@ -279,8 +279,8 @@ function system_mass_matrix!( device_inner_vars = @view inner_vars[get_inner_vars_index(dynamic_device)] device_states = @view x[ix_range] bus_ix = get_bus_ix(dynamic_device) - p_ix = get_p_range(dynamic_device) - device_parameters = view(p, p_ix) + device_name = _get_wrapper_name(dynamic_device) + device_parameters = p[device_name] #TODO should be a view... device!( device_states, device_ode_output, @@ -317,8 +317,8 @@ function system_mass_matrix!( for static_device in get_static_injectors(inputs) bus_ix = get_bus_ix(static_device) - p_ix = get_p_range(static_device) - device_parameters = view(p, p_ix) + device_name = _get_wrapper_name(static_device) + device_parameters = p[device_name] device!( device_parameters, voltage_r[bus_ix], diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index ec1beedf7..96abd6642 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -1,26 +1,19 @@ struct ParamsMetadata - symbol::Symbol in_mass_matrix::Bool in_network::Bool impacts_ic::Bool - impacts_pf::Bool end -get_params_symbol(x) = [metadata.symbol for metadata in get_params_metadata(x)] -# TODO - temporary for dynamic components that have not yet been modified to use parameters. -function get_params(x::PSY.Device) - @warn "Parameters not yet defined for device: $(typeof(x))" - Float64[] +function get_params(x) + @error "Parameters not yet defined for component: $(typeof(x))" + (;) end -function get_params(x::T) where {T <: PSY.DynamicComponent} - @warn "Parameters not yet defined for dynamic component: $(typeof(x))" - Float64[] -end -get_params_metadata(::T) where {T <: PSY.DynamicComponent} = ParamsMetadata[] -get_params(::PSY.ActivePowerControl) = Float64[] -get_params_metadata(::PSY.ActivePowerControl) = ParamsMetadata[] -get_params(::PSY.ReactivePowerControl) = Float64[] -get_params_metadata(::PSY.ReactivePowerControl) = ParamsMetadata[] + +get_params_metadata(::T) where {T <: PSY.DynamicComponent} = (;) +get_params(::PSY.ActivePowerControl) = (;) +get_params_metadata(::PSY.ActivePowerControl) = (;) +get_params(::PSY.ReactivePowerControl) = (;) +get_params_metadata(::PSY.ReactivePowerControl) = (;) get_params( d::DynamicWrapper{T}, @@ -42,159 +35,175 @@ get_params_metadata(x::BranchWrapper) = get_params_metadata(get_branch(x)) get_params(x::PSY.DynamicBranch) = get_params(PSY.get_branch(x)) get_params_metadata(x::PSY.DynamicBranch) = get_params_metadata(PSY.get_branch(x)) -get_params(x::PSY.Line) = [PSY.get_r(x), PSY.get_x(x)] -get_params_metadata(::PSY.Line) = [ - ParamsMetadata(:r, false, true, true, true), - ParamsMetadata(:x, false, true, true, true), -] -get_params(::StaticLoadWrapper) = Float64[] -get_params_metadata(::StaticLoadWrapper) = ParamsMetadata[] +get_params(x::PSY.Line) = (r = PSY.get_r(x), x = PSY.get_x(x)) +get_params_metadata(::PSY.Line) = ( + r = ParamsMetadata(false, true, true), + x = ParamsMetadata(false, true, true), +) +get_params(::StaticLoadWrapper) = (;) +get_params_metadata(::StaticLoadWrapper) = (;) ########### INVERTERS ############# function get_params(g::PSY.DynamicInverter) - vcat( - get_params(PSY.get_converter(g)), - get_params(PSY.get_outer_control(g)), - get_params(PSY.get_inner_control(g)), - get_params(PSY.get_dc_source(g)), - get_params(PSY.get_freq_estimator(g)), - get_params(PSY.get_filter(g)), + ( + Converter = get_params(PSY.get_converter(g)), + DCSource = get_params(PSY.get_dc_source(g)), + Filter = get_params(PSY.get_filter(g)), + FrequencyEstimator = get_params(PSY.get_freq_estimator(g)), + InnerControl = get_params(PSY.get_inner_control(g)), + OuterControl = get_params(PSY.get_outer_control(g)), ) end function get_params_metadata(g::PSY.DynamicInverter) - vcat( - get_params_metadata(PSY.get_converter(g)), - get_params_metadata(PSY.get_outer_control(g)), - get_params_metadata(PSY.get_inner_control(g)), - get_params_metadata(PSY.get_dc_source(g)), - get_params_metadata(PSY.get_freq_estimator(g)), - get_params_metadata(PSY.get_filter(g)), + ( + Converter = get_params_metadata(PSY.get_converter(g)), + DCSource = get_params_metadata(PSY.get_dc_source(g)), + Filter = get_params_metadata(PSY.get_filter(g)), + FrequencyEstimator = get_params_metadata(PSY.get_freq_estimator(g)), + InnerControl = get_params_metadata(PSY.get_inner_control(g)), + OuterControl = get_params_metadata(PSY.get_outer_control(g)), ) end #FILTERS get_params(x::PSY.LCLFilter) = - [PSY.get_lf(x), PSY.get_rf(x), PSY.get_cf(x), PSY.get_lg(x), PSY.get_rg(x)] -get_params_metadata(::PSY.LCLFilter) = [ - ParamsMetadata(:lf_Filter, true, false, true, false), - ParamsMetadata(:rf_Filter, false, false, true, false), - ParamsMetadata(:cf_Filter, true, false, true, false), - ParamsMetadata(:lg_Filter, true, false, true, false), - ParamsMetadata(:rg_Filter, false, false, true, false), -] -get_params(x::PSY.RLFilter) = [PSY.get_rf(x), PSY.get_lf(x)] -get_params_metadata(::PSY.RLFilter) = [ - ParamsMetadata(:rf_Filter, false, false, true, false), - ParamsMetadata(:lf_Filter, false, false, true, false), -] + ( + lf = PSY.get_lf(x), + rf = PSY.get_rf(x), + cf = PSY.get_cf(x), + lg = PSY.get_lg(x), + rg = PSY.get_rg(x), + ) +get_params_metadata(::PSY.LCLFilter) = ( + lf = ParamsMetadata(true, false, true), + rf = ParamsMetadata(false, false, true), + cf = ParamsMetadata(true, false, true), + lg = ParamsMetadata(true, false, true), + rg = ParamsMetadata(false, false, true), +) +get_params(x::PSY.RLFilter) = (rf = PSY.get_rf(x), lf = PSY.get_lf(x)) +get_params_metadata(::PSY.RLFilter) = ( + rf = ParamsMetadata(false, false, true), + lf = ParamsMetadata(false, false, true), +) -#OUTER CONTROL -get_params(x::PSY.OuterControl) = vcat( - get_params(PSY.get_active_power_control(x)), - get_params(PSY.get_reactive_power_control(x)), +#OUTER CONTROL, +get_params(x::PSY.OuterControl) = ( + ActivePowerControl = get_params(PSY.get_active_power_control(x)), + ReactivePowerControl = get_params(PSY.get_reactive_power_control(x)), ) -get_params_metadata(x::PSY.OuterControl) = vcat( - get_params_metadata(PSY.get_active_power_control(x)), - get_params_metadata(PSY.get_reactive_power_control(x)), +get_params_metadata(x::PSY.OuterControl) = ( + ActivePowerControl = get_params_metadata(PSY.get_active_power_control(x)), + ReactivePowerControl = get_params_metadata(PSY.get_reactive_power_control(x)), ) #ACTIVE POWER CONTROL -get_params(x::PSY.VirtualInertia) = [PSY.get_Ta(x), PSY.get_kd(x), PSY.get_kω(x)] -get_params_metadata(::PSY.VirtualInertia) = [ - ParamsMetadata(:Ta_ActivePowerControl, false, false, false, false), - ParamsMetadata(:kd_ActivePowerControl, false, false, false, false), - ParamsMetadata(:kω_ActivePowerControl, false, false, false, false), -] -get_params(x::PSY.ActiveRenewableControllerAB) = [ - PSY.get_K_pg(x), - PSY.get_K_ig(x), - PSY.get_T_p(x), - PSY.get_fdbd_pnts(x)[1], - PSY.get_fdbd_pnts(x)[2], - PSY.get_fe_lim(x)[1], - PSY.get_fe_lim(x)[2], - PSY.get_P_lim(x)[1], - PSY.get_P_lim(x)[2], - PSY.get_T_g(x), - PSY.get_D_dn(x), - PSY.get_D_up(x), - PSY.get_dP_lim(x)[1], - PSY.get_dP_lim(x)[2], - PSY.get_P_lim_inner(x)[1], - PSY.get_P_lim_inner(x)[2], - PSY.get_T_pord(x)] -get_params_metadata(::PSY.ActiveRenewableControllerAB) = [ - ParamsMetadata(:K_pg_ActivePowerControl, false, false, false, false), - ParamsMetadata(:K_ig_ActivePowerControl, false, false, true, false), - ParamsMetadata(:T_p_ActivePowerControl, false, false, true, false), - ParamsMetadata(:fdbd1_ActivePowerControl, false, false, false, false), - ParamsMetadata(:fdbd2_ActivePowerControl, false, false, false, false), - ParamsMetadata(:fe_min_ActivePowerControl, false, false, false, false), - ParamsMetadata(:fe_max_ActivePowerControl, false, false, false, false), - ParamsMetadata(:P_min_ActivePowerControl, false, false, false, false), - ParamsMetadata(:P_max_ActivePowerControl, false, false, false, false), - ParamsMetadata(:T_g_ap_ActivePowerControl, false, false, false, false), - ParamsMetadata(:D_dn_ActivePowerControl, false, false, false, false), - ParamsMetadata(:D_up_ActivePowerControl, false, false, false, false), - ParamsMetadata(:dP_min_ActivePowerControl, false, false, false, false), - ParamsMetadata(:dP_max_ActivePowerControl, false, false, false, false), - ParamsMetadata(:P_min_inner_ActivePowerControl, false, false, false, false), - ParamsMetadata(:P_max_inner_ActivePowerControl, false, false, false, false), - ParamsMetadata(:T_pord_ActivePowerControl, false, false, false, false), -] - +get_params(x::PSY.VirtualInertia) = + (Ta = PSY.get_Ta(x), kd = PSY.get_kd(x), kω = PSY.get_kω(x)) +get_params_metadata(::PSY.VirtualInertia) = ( + Ta = ParamsMetadata(false, false, false), + kd = ParamsMetadata(false, false, false), + kω = ParamsMetadata(false, false, false), +) +#Note: Removed fbdd_pnts from parameters because it is not a NamedTuple +get_params(x::PSY.ActiveRenewableControllerAB) = ( + K_pg = PSY.get_K_pg(x), + K_ig = PSY.get_K_ig(x), + T_p = PSY.get_T_p(x), + fe_lim = PSY.get_fe_lim(x), + P_lim = PSY.get_P_lim(x), + T_g = PSY.get_T_g(x), + D_dn = PSY.get_D_dn(x), + D_up = PSY.get_D_up(x), + dP_lim = PSY.get_dP_lim(x), + P_lim_inner = PSY.get_P_lim_inner(x), + T_pord = PSY.get_T_pord(x), +) +get_params_metadata(::PSY.ActiveRenewableControllerAB) = ( + K_pg = ParamsMetadata(false, false, false), + K_ig = ParamsMetadata(false, false, true), + T_p = ParamsMetadata(false, false, true), + fe_lim = ( + min = ParamsMetadata(false, false, false), + max = ParamsMetadata(false, false, false), + ), + P_lim = ( + min = ParamsMetadata(false, false, false), + max = ParamsMetadata(false, false, false), + ), + T_g = ParamsMetadata(false, false, false), + D_dn = ParamsMetadata(false, false, false), + D_up = ParamsMetadata(false, false, false), + dP_lim = ( + min = ParamsMetadata(false, false, false), + max = ParamsMetadata(false, false, false), + ), + P_lim_innem_inner = ( + min = ParamsMetadata(false, false, false), + max = ParamsMetadata(false, false, false), + ), + T_pord = ParamsMetadata(false, false, false), +) #REACTIVE POWER CONTROL -get_params(x::PSY.ReactivePowerDroop) = [PSY.get_kq(x), PSY.get_ωf(x)] -get_params_metadata(x::PSY.ReactivePowerDroop) = [ - ParamsMetadata(:kq_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:ωf_ReactivePowerControl, false, false, false, false), -] -get_params(x::PSY.ReactiveRenewableControllerAB) = [ - PSY.get_T_fltr(x), - PSY.get_K_p(x), - PSY.get_K_i(x), - PSY.get_T_ft(x), - PSY.get_T_fv(x), - PSY.get_V_frz(x), - PSY.get_R_c(x), - PSY.get_X_c(x), - PSY.get_K_c(x), - PSY.get_e_lim(x)[1], - PSY.get_e_lim(x)[2], - PSY.get_dbd_pnts(x)[1], - PSY.get_dbd_pnts(x)[2], - PSY.get_Q_lim(x)[1], - PSY.get_Q_lim(x)[2], - PSY.get_T_p(x), - PSY.get_Q_lim_inner(x)[1], - PSY.get_Q_lim_inner(x)[2], - PSY.get_V_lim(x)[1], - PSY.get_V_lim(x)[2], - PSY.get_K_qp(x), - PSY.get_K_qi(x), -] -get_params_metadata(::PSY.ReactiveRenewableControllerAB) = [ - ParamsMetadata(:T_fltr_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:K_p_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:K_i_ReactivePowerControl, false, false, true, false), - ParamsMetadata(:T_ft_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:T_fv_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:V_frz_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:R_c_ReactivePowerControl, false, false, true, false), - ParamsMetadata(:X_c_ReactivePowerControl, false, false, true, false), - ParamsMetadata(:K_c_ReactivePowerControl, false, false, true, false), - ParamsMetadata(:e_min_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:e_max_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:dbd_pnts1_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:dbd_pnts2_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:Q_min_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:Q_max_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:T_p_ReactivePowerControl, false, false, true, false), - ParamsMetadata(:Q_min_inner_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:Q_max_inner_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:V_min_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:V_max_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:K_qp_ReactivePowerControl, false, false, false, false), - ParamsMetadata(:K_qi_ReactivePowerControl, false, false, true, false), -] +get_params(x::PSY.ReactivePowerDroop) = (kq = PSY.get_kq(x), ωf = PSY.get_ωf(x)) +get_params_metadata(::PSY.ReactivePowerDroop) = ( + kq = ParamsMetadata(false, false, false), + ωf = ParamsMetadata(false, false, false), +) +get_params(x::PSY.ReactiveRenewableControllerAB) = ( + T_fltr = PSY.get_T_fltr(x), + K_p = PSY.get_K_p(x), + K_i = PSY.get_K_i(x), + T_ft = PSY.get_T_ft(x), + T_fv = PSY.get_T_fv(x), + V_frz = PSY.get_V_frz(x), + R_c = PSY.get_R_c(x), + X_c = PSY.get_X_c(x), + K_c = PSY.get_K_c(x), + e_lim = (min = PSY.get_e_lim(x)[:min], max = PSY.get_e_lim(x)[:max]), + Q_lim = (min = PSY.get_Q_lim(x)[:min], max = PSY.get_Q_lim(x)[:max]), + T_p = PSY.get_T_p(x), + Q_lim_inner = (min = PSY.get_Q_lim_inner(x)[:min], max = PSY.get_Q_lim_inner(x)[:max]), + V_lim = (min = PSY.get_V_lim(x)[:min], max = PSY.get_V_lim(x)[:max]), + K_qp = PSY.get_K_qp(x), + K_qi = PSY.get_K_qi(x), +) +get_params_metadata(::PSY.ReactiveRenewableControllerAB) = + (T_fltr = ParamsMetadata(false, false, false), + K_p = ParamsMetadata(false, false, false), + K_i = ParamsMetadata(false, false, true), + T_ft = ParamsMetadata(false, false, false), + T_fv = ParamsMetadata(false, false, false), + V_frz = ParamsMetadata(false, false, false), + R_c = ParamsMetadata(false, false, true), + X_c = ParamsMetadata(false, false, true), + K_c = ParamsMetadata(false, false, true), + e_lim = ( + min = ParamsMetadata(false, false, false), + max = ParamsMetadata(false, false, false), + ), + Q_lim = ( + min = ParamsMetadata(false, false, false), + max = ParamsMetadata(false, false, false), + ), + T_p = ParamsMetadata(false, false, true), + Q_lim_inner = ( + min = ParamsMetadata(false, false, false), + max = ParamsMetadata(false, false, false), + ), + V_lim = ( + min = ParamsMetadata(false, false, false), + max = ParamsMetadata(false, false, false), + ), + K_qp = ParamsMetadata(false, false, false), + K_qi = ParamsMetadata(false, false, true), + ) +#= += PSY.get_dbd_pnts(x)[1], += PSY.get_dbd_pnts(x)[2], + +ParamsMetadata(:dbd_pnts1_ReactivePowerControl, false, false, false, false), +ParamsMetadata(:dbd_pnts2_ReactivePowerControl, false, false, false, false), + =# +#= #INNER CONTROL get_params(x::PSY.VoltageModeControl) = [ @@ -308,36 +317,37 @@ get_params_metadata(::PSY.RenewableEnergyConverterTypeA) = [ ParamsMetadata(:Q_ref_Converter, false, false, false, false) ParamsMetadata(:R_source_Converter, false, false, false, false) ParamsMetadata(:X_source_Converter, false, false, false, false) -] +] =# ########### GENERATORS ############# function get_params(g::PSY.DynamicGenerator) - vcat( - get_params(PSY.get_machine(g)), - get_params(PSY.get_shaft(g)), - get_params(PSY.get_avr(g)), - get_params(PSY.get_prime_mover(g)), - get_params(PSY.get_pss(g)), + return ( + Machine = get_params(PSY.get_machine(g)), + Shaft = get_params(PSY.get_shaft(g)), + AVR = get_params(PSY.get_avr(g)), + TurbineGov = get_params(PSY.get_prime_mover(g)), + PSS = get_params(PSY.get_pss(g)), ) end function get_params_metadata(g::PSY.DynamicGenerator) - vcat( - get_params_metadata(PSY.get_machine(g)), - get_params_metadata(PSY.get_shaft(g)), - get_params_metadata(PSY.get_avr(g)), - get_params_metadata(PSY.get_prime_mover(g)), - get_params_metadata(PSY.get_pss(g)), + return ( + Machine = get_params_metadata(PSY.get_machine(g)), + Shaft = get_params_metadata(PSY.get_shaft(g)), + AVR = get_params_metadata(PSY.get_avr(g)), + TurbineGov = get_params_metadata(PSY.get_prime_mover(g)), + PSS = get_params_metadata(PSY.get_pss(g)), ) end #MACHINES -get_params(x::PSY.BaseMachine) = [PSY.get_R(x), PSY.get_Xd_p(x), PSY.get_eq_p(x)] -get_params_metadata(::PSY.BaseMachine) = [ - ParamsMetadata(:R_Machine, false, false, true, false), - ParamsMetadata(:Xd_p_Machine, false, false, true, false), - ParamsMetadata(:eq_p_Machine, false, false, true, false), -] -get_params(x::PSY.OneDOneQMachine) = [ +get_params(x::PSY.BaseMachine) = + (R = PSY.get_R(x), Xd_p = PSY.get_Xd_p(x), eq_p = PSY.get_eq_p(x)) +get_params_metadata(::PSY.BaseMachine) = ( + R = ParamsMetadata(false, false, true), + Xd_p = ParamsMetadata(false, false, true), + eq_p = ParamsMetadata(false, false, true), +) +#= get_params(x::PSY.OneDOneQMachine) = [ PSY.get_R(x), PSY.get_Xd(x), PSY.get_Xq(x), @@ -414,47 +424,48 @@ get_params_metadata(::PSY.AndersonFouadMachine) = [ ParamsMetadata(:Tq0_pp_Machine, false, false, false, false), ] #NOTE: Saturation not considered as paramters +=# get_params( x::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, -) = [ - PSY.get_R(x), - PSY.get_Td0_p(x), - PSY.get_Td0_pp(x), - PSY.get_Tq0_p(x), - PSY.get_Tq0_pp(x), - PSY.get_Xd(x), - PSY.get_Xq(x), - PSY.get_Xd_p(x), - PSY.get_Xq_p(x), - PSY.get_Xd_pp(x), - PSY.get_Xl(x), - PSY.get_γ_d1(x), - PSY.get_γ_q1(x), - PSY.get_γ_d2(x), - PSY.get_γ_q2(x), - PSY.get_γ_qd(x), -] +) = ( + R = PSY.get_R(x), + Td0_p = PSY.get_Td0_p(x), + Td0_pp = PSY.get_Td0_pp(x), + Tq0_p = PSY.get_Tq0_p(x), + Tq0_pp = PSY.get_Tq0_pp(x), + Xd = PSY.get_Xd(x), + Xq = PSY.get_Xq(x), + Xd_p = PSY.get_Xd_p(x), + Xq_p = PSY.get_Xq_p(x), + Xd_pp = PSY.get_Xd_pp(x), + Xl = PSY.get_Xl(x), + γ_d1 = PSY.get_γ_d1(x), + γ_q1 = PSY.get_γ_q1(x), + γ_d2 = PSY.get_γ_d2(x), + γ_q2 = PSY.get_γ_q2(x), + γ_qd = PSY.get_γ_qd(x), +) get_params_metadata( ::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, -) = [ - ParamsMetadata(:R_Machine, false, false, true, false), - ParamsMetadata(:Td0_p_Machine, false, false, true, false), - ParamsMetadata(:Td0_pp_Machine, false, false, true, false), - ParamsMetadata(:Tq0_p_Machine, false, false, true, false), - ParamsMetadata(:Tq0_pp_Machine, false, false, true, false), - ParamsMetadata(:Xd_Machine, false, false, true, false), - ParamsMetadata(:Xq_Machine, false, false, true, false), - ParamsMetadata(:Xd_p_Machine, false, false, true, false), - ParamsMetadata(:Xq_p_Machine, false, false, true, false), - ParamsMetadata(:Xd_pp_Machine, false, false, true, false), - ParamsMetadata(:Xl_Machine, false, false, true, false), - ParamsMetadata(:γ_d1_Machine, false, false, true, false), - ParamsMetadata(:γ_q1_Machine, false, false, true, false), - ParamsMetadata(:γ_d2_Machine, false, false, true, false), - ParamsMetadata(:γ_q2_Machine, false, false, true, false), - ParamsMetadata(:γ_qd_Machine, false, false, true, false), -] -get_params( +) = ( + R = ParamsMetadata(false, false, true), + Td0_p = ParamsMetadata(false, false, true), + Td0_pp = ParamsMetadata(false, false, true), + Tq0_p = ParamsMetadata(false, false, true), + Tq0_pp = ParamsMetadata(false, false, true), + Xd = ParamsMetadata(false, false, true), + Xq = ParamsMetadata(false, false, true), + Xd_p = ParamsMetadata(false, false, true), + Xq_p = ParamsMetadata(false, false, true), + Xd_pp = ParamsMetadata(false, false, true), + Xl = ParamsMetadata(false, false, true), + γ_d1 = ParamsMetadata(false, false, true), + γ_q1 = ParamsMetadata(false, false, true), + γ_d2 = ParamsMetadata(false, false, true), + γ_q2 = ParamsMetadata(false, false, true), + γ_qd = ParamsMetadata(false, false, true), +) +#= get_params( x::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, ) = [ PSY.get_R(x), @@ -485,15 +496,16 @@ get_params_metadata( ParamsMetadata(:γ_d1_Machine, false, false, true, false), ParamsMetadata(:γ_q1_Machine, false, false, true, false), ParamsMetadata(:γ_d2_Machine, false, false, true, false), -] +] =# #SHAFTS -get_params(x::PSY.SingleMass) = [PSY.get_H(x), PSY.get_D(x)] -get_params_metadata(::PSY.SingleMass) = [ - ParamsMetadata(:H_Shaft, false, false, false, false), - ParamsMetadata(:D_Shaft, false, false, false, false), -] -get_params(x::PSY.FiveMassShaft) = [ +get_params(x::PSY.SingleMass) = (H = PSY.get_H(x), D = PSY.get_D(x)) +get_params_metadata(::PSY.SingleMass) = ( + H = ParamsMetadata(false, false, false), + D = ParamsMetadata(false, false, false), +) + +#= get_params(x::PSY.FiveMassShaft) = [ PSY.get_H(x), PSY.get_H_hp(x), PSY.get_H_ip(x), @@ -532,12 +544,13 @@ get_params_metadata(::PSY.FiveMassShaft) = [ ParamsMetadata(:K_ip_Shaft, false, false, true, false) ParamsMetadata(:K_lp_Shaft, false, false, true, false) ParamsMetadata(:K_ex_Shaft, false, false, true, false) -] +] =# #AVRS -get_params(::PSY.AVRFixed) = Float64[] -get_params_metadata(::PSY.AVRFixed) = ParamsMetadata[] -get_params(x::PSY.AVRSimple) = [PSY.get_Kv(x)] +get_params(::PSY.AVRFixed) = (;) +get_params_metadata(::PSY.AVRFixed) = (;) + +#= get_params(x::PSY.AVRSimple) = [PSY.get_Kv(x)] get_params_metadata(::PSY.AVRSimple) = [ParamsMetadata(:Kv_AVR, false, false, false, false)] get_params(x::PSY.AVRTypeI) = [ PSY.get_Ka(x), @@ -561,23 +574,26 @@ get_params_metadata(::PSY.AVRTypeI) = [ ParamsMetadata(:Ae_AVR, false, false, true, false), ParamsMetadata(:Be_AVR, false, false, true, false), ] -get_params(x::PSY.SEXS) = [ - PSY.get_Ta_Tb(x), - PSY.get_Tb(x), - PSY.get_K(x), - PSY.get_Te(x), - PSY.get_V_lim(x)[1], - PSY.get_V_lim(x)[2], -] -get_params_metadata(::PSY.SEXS) = [ - ParamsMetadata(:Ta_Tb_AVR, false, false, true, false) - ParamsMetadata(:Tb_AVR, false, false, false, false) - ParamsMetadata(:K_AVR, false, false, true, false) - ParamsMetadata(:Te_AVR, false, false, false, false) - ParamsMetadata(:V_min_AVR, false, false, true, false) - ParamsMetadata(:V_max_AVR, false, false, true, false) -] -get_params(x::PSY.AVRTypeII) = [ + =# + +get_params(x::PSY.SEXS) = ( + Ta_Tb = PSY.get_Ta_Tb(x), + Tb = PSY.get_Tb(x), + K = PSY.get_K(x), + Te = PSY.get_Te(x), + V_lim = PSY.get_V_lim(x), +) +get_params_metadata(::PSY.SEXS) = ( + Ta_Tb = ParamsMetadata(false, false, true), + Tb = ParamsMetadata(false, false, false), + K = ParamsMetadata(false, false, true), + Te = ParamsMetadata(false, false, false), + V_lim = ( + min = ParamsMetadata(false, false, true), + max = ParamsMetadata(false, false, true), + ), +) +#= get_params(x::PSY.AVRTypeII) = [ PSY.get_K0(x), PSY.get_T1(x), PSY.get_T2(x), @@ -694,11 +710,11 @@ get_params_metadata(::PSY.EXAC1) = [ ParamsMetadata(:Kd_AVR, false, false, true, false), ParamsMetadata(:Ke_AVR, false, false, true, false), ] - + =# #TurbineGov -get_params(x::PSY.TGFixed) = [PSY.get_efficiency(x)] -get_params_metadata(::PSY.TGFixed) = - [ParamsMetadata(:efficiency_TurbineGov, false, false, true, false)] +get_params(x::PSY.TGFixed) = (; efficiency = PSY.get_efficiency(x)) +get_params_metadata(::PSY.TGFixed) = (; efficiency = ParamsMetadata(false, false, true)) +#= get_params(x::PSY.TGTypeII) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_T2(x)] get_params_metadata(::PSY.TGTypeII) = [ ParamsMetadata(:R_tg_TurbineGovR, false, false, true, false), @@ -747,23 +763,28 @@ get_params_metadata(::PSY.TGTypeI) = [ ParamsMetadata(:valve_position_min_TurbineGov, false, false, true, false), ParamsMetadata(:valve_position_max_TurbineGov, false, false, true, false), ] -get_params(x::PSY.SteamTurbineGov1) = [PSY.get_R(x), - PSY.get_T1(x), - PSY.get_valve_position_limits(x)[1], - PSY.get_valve_position_limits(x)[2], - PSY.get_T2(x), - PSY.get_T3(x), - PSY.get_D_T(x)] -get_params_metadata(::PSY.SteamTurbineGov1) = [ - ParamsMetadata(:R_tg, false, false, true, false), - ParamsMetadata(:T1_TurbineGov, false, false, true, false), - ParamsMetadata(:valve_position_min_TurbineGov, false, false, true, false), - ParamsMetadata(:valve_position_max_TurbineGov, false, false, true, false), - ParamsMetadata(:T2_TurbineGov, false, false, true, false), - ParamsMetadata(:T3_TurbineGov, false, false, true, false), - ParamsMetadata(:D_T_TurbineGov, false, false, true, false), -] -get_params(x::PSY.HydroTurbineGov) = [ + =# + +get_params(x::PSY.SteamTurbineGov1) = ( + R = PSY.get_R(x), + T1 = PSY.get_T1(x), + valve_position_limits = PSY.get_valve_position_limits(x), + T2 = PSY.get_T2(x), + T3 = PSY.get_T3(x), + D_T = PSY.get_D_T(x), +) +get_params_metadata(::PSY.SteamTurbineGov1) = ( + R = ParamsMetadata(false, false, true), + T1 = ParamsMetadata(false, false, true), + valve_position = ( + min = ParamsMetadata(false, false, true), + max = ParamsMetadata(false, false, true), + ), + T2 = ParamsMetadata(false, false, true), + T3 = ParamsMetadata(false, false, true), + D_T = ParamsMetadata(false, false, true), +) +#= get_params(x::PSY.HydroTurbineGov) = [ PSY.get_R(x), PSY.get_r(x), PSY.get_Tr(x), @@ -790,12 +811,12 @@ get_params_metadata(::PSY.HydroTurbineGov) = [ ParamsMetadata(:At_TurbineGov, false, false, true, false), ParamsMetadata(:D_T_TurbineGov, false, false, true, false), ParamsMetadata(:q_nl_TurbineGov, false, false, true, false), -] +] =# #PSS -get_params(x::PSY.PSSFixed) = [PSY.get_V_pss(x)] -get_params_metadata(::PSY.PSSFixed) = - [ParamsMetadata(:V_pss_PSS, false, false, false, false)] +get_params(x::PSY.PSSFixed) = (; V_pss = PSY.get_V_pss(x)) +get_params_metadata(::PSY.PSSFixed) = (; V_pss = ParamsMetadata(false, false, false)) +#= get_params(x::PSY.STAB1) = [ PSY.get_KT(x), PSY.get_T(x), @@ -813,19 +834,19 @@ get_params_metadata(::PSY.STAB1) = [ ParamsMetadata(:T2T4_PSS, false, false, false, false), ParamsMetadata(:T4_PSS, false, false, false, false), ParamsMetadata(:H_lim_PSS, false, false, false, false), -] +] =# #SOURCE -get_params(x::PSY.Source) = [ - PSY.get_R_th(x), - PSY.get_X_th(x), -] -get_params_metadata(::PSY.Source) = [ - ParamsMetadata(:R_th, false, false, true, false), - ParamsMetadata(:X_th, false, false, true, false), -] +get_params(x::PSY.Source) = ( + R_th = PSY.get_R_th(x), + X_th = PSY.get_X_th(x), +) +get_params_metadata(::PSY.Source) = ( + R_th = ParamsMetadata(false, false, true), + X_th = ParamsMetadata(false, false, true), +) #Parameters not implemented for PeriodicVariableSource - requires change in PSY Struct to have information required to construct and deconstruct parameter vector - +#= #DYNAMIC LOADS get_params(x::PSY.ActiveConstantPowerLoad) = [ PSY.get_r_load(x), @@ -1016,3 +1037,4 @@ get_params_metadata(::PSY.CSVGN1) = [ ParamsMetadata(:R_th, false, false, false, false), ParamsMetadata(:X_th, false, false, false, false), ] + =# diff --git a/test/Project.toml b/test/Project.toml index e3321c8dd..c0363117e 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -6,6 +6,7 @@ DelayDiffEq = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb" DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" diff --git a/test/runtests.jl b/test/runtests.jl index 48bc51dbd..fcfc17033 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -15,6 +15,11 @@ using PowerNetworkMatrices import LinearAlgebra using Logging using SciMLSensitivity +using Enzyme +Enzyme.API.runtimeActivity!(true) +Enzyme.API.looseTypeAnalysis!(true) #Required for using component arrays with Enzyme +Enzyme.API.maxtypeoffset!(1024) +Enzyme.API.maxtypedepth!(20) using Zygote using Optimization using OptimizationOptimisers From 2635603a74fc692b9baf793a7e7107f7438d41e0 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 30 May 2024 09:28:56 -0400 Subject: [PATCH 14/76] remove enable_sensitivity (passes test_case_OMIB) --- src/PowerSimulationsDynamics.jl | 8 +- src/base/sensitivity_analysis.jl | 1 - src/base/simulation.jl | 127 +++----------------------- src/base/simulation_initialization.jl | 6 +- 4 files changed, 17 insertions(+), 125 deletions(-) diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index 9051b968b..4e528803a 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -61,9 +61,9 @@ export is_valid export transform_load_to_constant_impedance export transform_load_to_constant_current export transform_load_to_constant_power -export get_parameter_values -export get_forward_function -export get_gradient_function +#export get_parameter_values +#export get_forward_function +#export get_gradient_function ####################################### Package Imports #################################### import Logging @@ -136,7 +136,7 @@ include("base/nlsolve_wrapper.jl") include("base/simulation_initialization.jl") include("base/small_signal.jl") include("base/model_validation.jl") -include("base/sensitivity_analysis.jl") +#include("base/sensitivity_analysis.jl") #Common Models include("models/branch.jl") diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index c9e762cae..1f32e5eb7 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -35,7 +35,6 @@ function get_parameter_sensitivity_function!(sim, device_param_pairs, f) reset!(sim) @assert sim.status == BUILT sim.initialize_level = sim_level - sim.enable_sensitivity = true sensitivity_function = (p, data) -> begin sim.inputs = deepcopy(sim.inputs_init) diff --git a/src/base/simulation.jl b/src/base/simulation.jl index 4a8f7664a..e6d839bb8 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -17,7 +17,6 @@ mutable struct Simulation{T <: SimulationModel} file_level::Base.CoreLogging.LogLevel multimachine::Bool frequency_reference::Union{ConstantFrequency, ReferenceBus} - enable_sensitivity::Bool end get_system(sim::Simulation) = sim.sys @@ -68,7 +67,6 @@ function Simulation( file_level, false, frequency_reference, - false, ) end @@ -144,7 +142,7 @@ function Simulation!( frequency_reference = get(kwargs, :frequency_reference, ReferenceBus()), ) - build!(sim, Val(sim.enable_sensitivity); kwargs...) + build!(sim; kwargs...) if get(kwargs, :system_to_file, false) PSY.to_json(system, joinpath(simulation_folder, "initialized_system.json")) end @@ -201,7 +199,7 @@ function Simulation( file_level = get(kwargs, :file_level, Logging.Info), frequency_reference = get(kwargs, :frequency_reference, ReferenceBus()), ) - build!(sim, Val(sim.enable_sensitivity); kwargs...) + build!(sim; kwargs...) if get(kwargs, :system_to_file, false) PSY.to_json(system, joinpath(simulation_folder, "input_system.json")) end @@ -211,7 +209,7 @@ end function reset!(sim::Simulation{T}) where {T <: SimulationModel} CRC.@ignore_derivatives @info "Rebuilding the simulation after reset" sim.status = BUILD_INCOMPLETE - build!(sim, Val(sim.enable_sensitivity)) + build!(sim) CRC.@ignore_derivatives @info "Simulation reset to status $(sim.status)" return end @@ -252,7 +250,7 @@ function _get_flat_start(inputs::SimulationInputs) end function _pre_initialize_simulation!(sim::Simulation) - _initialize_state_space(sim, Val(sim.initialize_level), Val(sim.enable_sensitivity)) + _initialize_state_space(sim, Val(sim.initialize_level)) return end @@ -318,7 +316,6 @@ function _get_diffeq_problem( sim::Simulation, model::SystemModel{ResidualModel, NoDelays}, jacobian::JacobianFunctionWrapper, - ::Val{false}, ) x0 = get_x0(sim) sim.x0_init = deepcopy(x0) @@ -342,36 +339,12 @@ function _get_diffeq_problem( return end -function _get_diffeq_problem( - sim::Simulation, - model::SystemModel{MassMatrixModel, NoDelays}, - jacobian::JacobianFunctionWrapper, - ::Val{true}, -) - x0 = get_x0(sim) - sim.x0_init = deepcopy(x0) - simulation_inputs = get_simulation_inputs(sim) - p = get_parameters(simulation_inputs) - sim.problem = SciMLBase.ODEProblem( - SciMLBase.ODEFunction{true}( - model; - mass_matrix = get_mass_matrix(simulation_inputs), - # Necessary to avoid unnecessary calculations in Rosenbrock methods - tgrad = (dT, u, p, t) -> dT .= false, - ), - x0, - get_tspan(sim), - p; - ) - sim.status = BUILT - return -end + function _get_diffeq_problem( sim::Simulation, model::SystemModel{MassMatrixModel, NoDelays}, jacobian::JacobianFunctionWrapper, - ::Val{false}, ) x0 = get_x0(sim) sim.x0_init = deepcopy(x0) @@ -404,7 +377,6 @@ function _get_diffeq_problem( sim::Simulation, model::SystemModel{MassMatrixModel, HasDelays}, jacobian::JacobianFunctionWrapper, - ::Val{false}, ) x0 = get_x0(sim) sim.x0_init = deepcopy(x0) @@ -429,69 +401,9 @@ function _get_diffeq_problem( return end -function _get_diffeq_problem( - sim::Simulation, - model::SystemModel{MassMatrixModel, HasDelays}, - jacobian::JacobianFunctionWrapper, - ::Val{true}, -) - x0 = get_x0(sim) - sim.x0_init = deepcopy(x0) - simulation_inputs = get_simulation_inputs(sim) - h = get_history_function(sim) - p = get_parameters(simulation_inputs) - sim.problem = SciMLBase.DDEProblem( - SciMLBase.DDEFunction{true}( - model; - mass_matrix = get_mass_matrix(simulation_inputs), - ), - x0, - h, - get_tspan(sim), - p; - constant_lags = filter(x -> x != 0, get_constant_lags(simulation_inputs)), - ) - sim.status = BUILT - - return -end - -#Does not build inputs (enable_sensitivity = true) -function _build!(sim::Simulation{T}, ::Val{true}; kwargs...) where {T <: SimulationModel} - check_kwargs(kwargs, SIMULATION_ACCEPTED_KWARGS, "Simulation") - # Branches are a super set of Lines. Passing both kwargs will - # be redundant. - if get(kwargs, :all_branches_dynamic, false) - sys = get_system(sim) - transform_branches_to_dynamic(sys, PSY.ACBranch) - elseif get(kwargs, :all_lines_dynamic, false) - sys = get_system(sim) - transform_branches_to_dynamic(sys, PSY.Line) - end - sim.multimachine = - get_global_vars_update_pointers(sim.inputs)[GLOBAL_VAR_SYS_FREQ_INDEX] != - 0 - _pre_initialize_simulation!(sim) - if sim.status != BUILD_FAILED - simulation_inputs = get_simulation_inputs(sim) - jacobian = CRC.@ignore_derivatives _get_jacobian(sim) #see MWE; can ignore derivative of Jacobian construction? - model = T(simulation_inputs, get_x0(sim), SimCache) - refine_initial_condition!( - sim, - model, - jacobian, - Val(sim.initialize_level), - ) - CRC.@ignore_derivatives _build_perturbations!(sim) #todo - can we safely ignore derivatives here? - _get_diffeq_problem(sim, model, jacobian, Val(sim.enable_sensitivity)) - CRC.@ignore_derivatives @info "Simulations status = $(sim.status)" - else - CRC.@ignore_derivatives @error "The simulation couldn't be initialized correctly. Simulations status = $(sim.status)" - end - return -end - -function _build!(sim::Simulation{T}, ::Val{false}; kwargs...) where {T <: SimulationModel} +#Timers on this level are fine; but not for initializing individual types of components. +#Seems like a reasonable tradeoff for reduced complexity; allows getting rid of "enable_sensitivity" +function _build!(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} check_kwargs(kwargs, SIMULATION_ACCEPTED_KWARGS, "Simulation") # Branches are a super set of Lines. Passing both kwargs will # be redundant. @@ -544,7 +456,7 @@ function _build!(sim::Simulation{T}, ::Val{false}; kwargs...) where {T <: Simula _build_perturbations!(sim) end TimerOutputs.@timeit BUILD_TIMER "Make DiffEq Problem" begin - _get_diffeq_problem(sim, model, jacobian, Val(sim.enable_sensitivity)) + _get_diffeq_problem(sim, model, jacobian) end @info "Simulations status = $(sim.status)" else @@ -559,15 +471,11 @@ function _build!(sim::Simulation{T}, ::Val{false}; kwargs...) where {T <: Simula return end -function build!(sim, ::Val{true}; kwargs...) - _build!(sim, Val(sim.enable_sensitivity); kwargs...) - return sim.status -end -function build!(sim, ::Val{false}; kwargs...) +function build!(sim; kwargs...) logger = configure_logging(sim, "w") Logging.with_logger(logger) do - _build!(sim, Val(sim.enable_sensitivity); kwargs...) + _build!(sim; kwargs...) #if sim.status == BUILT string_buffer = IOBuffer() TimerOutputs.print_timer( @@ -611,9 +519,7 @@ end function _execute!(sim::Simulation, solver; kwargs...) CRC.@ignore_derivatives @debug "status before execute" sim.status - if !(sim.enable_sensitivity) - CRC.@ignore_derivatives simulation_pre_step!(sim) - end + CRC.@ignore_derivatives simulation_pre_step!(sim) sim.status = SIMULATION_STARTED time_log = Dict{Symbol, Any}() if get(kwargs, :auto_abstol, false) @@ -669,10 +575,6 @@ Solves the time-domain dynamic simulation model. - Additional solver keyword arguments can be included. See [Common Solver Options](https://diffeq.sciml.ai/stable/basics/common_solver_opts/) in the `DifferentialEquations.jl` documentation for more details. """ function execute!(sim::Simulation, solver; kwargs...) - execute!(sim, Val(sim.enable_sensitivity), solver; kwargs...) -end - -function execute!(sim::Simulation, ::Val{false}, solver; kwargs...) logger = configure_logging(sim, "a"; kwargs...) Logging.with_logger(logger) do try @@ -687,11 +589,6 @@ function execute!(sim::Simulation, ::Val{false}, solver; kwargs...) return sim.status end -function execute!(sim::Simulation, ::Val{true}, solver; kwargs...) - _execute!(sim, solver; kwargs...) - return sim.status -end - function read_results(sim::Simulation) return sim.results end diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index d3499b532..a2cee0ac5 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -130,11 +130,10 @@ end # Default implementation for both models. This implementation is to future proof if there is # a divergence between the required build methods -#PASS x0, not sim....? +#PASS x0 and inputs, but not the full simulation not sim....? function _initialize_state_space( sim::Simulation{T}, ::Val{POWERFLOW_AND_DEVICES}, - ::Val{false}, #not yet supported with sensitivity analysis ) where {T <: SimulationModel} inputs = get_simulation_inputs(sim) sim.x0 = _get_flat_start(inputs) @@ -159,7 +158,6 @@ end function _initialize_state_space( sim::Simulation{T}, ::Val{DEVICES_ONLY}, - ::Val{false}, #not yet supported with sensitivity analysis ) where {T <: SimulationModel} CRC.@ignore_derivatives @info("Pre-Initializing Simulation States") inputs = get_simulation_inputs(sim) @@ -181,7 +179,6 @@ end function _initialize_state_space( sim::Simulation{T}, ::Val{FLAT_START}, - ::Union{Val{true}, Val{false}}, ) where {T <: SimulationModel} simulation_inputs = get_simulation_inputs(sim) sim.x0 = _get_flat_start(simulation_inputs) @@ -190,7 +187,6 @@ end function _initialize_state_space( sim::Simulation{T}, ::Val{INITIALIZED}, - ::Union{Val{true}, Val{false}}, ) where {T <: SimulationModel} simulation_inputs = get_simulation_inputs(sim) @assert sim.status == BUILD_INCOMPLETE From a0aef5837e557161798940ca758f6b4598c458d5 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 30 May 2024 16:15:13 -0400 Subject: [PATCH 15/76] remove refs from dyn wrapper; add reactive_power field (OMIB passes) --- src/PowerSimulationsDynamics.jl | 2 +- src/base/device_wrapper.jl | 41 +++---------------- src/base/simulation.jl | 5 +-- src/base/simulation_initialization.jl | 4 +- src/base/simulation_inputs.jl | 21 +++++----- .../generator_components/init_avr.jl | 4 +- .../inverter_components/init_filter.jl | 2 +- src/models/generator_models/avr_models.jl | 7 ++-- 8 files changed, 25 insertions(+), 61 deletions(-) diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index 4e528803a..ae85bdb86 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -88,7 +88,7 @@ import Enzyme Enzyme.API.runtimeActivity!(true) Enzyme.API.looseTypeAnalysis!(true) #Required for using component arrays with Enzyme Enzyme.API.maxtypeoffset!(1024) -Enzyme.API.maxtypedepth!(20) +Enzyme.API.maxtypedepth!(20) #Enzyme.API.runtimeActivity!(true) #= Generally, the preferred solution to these type of activity unstable codes should be to make your variables all activity-stable (e.g. always containing differentiable memory or always diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index 22cd85b18..badcb21c1 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -32,15 +32,12 @@ status, and allocate the required indexes of the state space and parameter space """ struct DynamicWrapper{T <: PSY.DynamicInjection} device::T + reactive_power::Float64 system_base_power::Float64 system_base_frequency::Float64 static_type::Type{<:PSY.StaticInjection} bus_category::Type{<:BusCategory} connection_status::Base.RefValue{Float64} - V_ref::Base.RefValue{Float64} - ω_ref::Base.RefValue{Float64} - P_ref::Base.RefValue{Float64} - Q_ref::Base.RefValue{Float64} inner_vars_index::Vector{Int} ix_range::Vector{Int} ode_range::Vector{Int} @@ -52,15 +49,12 @@ struct DynamicWrapper{T <: PSY.DynamicInjection} function DynamicWrapper( device::T, + reactive_power::Float64, system_base_power::Float64, system_base_frequency::Float64, static_type::Type{<:PSY.StaticInjection}, bus_category::Type{<:BusCategory}, connection_status::Base.RefValue{Float64}, - V_ref::Base.RefValue{Float64}, - ω_ref::Base.RefValue{Float64}, - P_ref::Base.RefValue{Float64}, - Q_ref::Base.RefValue{Float64}, inner_vars_index, ix_range, ode_range, @@ -74,15 +68,12 @@ struct DynamicWrapper{T <: PSY.DynamicInjection} new{T}( device, + reactive_power, system_base_power, system_base_frequency, static_type, bus_category, connection_status, - V_ref, - ω_ref, - P_ref, - Q_ref, Vector{Int}(inner_vars_index), Vector{Int}(ix_range), Vector{Int}(ode_range), @@ -137,15 +128,12 @@ function DynamicWrapper( end return DynamicWrapper( dynamic_device, + reactive_power, sys_base_power, sys_base_freq, T, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), - Base.Ref(PSY.get_V_ref(dynamic_device)), - Base.Ref(PSY.get_ω_ref(dynamic_device)), - Base.Ref(PSY.get_P_ref(dynamic_device)), - Base.Ref(reactive_power), inner_var_range, ix_range, ode_range, @@ -190,10 +178,6 @@ function DynamicWrapper( PSY.ThermalStandard, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), - Base.Ref(PSY.get_V_ref(dynamic_device)), - Base.Ref(PSY.get_ω_ref(dynamic_device)), - Base.Ref(PSY.get_P_ref(dynamic_device)), - Base.Ref(PSY.get_reactive_power(static_device)), inner_var_range, ix_range, ode_range, @@ -236,10 +220,6 @@ function DynamicWrapper( PSY.Source, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), - Base.Ref(0.0), - Base.Ref(0.0), - Base.Ref(0.0), - Base.Ref(0.0), collect(inner_var_range), collect(ix_range), collect(ode_range), @@ -275,6 +255,7 @@ function _index_port_mapping!( end get_device(wrapper::DynamicWrapper) = wrapper.device +get_reactive_power(wrapper::DynamicWrapper) = wrapper.reactive_power get_device_type(::DynamicWrapper{T}) where {T <: PSY.DynamicInjection} = T get_bus_category(wrapper::DynamicWrapper) = wrapper.bus_category get_inner_vars_index(wrapper::DynamicWrapper) = wrapper.inner_vars_index @@ -289,16 +270,6 @@ get_ext(wrapper::DynamicWrapper) = wrapper.ext get_system_base_power(wrapper::DynamicWrapper) = wrapper.system_base_power get_system_base_frequency(wrapper::DynamicWrapper) = wrapper.system_base_frequency -get_P_ref(wrapper::DynamicWrapper) = wrapper.P_ref[] -get_Q_ref(wrapper::DynamicWrapper) = wrapper.Q_ref[] -get_V_ref(wrapper::DynamicWrapper) = wrapper.V_ref[] -get_ω_ref(wrapper::DynamicWrapper) = wrapper.ω_ref[] - -set_P_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.P_ref[] = val -set_Q_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.Q_ref[] = val -set_V_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.V_ref[] = val -set_ω_ref(wrapper::DynamicWrapper, val::Float64) = wrapper.ω_ref[] = val - # PSY overloads for the wrapper PSY.get_name(wrapper::DynamicWrapper) = PSY.get_name(wrapper.device) PSY.get_ext(wrapper::DynamicWrapper) = PSY.get_ext(wrapper.device) @@ -375,7 +346,6 @@ struct StaticWrapper{T <: PSY.StaticInjection, V} θ_ref::Base.RefValue{Float64} P_ref::Base.RefValue{Float64} Q_ref::Base.RefValue{Float64} - #p_range::Vector{Int} bus_ix::Int ext::Dict{String, Any} end @@ -404,7 +374,6 @@ function StaticWrapper(device::T, bus_ix::Int, p_range) where {T <: PSY.Source} Base.Ref(PSY.get_internal_angle(device)), Base.Ref(PSY.get_active_power(device)), Base.Ref(PSY.get_reactive_power(device)), - #p_range, bus_ix, Dict{String, Any}(), ) diff --git a/src/base/simulation.jl b/src/base/simulation.jl index e6d839bb8..383bbba3e 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -1,5 +1,5 @@ mutable struct Simulation{T <: SimulationModel} - status::STATUS + status::STATUS problem::Union{Nothing, SciMLBase.DEProblem} tspan::NTuple{2, Float64} sys::PSY.System @@ -339,8 +339,6 @@ function _get_diffeq_problem( return end - - function _get_diffeq_problem( sim::Simulation, model::SystemModel{MassMatrixModel, NoDelays}, @@ -471,7 +469,6 @@ function _build!(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} return end - function build!(sim; kwargs...) logger = configure_logging(sim, "w") Logging.with_logger(logger) do diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index a2cee0ac5..854fe4b03 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -49,8 +49,8 @@ function initialize_dynamic_injection!( ) CRC.@ignore_derivatives @debug "Initializing $(PSY.get_name(dynamic_device)) - $(typeof(dynamic_device.device))" _inner_vars = @view initial_inner_vars[get_inner_vars_index(dynamic_device)] - _parameters = @view parameters[_get_wrapper_name(dynamic_device)] - _states = @view initial_guess[get_ix_range(dynamic_device)] + _parameters = @view parameters[_get_wrapper_name(dynamic_device)] + _states = @view initial_guess[get_ix_range(dynamic_device)] initialize_dynamic_device!( dynamic_device, static, diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index de5449f45..5d777a2ba 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -185,19 +185,16 @@ function _get_wrapper_name(wrapped_device::BranchWrapper) Symbol(PSY.get_name(PSY.get_branch(wrapped_device))) end -#Eventually remove references from wrapper and get the values here from static/dynamic devices -#This would require having the static device included in the dynamic wrapper (in order to get reactive power...) -#For now, the wrappers get the references correctly already, so can just put those values directly into p function _add_parameters(initial_parameters, wrapped_devices) for wrapped_device in wrapped_devices p = get_params(wrapped_device) name = _get_wrapper_name(wrapped_device) if isa(wrapped_device, DynamicWrapper) refs = ( - V_ref = get_V_ref(wrapped_device), - ω_ref = get_ω_ref(wrapped_device), - P_ref = get_P_ref(wrapped_device), - Q_ref = get_Q_ref(wrapped_device), + V_ref = PSY.get_V_ref(get_device(wrapped_device)), + ω_ref = PSY.get_ω_ref(get_device(wrapped_device)), + P_ref = PSY.get_P_ref(get_device(wrapped_device)), + Q_ref = get_reactive_power(wrapped_device), ) elseif isa(wrapped_device, StaticWrapper) refs = ( @@ -527,12 +524,14 @@ end function get_setpoints(inputs::SimulationInputs) dic = Dict{String, Dict{String, Float64}}() + p = inputs.parameters for w in get_dynamic_injectors(inputs) + wrapped_device_name = _get_wrapper_name(w) dic_w = Dict{String, Float64}() - dic_w["P_ref"] = get_P_ref(w) - dic_w["Q_ref"] = get_Q_ref(w) - dic_w["ω_ref"] = get_ω_ref(w) - dic_w["V_ref"] = get_V_ref(w) + dic_w["P_ref"] = p[wrapped_device_name][:refs][:P_ref] + dic_w["Q_ref"] = p[wrapped_device_name][:refs][:Q_ref] + dic_w["ω_ref"] = p[wrapped_device_name][:refs][:ω_ref] + dic_w["V_ref"] = p[wrapped_device_name][:refs][:V_ref] dic[PSY.get_name(w)] = dic_w end return dic diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index da40e472d..c7732ae9b 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -1,6 +1,6 @@ function initialize_avr!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRFixed, TG, P}}, inner_vars::AbstractVector, @@ -9,7 +9,7 @@ function initialize_avr!( Vf = inner_vars[Vf_var] #Update Control Refs avr = PSY.get_avr(dynamic_device) - set_V_ref(dynamic_device, Vf) + set_V_ref!(p, Vf) PSY.set_Vf!(avr, Vf) PSY.set_V_ref!(avr, Vf) return diff --git a/src/initialization/inverter_components/init_filter.jl b/src/initialization/inverter_components/init_filter.jl index b33eb149c..31c642bb8 100644 --- a/src/initialization/inverter_components/init_filter.jl +++ b/src/initialization/inverter_components/init_filter.jl @@ -27,7 +27,7 @@ function initialize_filter!( #Get Parameters params = p[:params][:Filter] - lf = params[:lf] + lf = params[:lf] rf = params[:rf] cf = params[:cf] lg = params[:lg] diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index c2b149baa..f83a4c9c4 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -64,16 +64,15 @@ end function mdl_avr_ode!( ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRFixed, TG, P}}, h, t, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} - + V_ref = p[:refs][:V_ref] #Update Vf voltage on inner vars. In AVRFixed, Vf = V_ref - inner_vars[Vf_var] = get_V_ref(dynamic_device) - + inner_vars[Vf_var] = V_ref return end From 7c3bace67c6892c1d0d23a45a6d835ab878f5951 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 30 May 2024 16:31:41 -0400 Subject: [PATCH 16/76] remove refs from StaticWrapper (test_case_OMIB passes) --- src/base/device_wrapper.jl | 23 ----------------------- src/base/simulation_inputs.jl | 23 +++++++++++++++++------ 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index badcb21c1..db8d1f52f 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -342,10 +342,6 @@ end struct StaticWrapper{T <: PSY.StaticInjection, V} device::T connection_status::Base.RefValue{Float64} - V_ref::Base.RefValue{Float64} - θ_ref::Base.RefValue{Float64} - P_ref::Base.RefValue{Float64} - Q_ref::Base.RefValue{Float64} bus_ix::Int ext::Dict{String, Any} end @@ -355,10 +351,6 @@ function DynamicWrapper(device::T, bus_ix::Int) where {T <: PSY.Device} StaticWrapper{T, BUS_MAP[PSY.get_bustype(bus)]}( device, Base.Ref(1.0), - Base.Ref(PSY.get_magnitude(bus)), - Base.Ref(PSY.get_angle(bus)), - Base.Ref(PSY.get_active_power(device)), - Base.Ref(PSY.get_reactive_power(device)), Vector{Int}(), bus_ix, Dict{String, Any}(), @@ -370,10 +362,6 @@ function StaticWrapper(device::T, bus_ix::Int, p_range) where {T <: PSY.Source} return StaticWrapper{T, BUS_MAP[PSY.get_bustype(bus)]}( device, Base.Ref(1.0), - Base.Ref(PSY.get_internal_voltage(device)), - Base.Ref(PSY.get_internal_angle(device)), - Base.Ref(PSY.get_active_power(device)), - Base.Ref(PSY.get_reactive_power(device)), bus_ix, Dict{String, Any}(), ) @@ -384,7 +372,6 @@ get_bus_category(::StaticWrapper{<:PSY.StaticInjection, U}) where {U} = U # TODO: something smart to forward fields get_device(wrapper::StaticWrapper) = wrapper.device -#get_p_range(wrapper::StaticWrapper) = wrapper.p_range get_bus_ix(wrapper::StaticWrapper) = wrapper.bus_ix get_ext(wrapper::StaticWrapper) = wrapper.ext @@ -394,16 +381,6 @@ PSY.get_reactive_power(wrapper::StaticWrapper) = PSY.get_reactive_power(wrapper. PSY.get_name(wrapper::StaticWrapper) = PSY.get_name(wrapper.device) PSY.get_ext(wrapper::StaticWrapper) = PSY.get_ext(wrapper.device) -get_P_ref(wrapper::StaticWrapper) = wrapper.P_ref[] -get_Q_ref(wrapper::StaticWrapper) = wrapper.Q_ref[] -get_V_ref(wrapper::StaticWrapper) = wrapper.V_ref[] -get_θ_ref(wrapper::StaticWrapper) = wrapper.θ_ref[] - -set_P_ref(wrapper::StaticWrapper, val::Float64) = wrapper.P_ref[] = val -set_Q_ref(wrapper::StaticWrapper, val::Float64) = wrapper.Q_ref[] = val -set_V_ref(wrapper::StaticWrapper, val::Float64) = wrapper.V_ref[] = val -set_θ_ref(wrapper::StaticWrapper, val::Float64) = wrapper.θ_ref[] = val - mutable struct ExpLoadParams P_exp::Float64 P_coeff::Float64 diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index 5d777a2ba..16226f33a 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -197,12 +197,23 @@ function _add_parameters(initial_parameters, wrapped_devices) Q_ref = get_reactive_power(wrapped_device), ) elseif isa(wrapped_device, StaticWrapper) - refs = ( - V_ref = get_V_ref(wrapped_device), - θ_ref = get_θ_ref(wrapped_device), - P_ref = get_P_ref(wrapped_device), - Q_ref = get_Q_ref(wrapped_device), - ) + device = get_device(wrapped_device) + if typeof(device) <: PSY.Source + refs = ( + V_ref = PSY.get_internal_voltage(device), + θ_ref = PSY.get_internal_angle(device), + P_ref = PSY.get_active_power(device), + Q_ref = PSY.get_reactive_power(device), + ) + else + bus = PSY.get_bus(device) + refs = ( + V_ref = PSY.get_magnitude(bus), + θ_ref = PSY.get_angle(bus), + P_ref = PSY.get_active_power(device), + Q_ref = PSY.get_reactive_power(device), + ) + end else refs = (;) end From 3047e391c61379df0044e970762fc7d98f3f5e40 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 30 May 2024 17:05:07 -0400 Subject: [PATCH 17/76] handle refs for staticloadwrapper --- src/base/device_wrapper.jl | 12 ++---------- src/base/nlsolve_wrapper.jl | 2 +- src/base/simulation_inputs.jl | 11 +++++++++++ src/models/load_models.jl | 20 ++++++++++---------- src/models/system.jl | 8 ++++---- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index db8d1f52f..771879d89 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -388,6 +388,8 @@ mutable struct ExpLoadParams Q_coeff::Float64 end +#Note: References are left in StaticLoadWrapper but transfered to ComponentArray. +#Can remove from the StaticLoadWrapper but would need access to the ElectricLoad components when calculating references. mutable struct StaticLoadWrapper bus::PSY.Bus V_ref::Float64 @@ -480,20 +482,10 @@ get_Q_power(wrapper::StaticLoadWrapper) = wrapper.Q_power get_Q_current(wrapper::StaticLoadWrapper) = wrapper.Q_current get_Q_impedance(wrapper::StaticLoadWrapper) = wrapper.Q_impedance -get_p_range(wrapper::StaticLoadWrapper) = wrapper.p_range get_exp_params(wrapper::StaticLoadWrapper) = wrapper.exp_params get_exp_names(wrapper::StaticLoadWrapper) = wrapper.exp_names get_bus_ix(wrapper::StaticLoadWrapper) = wrapper.bus_ix -set_V_ref!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.V_ref = val -set_θ_ref!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.θ_ref = val -set_P_power!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.P_power = val -set_P_current!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.P_current = val -set_P_impedance!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.P_impedance = val -set_Q_power!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.Q_power = val -set_Q_current!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.Q_current = val -set_Q_impedance!(wrapper::StaticLoadWrapper, val::Float64) = wrapper.Q_impedance = val - function set_connection_status(wrapper::Union{StaticWrapper, DynamicWrapper}, val::Int) if val == 0 CRC.@ignore_derivatives @debug "Generator $(PSY.get_name(wrapper)) status set to off" diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index 98bfbd7d9..df9d65a1d 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -67,7 +67,7 @@ function _convergence_check( ) else CRC.@ignore_derivatives @warn( - "Initialization non-linear solve convergence failed, initial conditions do not meet conditions for an stable equilibrium.\nAttempting again with reduced numeric tolerance and using another solver" + "Initialization non-linear solve convergence failed with a tolerance of $(tol) using solver $(solv), initial conditions do not meet conditions for an stable equilibrium.\nAttempting again with reduced numeric tolerance and using another solver" ) end return converged(sys_solve) diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index 16226f33a..d57b95dee 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -214,6 +214,17 @@ function _add_parameters(initial_parameters, wrapped_devices) Q_ref = PSY.get_reactive_power(device), ) end + elseif isa(wrapped_device, StaticLoadWrapper) + refs = ( + V_ref = get_V_ref(wrapped_device), + θ_ref = get_θ_ref(wrapped_device), + P_power = get_P_power(wrapped_device), + P_current = get_P_current(wrapped_device), + P_impedance = get_P_impedance(wrapped_device), + Q_power = get_Q_power(wrapped_device), + Q_current = get_Q_current(wrapped_device), + Q_impedance = get_Q_impedance(wrapped_device), + ) else refs = (;) end diff --git a/src/models/load_models.jl b/src/models/load_models.jl index 1fde8359d..e39b647c9 100644 --- a/src/models/load_models.jl +++ b/src/models/load_models.jl @@ -37,28 +37,28 @@ Ii_im = V_i * P0 * (V^(α - 2) / V0^α) - V_r * Q0 * (V^(β - 2)/ V0^β) """ function mdl_zip_load!( - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, current_i::AbstractArray{T}, wrapper::StaticLoadWrapper, ) where {T <: ACCEPTED_REAL_TYPES} - #V0_mag_inv = 1.0 / get_V_ref(wrapper) - V0_mag_inv = 1.0 / PSY.get_magnitude(PSY.get_bus(wrapper)) + V0_mag_inv = 1.0 / p[:refs][:V_ref] + #V0_mag_inv = 1.0 / PSY.get_magnitude(PSY.get_bus(wrapper)) V0_mag_sq_inv = V0_mag_inv^2 V_mag = sqrt(voltage_r^2 + voltage_i^2) V_mag_inv = 1.0 / V_mag V_mag_sq_inv = V_mag_inv^2 - # Load device parameters - P_power = get_P_power(wrapper) - P_current = get_P_current(wrapper) - P_impedance = get_P_impedance(wrapper) - Q_power = get_Q_power(wrapper) - Q_current = get_Q_current(wrapper) - Q_impedance = get_Q_impedance(wrapper) + # Load device references + P_power = p[:refs][:P_power] + P_current = p[:refs][:P_current] + P_impedance = p[:refs][:P_impedance] + Q_power = p[:refs][:Q_power] + Q_current = p[:refs][:Q_current] + Q_impedance = p[:refs][:Q_impedance] exp_params = get_exp_params(wrapper) Ir_exp = zero(T) Ii_exp = zero(T) diff --git a/src/models/system.jl b/src/models/system.jl index 3248fa741..b34880366 100644 --- a/src/models/system.jl +++ b/src/models/system.jl @@ -111,8 +111,8 @@ function system_residual!( for static_load in get_static_loads(inputs) bus_ix = get_bus_ix(static_load) - p_ix = get_p_range(static_load) - device_parameters = view(p, p_ix) + device_name = _get_wrapper_name(static_load) + device_parameters = p[device_name] device!( device_parameters, voltage_r[bus_ix], @@ -300,8 +300,8 @@ function system_mass_matrix!( for static_load in get_static_loads(inputs) bus_ix = get_bus_ix(static_load) - p_ix = get_p_range(static_load) - device_parameters = view(p, p_ix) + device_name = _get_wrapper_name(static_load) + device_parameters = p[device_name] device!( device_parameters, voltage_r[bus_ix], From 084977a8c11c9df08803c68ccc5aee45959debaf Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Fri, 31 May 2024 09:03:52 -0400 Subject: [PATCH 18/76] remove p_range formulation; pass dyn branch test (convert additional models) --- src/base/branch_wrapper.jl | 4 - src/base/device_wrapper.jl | 6 +- src/base/simulation_initialization.jl | 3 +- src/base/simulation_inputs.jl | 74 ++----- .../generator_components/init_avr.jl | 33 ++- .../generator_components/init_machine.jl | 28 ++- src/initialization/init_device.jl | 5 +- .../inverter_components/init_DCside.jl | 6 +- .../inverter_components/init_converter.jl | 2 +- .../inverter_components/init_filter.jl | 34 +-- .../init_frequency_estimator.jl | 24 ++- .../inverter_components/init_inner.jl | 43 ++-- .../inverter_components/init_outer.jl | 8 +- src/models/device.jl | 18 +- src/models/dynline_model.jl | 6 +- src/models/generator_models/avr_models.jl | 18 +- src/models/generator_models/machine_models.jl | 13 +- src/models/inverter_models/DCside_models.jl | 6 +- .../inverter_models/converter_models.jl | 2 +- src/models/inverter_models/filter_models.jl | 12 +- .../frequency_estimator_models.jl | 9 +- .../inverter_models/inner_control_models.jl | 25 ++- .../inverter_models/outer_control_models.jl | 20 +- src/models/system.jl | 8 +- src/utils/parameters.jl | 170 +++++++-------- test/Project.toml | 4 +- test/runtests.jl | 8 +- test/test_case_enzyme.jl | 193 ++++++++++++++++++ test/test_case_sensitivity.jl | 77 ++++++- test/test_sundials.jl | 2 +- 30 files changed, 565 insertions(+), 296 deletions(-) create mode 100644 test/test_case_enzyme.jl diff --git a/src/base/branch_wrapper.jl b/src/base/branch_wrapper.jl index 41f131831..9b96d733f 100644 --- a/src/base/branch_wrapper.jl +++ b/src/base/branch_wrapper.jl @@ -11,7 +11,6 @@ struct BranchWrapper bus_ix_to::Int ix_range::Vector{Int} ode_range::Vector{Int} - p_range::Vector{Int} global_index::Base.ImmutableDict{Symbol, Int} function BranchWrapper( branch::PSY.DynamicBranch, @@ -19,7 +18,6 @@ struct BranchWrapper bus_ix_to::Int, ix_range, ode_range, - p_range, sys_base_power, sys_base_freq, ) @@ -33,7 +31,6 @@ struct BranchWrapper bus_ix_to, ix_range, ode_range, - p_range, Base.ImmutableDict(Dict(branch_states .=> ix_range)...), ) end @@ -44,7 +41,6 @@ get_bus_ix_from(wrapper::BranchWrapper) = wrapper.bus_ix_from get_bus_ix_to(wrapper::BranchWrapper) = wrapper.bus_ix_to get_ix_range(wrapper::BranchWrapper) = wrapper.ix_range get_ode_ouput_range(wrapper::BranchWrapper) = wrapper.ode_range -get_p_range(wrapper::BranchWrapper) = wrapper.p_range get_global_index(wrapper::BranchWrapper) = wrapper.global_index get_branch(wrapper::BranchWrapper) = wrapper.branch diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index 771879d89..bbad10e16 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -112,7 +112,6 @@ function DynamicWrapper( bus_ix::Int, ix_range, ode_range, - p_range, inner_var_range, sys_base_power, sys_base_freq, @@ -357,7 +356,7 @@ function DynamicWrapper(device::T, bus_ix::Int) where {T <: PSY.Device} ) end -function StaticWrapper(device::T, bus_ix::Int, p_range) where {T <: PSY.Source} +function StaticWrapper(device::T, bus_ix::Int) where {T <: PSY.Source} bus = PSY.get_bus(device) return StaticWrapper{T, BUS_MAP[PSY.get_bustype(bus)]}( device, @@ -402,14 +401,12 @@ mutable struct StaticLoadWrapper Q_impedance::Float64 exp_params::Vector{ExpLoadParams} exp_names::Dict{String, Int} - p_range::Vector{Int} bus_ix::Int end function StaticLoadWrapper( bus::PSY.Bus, loads::Vector{PSY.ElectricLoad}, - p_range, bus_ix::Int, sys_base_power::Float64, ) @@ -465,7 +462,6 @@ function StaticLoadWrapper( Q_impedance, exp_params, dict_names, - p_range, bus_ix, ) end diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index 854fe4b03..9652ae27f 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -70,7 +70,8 @@ function initialize_dynamic_branches!( CRC.@ignore_derivatives @debug "Initializing Dynamic Branches" for br in get_dynamic_branches(inputs) CRC.@ignore_derivatives @debug "$(PSY.get_name(br)) - $(typeof(br))" - _parameters = @view parameters[get_p_range(br)] + wrapper_name = _get_wrapper_name(br) + _parameters = @view parameters[wrapper_name] _states = @view initial_guess[get_ix_range(br)] initialize_dynamic_device!(br, _parameters, _states) end diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index d57b95dee..c4472ba0f 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -8,7 +8,6 @@ mutable struct SimulationInputs variable_count::Int inner_vars_count::Int bus_count::Int - parameter_count::Int ode_range::UnitRange{Int} dyn_lines::Bool lookup::Dict{Int, Int} @@ -30,26 +29,24 @@ function SimulationInputs( n_buses = get_n_buses(sys) _, lookup = _get_ybus(sys) state_count = 2 * n_buses + 1 - parameter_count = 1 TimerOutputs.@timeit BUILD_TIMER "Wrap Branches" begin - wrapped_branches, state_count, parameter_count = - _wrap_dynamic_branches(sys, lookup, state_count, parameter_count) + wrapped_branches, state_count = + _wrap_dynamic_branches(sys, lookup, state_count) has_dyn_lines = !isempty(wrapped_branches) end n_branch_states = state_count - (2 * n_buses + 1) injection_start = state_count TimerOutputs.@timeit BUILD_TIMER "Wrap Dynamic Injectors" begin - wrapped_injectors, state_count, parameter_count = - _wrap_dynamic_injector_data(sys, lookup, state_count, parameter_count) + wrapped_injectors, state_count = + _wrap_dynamic_injector_data(sys, lookup, state_count) n_vars = state_count - 1 end TimerOutputs.@timeit BUILD_TIMER "Wrap Static Injectors" begin - wrapped_loads, parameter_count = _wrap_loads(sys, lookup, parameter_count) - wrapped_static_injectors, parameter_count = - _wrap_static_injectors(sys, lookup, parameter_count) - n_parameters = parameter_count - 1 + wrapped_loads = _wrap_loads(sys, lookup) + wrapped_static_injectors = + _wrap_static_injectors(sys, lookup) end global_vars = _make_global_variable_index(wrapped_injectors, wrapped_static_injectors, T) @@ -64,7 +61,6 @@ function SimulationInputs( Ybus, _ = _get_ybus(sys) total_shunts = _make_total_shunts(wrapped_branches, n_buses) TimerOutputs.@timeit BUILD_TIMER "Build initial parameters" begin - parameter_count = n_parameters initial_parameters = ComponentArrays.ComponentVector{Float64}() initial_parameters = _add_parameters(initial_parameters, wrapped_branches) initial_parameters = _add_parameters(initial_parameters, wrapped_injectors) @@ -97,7 +93,6 @@ function SimulationInputs( n_vars, inner_vars_count, n_buses, - n_parameters, injection_start:n_vars, has_dyn_lines, lookup, @@ -128,7 +123,6 @@ get_variable_count(inputs::SimulationInputs) = inputs.variable_count get_inner_vars_count(inputs::SimulationInputs) = inputs.inner_vars_count get_ode_ouput_range(inputs::SimulationInputs) = inputs.ode_range get_bus_count(inputs::SimulationInputs) = inputs.bus_count -get_parameter_count(inputs::SimulationInputs) = inputs.parameter_count get_bus_range(inputs::SimulationInputs) = 1:(2 * inputs.bus_count) #LEVEL TWO INPUTS @@ -182,7 +176,7 @@ function _get_wrapper_name(wrapped_device::StaticLoadWrapper) Symbol(PSY.get_name(PSY.get_bus(wrapped_device))) end function _get_wrapper_name(wrapped_device::BranchWrapper) - Symbol(PSY.get_name(PSY.get_branch(wrapped_device))) + Symbol(PSY.get_name(get_branch(wrapped_device))) end function _add_parameters(initial_parameters, wrapped_devices) @@ -239,25 +233,10 @@ function _add_parameters(initial_parameters, wrapped_devices) return initial_parameters end -function _get_n_params( - dynamic_device::PSY.DynamicInjection, - static_device::PSY.StaticInjection, -) - return length(ComponentArrays.ComponentVector(get_params(dynamic_device))) -end - -function _get_n_params( - dynamic_device::T, - static_device::PSY.StaticInjection, -) where {T <: Union{PSY.DynamicGenerator, PSY.DynamicInverter}} - return length(ComponentArrays.ComponentVector(get_params(dynamic_device))) -end - function _wrap_dynamic_injector_data( sys::PSY.System, lookup, state_count::Int, - parameter_count::Int, ) #injection_start injector_data = get_injectors_with_dynamics(sys) isempty(injector_data) && error("System doesn't contain any DynamicInjection devices") @@ -272,15 +251,13 @@ function _wrap_dynamic_injector_data( @debug "Wrapping $(PSY.get_name(device))" dynamic_device = PSY.get_dynamic_injector(device) n_states = PSY.get_n_states(dynamic_device) - n_params = _get_n_params(dynamic_device, device) n_inner_vars = get_inner_vars_count(dynamic_device) ix_range = range(state_count; length = n_states) ode_range = range(injection_count; length = n_states) - p_range = range(parameter_count; length = n_params) bus_n = PSY.get_number(PSY.get_bus(device)) bus_ix = lookup[bus_n] inner_vars_range = range(inner_vars_count; length = n_inner_vars) - @debug "ix_range=$ix_range ode_range=$ode_range inner_vars_range= $inner_vars_range p_range=$p_range" + @debug "ix_range=$ix_range ode_range=$ode_range inner_vars_range= $inner_vars_range" dynamic_device = PSY.get_dynamic_injector(device) @assert dynamic_device !== nothing #TODO - add check if name of device is unique? @@ -290,17 +267,15 @@ function _wrap_dynamic_injector_data( bus_ix, ix_range, ode_range, - p_range, inner_vars_range, sys_base_power, sys_base_freq, ) injection_count += n_states state_count += n_states - parameter_count += n_params inner_vars_count += n_inner_vars end - return wrapped_injector, state_count, parameter_count + return wrapped_injector, state_count end function get_constant_lags(sys::PSY.System) @@ -318,7 +293,6 @@ function _wrap_dynamic_branches( sys::PSY.System, lookup::Dict{Int, Int}, state_count::Int, - parameter_count::Int, ) sys_base_power = PSY.get_base_power(sys) sys_base_freq = PSY.get_frequency(sys) @@ -336,33 +310,28 @@ function _wrap_dynamic_branches( bus_ix_to = lookup[to_bus_number] ix_range = range(state_count; length = n_states) ode_range = range(branches_count; length = n_states) - n_params = length(get_params(br)) - p_range = range(parameter_count; length = n_params) - @debug "ix_range=$ix_range ode_range=$ode_range p_range=$ode_range" + @debug "ix_range=$ix_range ode_range=$ode_range" wrapped_branches[ix] = BranchWrapper( br, bus_ix_from, bus_ix_to, ix_range, ode_range, - p_range, sys_base_power, sys_base_freq, ) branches_count += n_states state_count += n_states - parameter_count += n_params end else @debug("System doesn't contain Dynamic Branches") end - return wrapped_branches, state_count, parameter_count + return wrapped_branches, state_count end function _wrap_static_injectors( sys::PSY.System, lookup::Dict{Int, Int}, - parameter_count::Int, ) static_injection_data = get_injection_without_dynamics(sys) container = Vector{StaticWrapper}(undef, length(static_injection_data)) @@ -372,15 +341,12 @@ function _wrap_static_injectors( end bus_n = PSY.get_number(PSY.get_bus(ld)) bus_ix = lookup[bus_n] - n_params = length(get_params(ld)) - p_range = range(parameter_count; length = n_params) - container[ix] = StaticWrapper(ld, bus_ix, p_range) - parameter_count += n_params + container[ix] = StaticWrapper(ld, bus_ix) end - return container, parameter_count + return container end -function _wrap_loads(sys::PSY.System, lookup::Dict{Int, Int}, parameter_count::Int) +function _wrap_loads(sys::PSY.System, lookup::Dict{Int, Int}) sys_base_power = PSY.get_base_power(sys) # This needs to change if we implement dynamic load models static_loads = @@ -394,25 +360,21 @@ function _wrap_loads(sys::PSY.System, lookup::Dict{Int, Int}, parameter_count::I # Optimize this dictionary push push!(get!(map_bus_load, bus, PSY.ElectricLoad[]), ld) end - return _construct_load_wrapper(lookup, map_bus_load, sys_base_power, parameter_count) + return _construct_load_wrapper(lookup, map_bus_load, sys_base_power) end function _construct_load_wrapper( lookup::Dict{Int, Int}, map_bus_load::Dict{PSY.Bus, Vector{PSY.ElectricLoad}}, sys_base_power, - parameter_count, ) container = Vector{StaticLoadWrapper}(undef, length(map_bus_load)) for (ix, (bus, loads)) in enumerate(map_bus_load) bus_n = PSY.get_number(bus) bus_ix = lookup[bus_n] - n_params = 0 - p_range = range(parameter_count; length = n_params) - container[ix] = StaticLoadWrapper(bus, loads, p_range, bus_ix, sys_base_power) - parameter_count += n_params + container[ix] = StaticLoadWrapper(bus, loads, bus_ix, sys_base_power) end - return container, parameter_count + return container end function _get_ybus(sys::PSY.System) diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index c7732ae9b..04ffedfc9 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -40,7 +40,7 @@ end function initialize_avr!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRTypeI, TG, P}}, inner_vars::AbstractVector, @@ -52,34 +52,45 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AVRTypeI) - internal_params = @view device_parameters[local_ix_params] - Ka, Ke, Kf, _, _, Tf, _, Ae, Be = internal_params - #Obtain saturated Vf - Se_Vf = Ae * exp(Be * abs(Vf0)) + params = p[:params][:AVR] #States of AVRTypeI are Vf, Vr1, Vr2, Vm #To solve V_ref, Vr1, Vr2 - function f!(out, x) + function f!(out, x, params) V_ref = x[1] Vr1 = x[2] Vr2 = x[3] + Ka = params[:Ka] + Ke = params[:Ke] + Kf = params[:Kf] + Tf = params[:Tf] + Ae = params[:Ae] + Be = params[:Be] + #Obtain saturated Vf + Se_Vf = Ae * exp(Be * abs(Vf0)) + out[1] = Vf0 * (Ke + Se_Vf) - Vr1 #16.12c out[2] = Ka * (V_ref - Vm - Vr2 - (Kf / Tf) * Vf0) - Vr1 #16.12a out[3] = (Kf / Tf) * Vf0 + Vr2 #16.12b end x0 = [1.0, Vf0, Vf0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) CRC.@ignore_derivatives @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - set_V_ref(dynamic_device, sol_x0[1]) + set_V_ref!(p, sol_x0[1]) #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeI) avr_states = @view device_states[avr_ix] diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index 8b5b32068..65341c844 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -85,7 +85,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{PSY.OneDOneQMachine, S, A, TG, P}}, inner_vars::AbstractVector, @@ -102,9 +102,9 @@ function initialize_mach_shaft!( I = conj(S0 / V) #Machine Data - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.OneDOneQMachine) - internal_params = @view device_parameters[local_ix_params] - R, Xd, Xq, Xd_p, Xq_p, _, _ = internal_params + params = p[:params][:Machine] + R = params[:R] + Xq = params[:Xq] #States of OneDOneQMachine are [1] eq_p and [2] ed_p δ0 = angle(V + (R + Xq * 1im) * I) @@ -112,13 +112,19 @@ function initialize_mach_shaft!( τm0 = real(V * conj(I)) @assert isapprox(τm0, P0; atol = STRICT_NLSOLVE_F_TOLERANCE) τm0, P0 #To solve: δ, τm, Vf0, eq_p, ed_p - function f!(out, x) + function f!(out, x, params) δ = x[1] τm = x[2] Vf0 = x[3] eq_p = x[4] ed_p = x[5] + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + V_dq = ri_dq(δ) * [V_R; V_I] i_d = (1.0 / (R^2 + Xd_p * Xq_p)) * (Xq_p * (eq_p - V_dq[2]) + R * (ed_p - V_dq[1])) #15.32 i_q = @@ -132,13 +138,19 @@ function initialize_mach_shaft!( end V_dq0 = ri_dq(δ0) * [V_R; V_I] x0 = [δ0, τm0, 1.0, V_dq0[2], V_dq0[1]] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) CRC.@ignore_derivatives @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages inner_vars[VR_gen_var] = V_R inner_vars[VI_gen_var] = V_I diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index 02bb8b33b..2771c3950 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -174,7 +174,7 @@ function initialize_dynamic_device!( end function initialize_dynamic_device!(branch::BranchWrapper, - parameters::AbstractVector, + p::AbstractVector, device_states::AbstractVector) #PowerFlow Data arc = PSY.get_arc(branch) @@ -186,7 +186,8 @@ function initialize_dynamic_device!(branch::BranchWrapper, V_I_from = Vm_from * sin(θ_from) V_R_to = Vm_to * cos(θ_to) V_I_to = Vm_to * sin(θ_to) - R, X = parameters + R = p[:params][:r] + X = p[:params][:x] Zmag_sq = R^2 + X^2 #Compute Current I_R = R * (V_R_from - V_R_to) / Zmag_sq + X * (V_I_from - V_I_to) / Zmag_sq diff --git a/src/initialization/inverter_components/init_DCside.jl b/src/initialization/inverter_components/init_DCside.jl index bbf8c6784..5a2c15698 100644 --- a/src/initialization/inverter_components/init_DCside.jl +++ b/src/initialization/inverter_components/init_DCside.jl @@ -1,6 +1,6 @@ function initialize_DCside!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, IC, PSY.FixedDCSource, P, F, L}, @@ -14,9 +14,7 @@ function initialize_DCside!( F <: PSY.Filter, L <: Union{Nothing, PSY.InverterLimiter}, } - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.FixedDCSource) - internal_params = @view device_parameters[local_ix_params] #Update inner_vars - inner_vars[Vdc_var] = internal_params[1] + inner_vars[Vdc_var] = p[:params][:DCSource][:voltage] return end diff --git a/src/initialization/inverter_components/init_converter.jl b/src/initialization/inverter_components/init_converter.jl index c9a20a3e3..085a6eba1 100644 --- a/src/initialization/inverter_components/init_converter.jl +++ b/src/initialization/inverter_components/init_converter.jl @@ -1,6 +1,6 @@ function initialize_converter!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{PSY.AverageConverter, O, IC, DC, P, F, L}, diff --git a/src/initialization/inverter_components/init_filter.jl b/src/initialization/inverter_components/init_filter.jl index 31c642bb8..637bc0472 100644 --- a/src/initialization/inverter_components/init_filter.jl +++ b/src/initialization/inverter_components/init_filter.jl @@ -25,18 +25,8 @@ function initialize_filter!( Ir_filter = real(I) Ii_filter = imag(I) - #Get Parameters - params = p[:params][:Filter] - lf = params[:lf] - rf = params[:rf] - cf = params[:cf] - lg = params[:lg] - rg = params[:rg] - #Set parameters - ω_sys = get_ω_ref(dynamic_device) - #To solve Vr_cnv, Vi_cnv, Ir_cnv, Ii_cnv, Vr_filter, Vi_filter - function f!(out, x) + function f!(out, x, p) Vr_cnv = x[1] Vi_cnv = x[2] Ir_cnv = x[3] @@ -44,6 +34,16 @@ function initialize_filter!( Vr_filter = x[5] Vi_filter = x[6] + #Get Parameters + params = p[:params][:Filter] + lf = params[:lf] + rf = params[:rf] + cf = params[:cf] + lg = params[:lg] + rg = params[:rg] + #Set parameters + ω_sys = p[:refs][:ω_ref] + #𝜕Ir_cnv/𝜕t out[1] = Vr_cnv - Vr_filter - rf * Ir_cnv + ω_sys * lf * Ii_cnv #𝜕Ii_cnv/𝜕t @@ -58,13 +58,19 @@ function initialize_filter!( out[6] = Vi_filter - V_I - rg * Ii_filter - ω_sys * lg * Ir_filter end x0 = [V_R, V_I, Ir_filter, Ii_filter, V_R, V_I] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem(f!, x0, p) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) CRC.@ignore_derivatives @warn( "Initialization in Filter failed $(PSY.get_name(static))" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages inner_vars[Vr_inv_var] = V_R inner_vars[Vi_inv_var] = V_I diff --git a/src/initialization/inverter_components/init_frequency_estimator.jl b/src/initialization/inverter_components/init_frequency_estimator.jl index 17f3dfa23..a83f17d7f 100644 --- a/src/initialization/inverter_components/init_frequency_estimator.jl +++ b/src/initialization/inverter_components/init_frequency_estimator.jl @@ -1,6 +1,6 @@ function initialize_frequency_estimator!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicInverter{C, O, IC, DC, PSY.KauraPLL, F, L}}, inner_vars::AbstractVector, @@ -16,10 +16,8 @@ function initialize_frequency_estimator!( Vi_filter = inner_vars[Vi_filter_var] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.KauraPLL) - internal_params = @view device_parameters[local_ix_params] - _, kp_pll, ki_pll = internal_params - ω_ref = get_ω_ref(dynamic_device) + params = p[:params][:FrequencyEstimator] + ω_ref = p[:refs][:ω_ref] #Get initial guess θ0_pll = atan(Vi_filter, Vr_filter) @@ -27,11 +25,13 @@ function initialize_frequency_estimator!( Vpll_q0 = 0.0 ϵ_pll0 = 0.0 - function f!(out, x) + function f!(out, x, params) vpll_d = x[1] vpll_q = x[2] ϵ_pll = x[3] θ_pll = x[4] + kp_pll = params[:kp_pll] + ki_pll = params[:ki_pll] V_dq_pll = ri_dq(θ_pll + pi / 2) * [Vr_filter; Vi_filter] @@ -43,11 +43,17 @@ function initialize_frequency_estimator!( end x0 = [Vpll_d0, Vpll_q0, ϵ_pll0, θ0_pll] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) CRC.@ignore_derivatives @warn("Initialization in PLL failed") else - sol_x0 = sol.zero + sol_x0 = sol.u #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.KauraPLL) diff --git a/src/initialization/inverter_components/init_inner.jl b/src/initialization/inverter_components/init_inner.jl index 8449e1b0c..807c3a464 100644 --- a/src/initialization/inverter_components/init_inner.jl +++ b/src/initialization/inverter_components/init_inner.jl @@ -1,6 +1,6 @@ function initialize_inner!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, PSY.VoltageModeControl, DC, P, PSY.LCLFilter, L}, @@ -24,7 +24,7 @@ function initialize_inner!( Vi_filter = device_states[external_ix[6]] #Obtain inner variables for component - ω_oc = get_ω_ref(dynamic_device) + ω_oc = p[:refs][:ω_ref] θ0_oc = inner_vars[θ_oc_var] Vdc = inner_vars[Vdc_var] @@ -33,17 +33,10 @@ function initialize_inner!( Vi_cnv0 = inner_vars[Vi_cnv_var] #Get Voltage Controller parameters - filter = PSY.get_filter(dynamic_device) - filter_ix_params = get_local_parameter_ix(dynamic_device, typeof(filter)) - filter_params = @view device_parameters[filter_ix_params] - cf = filter_params[3] - lf = filter_params[1] - - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.VoltageModeControl) - internal_params = @view device_parameters[local_ix_params] - kpv, kiv, kffv, rv, lv, kpc, kic, kffi, ωad, kad = internal_params - - function f!(out, x) + params = p[:params][:InnerControl] + cf = p[:params][:Filter][:cf] + lf = p[:params][:Filter][:lf] + function f!(out, x, params) θ_oc = x[1] v_refr = x[2] ξ_d = x[3] @@ -53,6 +46,16 @@ function initialize_inner!( ϕ_d = x[7] ϕ_q = x[8] + kpv = params[:kpv] + kiv = params[:kiv] + kffv = params[:kffv] + rv = params[:rv] + lv = params[:lv] + kpc = params[:kpc] + kic = params[:kic] + kffi = params[:kffi] + kad = params[:kad] + #Reference Frame Transformations I_dq_filter = ri_dq(θ_oc + pi / 2) * [Ir_filter; Ii_filter] I_dq_cnv = ri_dq(θ_oc + pi / 2) * [Ir_cnv; Ii_cnv] @@ -97,11 +100,17 @@ function initialize_inner!( out[8] = Vq_cnv_ref - V_dq_cnv0[q] end x0 = [θ0_oc, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) CRC.@ignore_derivatives @warn("Initialization in Inner Control failed") else - sol_x0 = sol.zero + sol_x0 = sol.u #Update angle: inner_vars[θ_oc_var] = sol_x0[1] outer_ix = get_local_state_ix(dynamic_device, O) @@ -109,7 +118,7 @@ function initialize_inner!( #Assumes that angle is in second position outer_states[1] = sol_x0[1] inner_vars[θ_oc_var] = sol_x0[1] - set_V_ref(dynamic_device, sol_x0[2]) + set_V_ref!(p, sol_x0[2]) PSY.set_V_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), sol_x0[2], diff --git a/src/initialization/inverter_components/init_outer.jl b/src/initialization/inverter_components/init_outer.jl index 56ff29cc7..db4a06806 100644 --- a/src/initialization/inverter_components/init_outer.jl +++ b/src/initialization/inverter_components/init_outer.jl @@ -1,6 +1,6 @@ function initialize_outer!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -37,7 +37,7 @@ function initialize_outer!( Vi_cnv = inner_vars[Vi_cnv_var] θ0_oc = atan(Vi_cnv, Vr_cnv) - ω_ref = get_ω_ref(dynamic_device) + ω_ref = p[:refs][:ω_ref] #Obtain additional expressions p_elec_out = Ir_filter * Vr_filter + Ii_filter * Vi_filter q_elec_out = -Ii_filter * Vr_filter + Ir_filter * Vi_filter @@ -57,13 +57,13 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc inner_vars[ω_oc_var] = ω_ref - set_P_ref(dynamic_device, p_elec_out) + set_P_ref!(p, p_elec_out) PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) #Update Q_ref. Initialization assumes q_ref = q_elec_out of PF solution - set_Q_ref(dynamic_device, q_elec_out) + set_Q_ref!(p, q_elec_out) return end diff --git a/src/models/device.jl b/src/models/device.jl index c7167dfcd..3d4a1cbad 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -184,7 +184,7 @@ end function device!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -208,14 +208,14 @@ function device!( inner_vars[Vi_inv_var] = voltage_i #Update V_ref - V_ref = get_V_ref(dynamic_device) + V_ref = p[:refs][:V_ref] inner_vars[V_oc_var] = V_ref #Update current inner_vars _update_inner_vars!( device_states, output_ode, - device_parameters, + p, sys_ω, inner_vars, dynamic_device, @@ -225,7 +225,7 @@ function device!( mdl_DCside_ode!( device_states, output_ode, - device_parameters, + p, sys_ω, inner_vars, dynamic_device, @@ -237,7 +237,7 @@ function device!( mdl_freq_estimator_ode!( device_states, output_ode, - device_parameters, + p, inner_vars, sys_ω, dynamic_device, @@ -249,7 +249,7 @@ function device!( mdl_outer_ode!( device_states, output_ode, - device_parameters, + p, inner_vars, sys_ω, dynamic_device, @@ -261,7 +261,7 @@ function device!( mdl_inner_ode!( device_states, output_ode, - device_parameters, + p, inner_vars, dynamic_device, h, @@ -272,7 +272,7 @@ function device!( mdl_converter_ode!( device_states, output_ode, - device_parameters, + p, inner_vars, dynamic_device, h, @@ -283,7 +283,7 @@ function device!( mdl_filter_ode!( device_states, output_ode, - device_parameters, + p, current_r, current_i, inner_vars, diff --git a/src/models/dynline_model.jl b/src/models/dynline_model.jl index 4270cc687..f581406bb 100644 --- a/src/models/dynline_model.jl +++ b/src/models/dynline_model.jl @@ -1,7 +1,7 @@ function mdl_branch_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r_from::T, voltage_i_from::T, voltage_r_to::T, @@ -12,7 +12,9 @@ function mdl_branch_ode!( current_i_to::AbstractArray{T}, branch::BranchWrapper, ) where {T <: ACCEPTED_REAL_TYPES} - R, L = device_parameters + R = p[:params][:r] + L = p[:params][:x] + ω_b = get_system_base_frequency(branch) * 2 * π Il_r = device_states[1] diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index f83a4c9c4..5125be413 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -116,15 +116,14 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRTypeI, TG, P}}, h, t, ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} - #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = p[:refs][:V_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeI) @@ -141,9 +140,16 @@ function mdl_avr_ode!( Vs = inner_vars[V_pss_var] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AVRTypeI) - internal_params = @view device_parameters[local_ix_params] - Ka, Ke, Kf, Ta, Te, Tf, Tr, Ae, Be = internal_params + params = p[:params][:AVR] + Ka = params[:Ka] + Ke = params[:Ke] + Kf = params[:Kf] + Ta = params[:Ta] + Te = params[:Te] + Tf = params[:Tf] + Tr = params[:Tr] + Ae = params[:Ae] + Be = params[:Be] #Compute auxiliary parameters Se_Vf = Ae * exp(Be * abs(Vf)) #16.13 diff --git a/src/models/generator_models/machine_models.jl b/src/models/generator_models/machine_models.jl index 57a56f4b7..ecc21c520 100644 --- a/src/models/generator_models/machine_models.jl +++ b/src/models/generator_models/machine_models.jl @@ -65,7 +65,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -93,9 +93,14 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.OneDOneQMachine) - internal_params = @view device_parameters[local_ix_params] - R, Xd, Xq, Xd_p, Xq_p, Td0_p, Tq0_p = internal_params + params = p[:params][:Machine] + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Td0_p = params[:Td0_p] + Tq0_p = params[:Tq0_p] basepower = PSY.get_base_power(dynamic_device) diff --git a/src/models/inverter_models/DCside_models.jl b/src/models/inverter_models/DCside_models.jl index 60c89f42c..ac0b85088 100644 --- a/src/models/inverter_models/DCside_models.jl +++ b/src/models/inverter_models/DCside_models.jl @@ -9,7 +9,7 @@ end function mdl_DCside_ode!( ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ @@ -25,8 +25,6 @@ function mdl_DCside_ode!( F <: PSY.Filter, L <: Union{Nothing, PSY.InverterLimiter}, } - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.FixedDCSource) - internal_params = @view device_parameters[local_ix_params] #Update inner_vars - inner_vars[Vdc_var] = internal_params[1] + inner_vars[Vdc_var] = p[:params][:DCSource][:voltage] end diff --git a/src/models/inverter_models/converter_models.jl b/src/models/inverter_models/converter_models.jl index 40bc4aa9f..cd2303f57 100644 --- a/src/models/inverter_models/converter_models.jl +++ b/src/models/inverter_models/converter_models.jl @@ -9,7 +9,7 @@ end function mdl_converter_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{PSY.AverageConverter, O, IC, DC, P, F, L}, diff --git a/src/models/inverter_models/filter_models.jl b/src/models/inverter_models/filter_models.jl index 395a3e8ae..99a503822 100644 --- a/src/models/inverter_models/filter_models.jl +++ b/src/models/inverter_models/filter_models.jl @@ -35,7 +35,7 @@ end function mdl_filter_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -64,11 +64,11 @@ function mdl_filter_ode!( #Get parameters f0 = get_system_base_frequency(dynamic_device) ωb = 2 * pi * f0 - lf = device_parameters[:Filter][:lf] - rf = device_parameters[:Filter][:rf] - cf = device_parameters[:Filter][:cf] - lg = device_parameters[:Filter][:lg] - rg = device_parameters[:Filter][:rg] + lf = p[:params][:Filter][:lf] + rf = p[:params][:Filter][:rf] + cf = p[:params][:Filter][:cf] + lg = p[:params][:Filter][:lg] + rg = p[:params][:Filter][:rg] basepower = PSY.get_base_power(dynamic_device) sys_Sbase = get_system_base_power(dynamic_device) diff --git a/src/models/inverter_models/frequency_estimator_models.jl b/src/models/inverter_models/frequency_estimator_models.jl index 0cc30a2a3..61996f8a7 100644 --- a/src/models/inverter_models/frequency_estimator_models.jl +++ b/src/models/inverter_models/frequency_estimator_models.jl @@ -9,7 +9,7 @@ end function mdl_freq_estimator_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicInverter{C, O, IC, DC, PSY.KauraPLL, F, L}}, @@ -30,9 +30,10 @@ function mdl_freq_estimator_ode!( Vi_filter = device_states[external_ix[2]] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.KauraPLL) - internal_params = @view device_parameters[local_ix_params] - ω_lp, kp_pll, ki_pll = internal_params + params = p[:params][:FrequencyEstimator] + ω_lp = params[:ω_lp] + kp_pll = params[:kp_pll] + ki_pll = params[:ki_pll] f0 = get_system_base_frequency(dynamic_device) ωb = 2.0 * pi * f0 diff --git a/src/models/inverter_models/inner_control_models.jl b/src/models/inverter_models/inner_control_models.jl index ccdf650cc..7f88c2c2d 100644 --- a/src/models/inverter_models/inner_control_models.jl +++ b/src/models/inverter_models/inner_control_models.jl @@ -168,7 +168,7 @@ end function mdl_inner_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, PSY.VoltageModeControl, DC, P, PSY.LCLFilter, L}, @@ -198,16 +198,21 @@ function mdl_inner_ode!( v_refr = inner_vars[V_oc_var] Vdc = inner_vars[Vdc_var] + cf = p[:params][:Filter][:cf] + lf = p[:params][:Filter][:lf] + #Get Voltage Controller parameters - filter = PSY.get_filter(dynamic_device) - filter_ix_params = get_local_parameter_ix(dynamic_device, typeof(filter)) - filter_params = @view device_parameters[filter_ix_params] - cf = filter_params[3] - lf = filter_params[1] - - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.VoltageModeControl) - internal_params = @view device_parameters[local_ix_params] - kpv, kiv, kffv, rv, lv, kpc, kic, kffi, ωad, kad = internal_params + params = p[:params][:InnerControl] + kpv = params[:kpv] + kiv = params[:kiv] + kffv = params[:kffv] + rv = params[:rv] + lv = params[:lv] + kpc = params[:kpc] + kic = params[:kic] + kffi = params[:kffi] + ωad = params[:ωad] + kad = params[:kad] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.VoltageModeControl) diff --git a/src/models/inverter_models/outer_control_models.jl b/src/models/inverter_models/outer_control_models.jl index 05b9789a8..be5285621 100644 --- a/src/models/inverter_models/outer_control_models.jl +++ b/src/models/inverter_models/outer_control_models.jl @@ -636,7 +636,7 @@ end function mdl_outer_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -674,16 +674,16 @@ function mdl_outer_ode!( #Obtain inner variables for component ω_pll = inner_vars[ω_freq_estimator_var] - Ta = device_parameters[:OuterControl][:ActivePowerControl][:Ta] - kd = device_parameters[:OuterControl][:ActivePowerControl][:kd] - kω = device_parameters[:OuterControl][:ActivePowerControl][:kω] - kq = device_parameters[:OuterControl][:ReactivePowerControl][:kq] - ωf = device_parameters[:OuterControl][:ReactivePowerControl][:ωf] + Ta = p[:params][:OuterControl][:ActivePowerControl][:Ta] + kd = p[:params][:OuterControl][:ActivePowerControl][:kd] + kω = p[:params][:OuterControl][:ActivePowerControl][:kω] + kq = p[:params][:OuterControl][:ReactivePowerControl][:kq] + ωf = p[:params][:OuterControl][:ReactivePowerControl][:ωf] - q_ref = get_Q_ref(dynamic_device) - V_ref = get_V_ref(dynamic_device) - ω_ref = get_ω_ref(dynamic_device) - p_ref = get_P_ref(dynamic_device) + q_ref = p[:refs][:Q_ref] + V_ref = p[:refs][:V_ref] + ω_ref = p[:refs][:ω_ref] + p_ref = p[:refs][:P_ref] f0 = get_system_base_frequency(dynamic_device) ωb = 2 * pi * f0 #Rated angular frequency diff --git a/src/models/system.jl b/src/models/system.jl index b34880366..db2216f2e 100644 --- a/src/models/system.jl +++ b/src/models/system.jl @@ -149,8 +149,8 @@ function system_residual!( dyn_branch = get_branch(dynamic_branch) # DynamicBranch branch = PSY.get_branch(dyn_branch) # Line or Transformer2W ix_range = get_ix_range(dynamic_branch) - p_ix = get_p_range(dynamic_branch) - branch_parameters = view(p, p_ix) + branch_name = _get_wrapper_name(dynamic_branch) + branch_parameters = @view p[branch_name] branch_output_ode = @view branches_ode[get_ode_ouput_range(dynamic_branch)] branch_states = @view x[ix_range] bus_ix_from = get_bus_ix_from(dynamic_branch) @@ -338,8 +338,8 @@ function system_mass_matrix!( dyn_branch = get_branch(dynamic_branch) # DynamicBranch branch = PSY.get_branch(dyn_branch) # Line or Transformer2W ix_range = get_ix_range(dynamic_branch) - p_ix = get_p_range(dynamic_branch) - branch_parameters = view(p, p_ix) + branch_name = _get_wrapper_name(dynamic_branch) + branch_parameters = @view p[branch_name] branch_output_ode = @view branches_ode[get_ode_ouput_range(dynamic_branch)] branch_states = @view x[ix_range] bus_ix_from = get_bus_ix_from(dynamic_branch) diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index 96abd6642..a001c1fbe 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -203,33 +203,33 @@ get_params_metadata(::PSY.ReactiveRenewableControllerAB) = ParamsMetadata(:dbd_pnts1_ReactivePowerControl, false, false, false, false), ParamsMetadata(:dbd_pnts2_ReactivePowerControl, false, false, false, false), =# -#= #INNER CONTROL -get_params(x::PSY.VoltageModeControl) = [ - PSY.get_kpv(x), - PSY.get_kiv(x), - PSY.get_kffv(x), - PSY.get_rv(x), - PSY.get_lv(x), - PSY.get_kpc(x), - PSY.get_kic(x), - PSY.get_kffi(x), - PSY.get_ωad(x), - PSY.get_kad(x), -] -get_params_metadata(::PSY.VoltageModeControl) = [ - ParamsMetadata(:kpv_InnerControl, false, false, true, false), - ParamsMetadata(:kiv_InnerControl, false, false, true, false), - ParamsMetadata(:kffv_InnerControl, false, false, true, false), - ParamsMetadata(:rv_InnerControl, false, false, true, false), - ParamsMetadata(:lv_InnerControl, false, false, true, false), - ParamsMetadata(:kpc_InnerControl, false, false, true, false), - ParamsMetadata(:kic_InnerControl, false, false, true, false), - ParamsMetadata(:kffi_InnerControl, false, false, true, false), - ParamsMetadata(:ωad_InnerControl, false, false, false, false), - ParamsMetadata(:kad_InnerControl, false, false, true, false), -] +get_params(x::PSY.VoltageModeControl) = ( + kpv = PSY.get_kpv(x), + kiv = PSY.get_kiv(x), + kffv = PSY.get_kffv(x), + rv = PSY.get_rv(x), + lv = PSY.get_lv(x), + kpc = PSY.get_kpc(x), + kic = PSY.get_kic(x), + kffi = PSY.get_kffi(x), + ωad = PSY.get_ωad(x), + kad = PSY.get_kad(x), +) +get_params_metadata(::PSY.VoltageModeControl) = ( + kpv = ParamsMetadata(false, false, true), + kiv = ParamsMetadata(false, false, true), + kffv = ParamsMetadata(false, false, true), + rv = ParamsMetadata(false, false, true), + lv = ParamsMetadata(false, false, true), + kpc = ParamsMetadata(false, false, true), + kic = ParamsMetadata(false, false, true), + kffi = ParamsMetadata(false, false, true), + ωad = ParamsMetadata(false, false, false), + kad = ParamsMetadata(false, false, true), +) +#= get_params(x::PSY.RECurrentControlB) = [ PSY.get_Vdip_lim(x)[1], PSY.get_Vdip_lim(x)[2], @@ -260,27 +260,31 @@ get_params_metadata(::PSY.RECurrentControlB) = [ ParamsMetadata(:T_iq_InnerControl, true, false, false, false), ParamsMetadata(:I_max_InnerControl, false, false, false, false), ] - + =# #DC SOURCE -get_params(x::PSY.FixedDCSource) = [PSY.get_voltage(x)] -get_params_metadata(::PSY.FixedDCSource) = - [ParamsMetadata(:voltage_DCSource, false, false, false, false)] +get_params(x::PSY.FixedDCSource) = (voltage = PSY.get_voltage(x),) +get_params_metadata(::PSY.FixedDCSource) = (voltage = ParamMetadata(false, false, false),) #FREQ ESTIMATOR -get_params(x::PSY.KauraPLL) = [PSY.get_ω_lp(x), PSY.get_kp_pll(x), PSY.get_ki_pll(x)] -get_params_metadata(::PSY.KauraPLL) = [ - ParamsMetadata(:ω_lp_FrequencyEstimator, false, false, false, false) - ParamsMetadata(:kp_pll_FrequencyEstimator, false, false, true, false) - ParamsMetadata(:ki_pll_FrequencyEstimator, false, false, true, false) -] -get_params(x::PSY.FixedFrequency) = [PSY.get_frequency(x)] +get_params(x::PSY.KauraPLL) = ( + ω_lp = PSY.get_ω_lp(x), + kp_pll = PSY.get_kp_pll(x), + ki_pll = PSY.get_ki_pll(x), +) +get_params_metadata(::PSY.KauraPLL) = ( + ω_lp = ParamsMetadata(false, false, false), + kp_pll = ParamsMetadata(false, false, true), + ki_pll = ParamsMetadata(false, false, true), +) +#= get_params(x::PSY.FixedFrequency) = [PSY.get_frequency(x)] get_params_metadata(::PSY.FixedFrequency) = [ParamsMetadata(:frequency_FrequencyEstimator, false, false, false, false)] - + =# #CONVERTER -get_params(::PSY.AverageConverter) = Float64[] -get_params_metadata(::PSY.AverageConverter) = ParamsMetadata[] -get_params(x::PSY.RenewableEnergyConverterTypeA) = [ +get_params(::PSY.AverageConverter) = (;) +get_params_metadata(::PSY.AverageConverter) = (;) + +#= get_params(x::PSY.RenewableEnergyConverterTypeA) = [ PSY.get_T_g(x), PSY.get_Rrpwr(x), PSY.get_Brkpt(x), @@ -317,8 +321,8 @@ get_params_metadata(::PSY.RenewableEnergyConverterTypeA) = [ ParamsMetadata(:Q_ref_Converter, false, false, false, false) ParamsMetadata(:R_source_Converter, false, false, false, false) ParamsMetadata(:X_source_Converter, false, false, false, false) -] =# - +] + =# ########### GENERATORS ############# function get_params(g::PSY.DynamicGenerator) return ( @@ -347,24 +351,25 @@ get_params_metadata(::PSY.BaseMachine) = ( Xd_p = ParamsMetadata(false, false, true), eq_p = ParamsMetadata(false, false, true), ) -#= get_params(x::PSY.OneDOneQMachine) = [ - PSY.get_R(x), - PSY.get_Xd(x), - PSY.get_Xq(x), - PSY.get_Xd_p(x), - PSY.get_Xq_p(x), - PSY.get_Td0_p(x), - PSY.get_Tq0_p(x), -] -get_params_metadata(::PSY.OneDOneQMachine) = [ - ParamsMetadata(:R_Machine, false, false, true, false), - ParamsMetadata(:Xd_Machine, false, false, true, false), - ParamsMetadata(:Xq_Machine, false, false, true, false), - ParamsMetadata(:Xd_p_Machine, false, false, true, false), - ParamsMetadata(:Xq_p_Machine, false, false, true, false), - ParamsMetadata(:Td0_p_Machine, false, false, false, false), - ParamsMetadata(:Tq0_p_Machine, false, false, false, false), -] +get_params(x::PSY.OneDOneQMachine) = ( + R = PSY.get_R(x), + Xd = PSY.get_Xd(x), + Xq = PSY.get_Xq(x), + Xd_p = PSY.get_Xd_p(x), + Xq_p = PSY.get_Xq_p(x), + Td0_p = PSY.get_Td0_p(x), + Tq0_p = PSY.get_Tq0_p(x), +) +get_params_metadata(::PSY.OneDOneQMachine) = ( + R = PartamsMetadata(false, false, true), + Xd = PartamsMetadata(false, false, true), + Xq = PartamsMetadata(false, false, true), + Xd_p = PartamsMetadata(false, false, true), + Xq_p = PartamsMetadata(false, false, true), + Td0_p = PartamsMetadata(false, false, false), + Tq0_p = PartamsMetadata(false, false, false), +) +#= #TODO - SimpleMarconatoMachine get_params(x::PSY.MarconatoMachine) = [ PSY.get_R(x), @@ -552,30 +557,29 @@ get_params_metadata(::PSY.AVRFixed) = (;) #= get_params(x::PSY.AVRSimple) = [PSY.get_Kv(x)] get_params_metadata(::PSY.AVRSimple) = [ParamsMetadata(:Kv_AVR, false, false, false, false)] -get_params(x::PSY.AVRTypeI) = [ - PSY.get_Ka(x), - PSY.get_Ke(x), - PSY.get_Kf(x), - PSY.get_Ta(x), - PSY.get_Te(x), - PSY.get_Tf(x), - PSY.get_Tr(x), - PSY.get_Ae(x), - PSY.get_Be(x), -] -get_params_metadata(::PSY.AVRTypeI) = [ - ParamsMetadata(:Ka_AVR, false, false, true, false), - ParamsMetadata(:Ke_AVR, false, false, true, false), - ParamsMetadata(:Kf_AVR, false, false, true, false), - ParamsMetadata(:Ta_AVR, false, false, false, false), - ParamsMetadata(:Te_AVR, false, false, false, false), - ParamsMetadata(:Tf_AVR, false, false, true, false), - ParamsMetadata(:Tr_AVR, false, false, false, false), - ParamsMetadata(:Ae_AVR, false, false, true, false), - ParamsMetadata(:Be_AVR, false, false, true, false), -] =# - +get_params(x::PSY.AVRTypeI) = ( + Ka = PSY.get_Ka(x), + Ke = PSY.get_Ke(x), + Kf = PSY.get_Kf(x), + Ta = PSY.get_Ta(x), + Te = PSY.get_Te(x), + Tf = PSY.get_Tf(x), + Tr = PSY.get_Tr(x), + Ae = PSY.get_Ae(x), + Be = PSY.get_Be(x), +) +get_params_metadata(::PSY.AVRTypeI) = ( + Ka = ParamsMetadata(false, false, true), + Ke = ParamsMetadata(false, false, true), + Kf = ParamsMetadata(false, false, true), + Ta = ParamsMetadata(false, false, false), + Te = ParamsMetadata(false, false, false), + Tf = ParamsMetadata(false, false, true), + Tr = ParamsMetadata(false, false, false), + Ae = ParamsMetadata(false, false, true), + Be = ParamsMetadata(false, false, true), +) get_params(x::PSY.SEXS) = ( Ta_Tb = PSY.get_Ta_Tb(x), Tb = PSY.get_Tb(x), diff --git a/test/Project.toml b/test/Project.toml index c0363117e..d024b9159 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -11,14 +11,14 @@ InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" -Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba" -OptimizationOptimisers = "42dfb2eb-d2b4-4451-abcd-913932933ac1" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" PowerFlows = "94fada2c-fd9a-4e89-8d82-81405f5cb4f6" PowerNetworkMatrices = "bed98974-b02a-5e2f-9fe0-a103f5c450dd" PowerSimulationsDynamics = "398b2ede-47ed-4edc-b52e-69e4a48b4336" PowerSystemCaseBuilder = "f00506e0-b84f-492a-93c2-c0a9afc4364e" PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd" +Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" diff --git a/test/runtests.jl b/test/runtests.jl index fcfc17033..e1a8766e4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,3 +1,4 @@ +using Revise using PowerSimulationsDynamics using PowerSystems using Test @@ -19,10 +20,11 @@ using Enzyme Enzyme.API.runtimeActivity!(true) Enzyme.API.looseTypeAnalysis!(true) #Required for using component arrays with Enzyme Enzyme.API.maxtypeoffset!(1024) -Enzyme.API.maxtypedepth!(20) +Enzyme.API.maxtypedepth!(20) using Zygote -using Optimization -using OptimizationOptimisers +## +#using Optimization #incompatible with latest Enzyme +#using OptimizationOptimisers import Aqua Aqua.test_unbound_args(PowerSimulationsDynamics) diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl new file mode 100644 index 000000000..9a026a394 --- /dev/null +++ b/test/test_case_enzyme.jl @@ -0,0 +1,193 @@ + +""" +Case 1: +This case study defines a classical machine against an infinite bus. Sensitivitiy +Analysis is performed for the inertia of the generator. The fault is a change in the +source voltage. This test also checks that incorrect user data is handled correctly. +""" +################################################## +############### LOAD DATA ###################### ## +################################################## + +omib_sys = build_system(PSIDTestSystems, "psid_test_omib") +ieee_9bus_sys = build_system(PSIDTestSystems, "psid_test_ieee_9bus") +andes_11bus_sys = build_system(PSIDSystems, "psid_11bus_andes") +################################################## +############### SOLVE PROBLEM #################### +################################################## + +s_device = get_component(Source, omib_sys, "InfBus") +s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) +using PlotlyJS + +#NOTES ON SENSITIVITY ALGORITHMS FROM SCIMLSENSITIVITY +#ReverseDiffVJP and EnzymeVJP only options compatible with Hybrid DEs (DEs with callbacks) +#BacksolveAdjoint prone to instabilities whenever the Lipschitz constant is sufficiently large (stiff equations, PDE discretizations, and many other contexts) +#For ForwardDiffSensitivity, convert_tspan=true is needed for hybrid equations. + +sim = Simulation( + MassMatrixModel, + omib_sys, + pwd(), + (0.0, 5.0), + s_change, +) + +#JULIA CRASHES - the problem has the Jacobian... +#= function f(p_in, sim ) + prob = sim.problem + prob_new = remake(prob, u0 = vcat(sim.problem.u0[1:end-1], p_in)) + #display(prob_new) + sol = solve(prob_new, Rodas4(), abstol =1e-9, reltol=1e-9) + u1 = [u[1] for u in sol.u] + #u6 = [u[6] for u in sol.u] + return sum(abs.(u1)) +end +p = [1.0000001] +f(p, sim) +dp = make_zero(p) +dsim = make_zero(sim) +#Would be huge if this works! +=# +#= prob = sim.problem +function f(p_in, prob_in ) + prob_new = remake(prob_in, u0 = vcat(prob_in.u0[1:end-1], p_in)) + sum(solve(prob_new, Rodas4(), abstol =1e-9, reltol=1e-9)) +end +p = [1.0000001] +f(p, prob) +dp_zygote = Zygote.gradient((p)->f(p, prob), p) =# + +#THIS EXACT THING WORKS IF THE PROBLEM DOESN"T COME FROM A SIMULATION... +prob = sim.problem +ode_f = prob.f +new_f = ODEFunction( + ode_f.f; + mass_matrix = ode_f.mass_matrix, + jac = nothing, + tgrad = ode_f.tgrad, +) +new_prob = ODEProblem(new_f, prob.u0, prob.tspan, prob.p) +function f(p_in, prob_in) + prob_new = remake(prob_in; u0 = vcat(prob_in.u0[1:(end - 1)], p_in)) + sum(solve(prob_new, Rodas4(); abstol = 1e-9, reltol = 1e-9)) +end +p = [1.0000002] +f(p, new_prob) +dp = make_zero(p) +dprob = make_zero(new_prob) +Enzyme.autodiff(Reverse, f, Active, Duplicated(p, dp), Duplicated(new_prob, dprob)) #Would be huge if this works! +dp_zygote2 = Zygote.gradient((p) -> f(p, new_prob), p)[1] +dp +dp_zygote2 + +##Now pass in the full sim... +sim = Simulation( + MassMatrixModel, + omib_sys, + pwd(), + (0.0, 5.0), + s_change, +) +sim.problem.f.jac +prob = sim.problem +ode_f = prob.f +new_f = ODEFunction( + ode_f.f; + mass_matrix = ode_f.mass_matrix, + jac = nothing, + tgrad = ode_f.tgrad, +) +new_prob = ODEProblem(new_f, prob.u0, prob.tspan, prob.p) +sim.problem = new_prob +sim.problem.f.jac + +#= #JULIA CRASHES... +#f2 = sim.problem.f.f #system model... Just a function. +function f(p_in, sim_in) + prob = sim_in.problem + #ode_f = prob.f + #new_f = ODEFunction{true}(f2)#; mass_matrix = ode_f.mass_matrix, jac = nothing, tgrad = ode_f.tgrad) + #new_prob = ODEProblem{true}(new_f, prob.u0, prob.tspan, prob.p) + prob_new = remake(prob, u0 = vcat(prob.u0[1:end-1], p_in)) + sum(solve(prob_new, Rodas4(), abstol =1e-9, reltol=1e-9)) +end +p = [1.0000002] +f(p, sim) +dp = make_zero(p) +dsim= make_zero(sim) +Enzyme.autodiff(Reverse, f, Active, Duplicated(p, dp), Duplicated(sim, dsim)) #Would be huge if this works! +dp_zygote2 = Zygote.gradient((p)->f(p, sim), p)[1] +dp +dp_zygote2 + +## =# +#PASS ONLY PROBLEM AND SIM INPUTS... In case it is some other part of Sim that causes the problem . +#= + fds +=# + +#= +@testset "Test Gradients - Mass Matrix no delays" begin + path = mktempdir() + try + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + H_gt = + get_H(get_shaft(get_component(DynamicGenerator, omib_sys, "generator-102-1"))) + execute!(sim, Rodas5(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + for solver in [FBDF(), Rodas5(), QNDF()] + for tol in [1e-6, 1e-9] + function f(sim, δ_gt) + execute!( + sim, + solver; + sensealg = ForwardDiffSensitivity(), + abstol = tol, + reltol = tol, + dtmax = 0.005, + saveat = 0.005, + ) + res = read_results(sim) + t, δ = get_state_series(res, ("generator-102-1", :δ)) + display(plot(scatter(; x = t, y = δ))) + return sum(abs.(δ - δ_gt)) + end + p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) + f_forward = + get_forward_function(f, sim, δ_gt, [("generator-102-1", :Shaft, :H)]) + @error p + @error f_forward([3.148]) + @error f_forward([3.0]) + #@error Enzyme.make_zero(sim) + f_grad = + get_gradient_function(f, sim, δ_gt, [("generator-102-1", :Shaft, :H)]) + f_grad([3.148]) + #f_grad = get_tradient_function + #p = PSID.get_parameter_sensitivity_values(sim, [("generator-102-1", SingleMass, :H)]) + #@error Zygote.gradient(g, [3.15])[1][1] + #= @test isapprox( + Zygote.gradient((p) -> g(p, δ_gt), [3.14])[1][1], + -8.0, + atol = 1.0, + ) + @test isapprox( + Zygote.gradient((p) -> g(p, δ_gt), [3.15])[1][1], + 8.0, + atol = 1.0, + ) =# + end + end + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + =# diff --git a/test/test_case_sensitivity.jl b/test/test_case_sensitivity.jl index ddf6ec665..c85842531 100644 --- a/test/test_case_sensitivity.jl +++ b/test/test_case_sensitivity.jl @@ -11,13 +11,14 @@ source voltage. This test also checks that incorrect user data is handled correc omib_sys = build_system(PSIDTestSystems, "psid_test_omib") ieee_9bus_sys = build_system(PSIDTestSystems, "psid_test_ieee_9bus") +andes_11bus_sys = build_system(PSIDSystems, "psid_11bus_andes") ################################################## ############### SOLVE PROBLEM #################### ################################################## s_device = get_component(Source, omib_sys, "InfBus") s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) -#using PlotlyJS +using PlotlyJS #NOTES ON SENSITIVITY ALGORITHMS FROM SCIMLSENSITIVITY #ReverseDiffVJP and EnzymeVJP only options compatible with Hybrid DEs (DEs with callbacks) @@ -57,7 +58,7 @@ s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) end g = PSID.get_parameter_sensitivity_function!( sim, - [("generator-102-1", SingleMass, :H)], + [("generator-102-1", :Shaft, :H)], f, ) #p = PSID.get_parameter_sensitivity_values(sim, [("generator-102-1", SingleMass, :H)]) @@ -111,12 +112,12 @@ end end g = PSID.get_parameter_sensitivity_function!( sim, - [("generator-102-1", SingleMass, :H)], + [("generator-102-1", :Shaft, :H)], f, ) p = PSID.get_parameter_sensitivity_values( sim, - [("generator-102-1", SingleMass, :H)], + [("generator-102-1", :Shaft, :H)], ) #H_values = [] #loss_values = [] @@ -210,7 +211,7 @@ end end g = PSID.get_parameter_sensitivity_function!( sim, - [("generator-102-1", SingleMass, :H)], + [("generator-102-1", :Shaft, :H)], f, ) #p = PSID.get_parameter_sensitivity_values(sim, [("generator-102-1", SingleMass, :H)]) @@ -296,12 +297,12 @@ end end g = PSID.get_parameter_sensitivity_function!( sim, - [("generator-102-1", SingleMass, :H)], + [("generator-102-1", :Shaft, :H)], f, ) p = PSID.get_parameter_sensitivity_values( sim, - [("generator-102-1", SingleMass, :H)], + [("generator-102-1", :Shaft, :H)], ) #H_values = [] #loss_values = [] @@ -327,7 +328,61 @@ end end end -@testset "Test unsupported options" begin +andes_11bus_sys = build_system(PSIDSystems, "psid_11bus_andes") +@testset "Test Gradients - Initialization" begin + path = mktempdir() + try + + #s_device = get_component(Source, omib_sys, "InfBus") + #s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) + # TODO - get an appropraite (valid) fault + sim = Simulation!( + MassMatrixModel, + andes_11bus_sys, + path, + (0.0, 5.0), + #s_change, TODO - new fault for this system + ) + #H_gt = + # get_H(get_shaft(get_component(DynamicGenerator, omib_sys, "generator-102-1"))) + #execute!(sim, Rodas5(); dtmax = 0.005, saveat = 0.005) + #res = read_results(sim) + #t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + function f(sim, data) + execute!( + sim, + Rodas5(); + sensealg = ForwardDiffSensitivity(), + abstol = 1e-6, + reltol = 1e-6, + dtmax = 0.005, + saveat = 0.005, + ) + res = read_results(sim) + t, δ = get_state_series(res, ("generator-2-1", :δ)) + display(plot(scatter(; x = t, y = δ))) + return sum(abs.(δ)) + end + g = PSID.get_parameter_sensitivity_function!( + sim, + [("generator-2-1", :Machine, :R)], + f, + ) + println(f(sim, nothing)) #TODO - to get here, we need to convert a few more models to NonlinearSolve.jl + @assert false + display(g) #Is returning nothing because initialization is explicitly not allowed: Change this and try to back propagate through eventually. + p = PSID.get_parameter_sensitivity_values(sim, [("generator-2-1", :Machine, :R)]) + println(p) + @error g(p, nothing) + #@error Zygote.gradient((x) -> g(x, nothing), p) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + +#Requires more models to be re-written: Check surrogate first. +#= @testset "Test unsupported options" begin path = mktempdir() try sim = Simulation!( @@ -338,8 +393,8 @@ end ) invalid_options = [ ("Bus 7-Bus 5-i_3", Line, :x), #not a wrapped component - ("generator-1-1", AndersonFouadMachine, :R), #part of initialization - ("generator-1-1", AndersonFouadMachine, :XXX), #incorrect symbol + ("generator-1-1", :Machine, :R), #part of initialization + ("generator-1-1", :Machine, :XXX), #incorrect symbol ] for option in invalid_options g = PSID.get_parameter_sensitivity_function!( @@ -353,4 +408,4 @@ end @info("removing test files") rm(path; force = true, recursive = true) end -end +end =# diff --git a/test/test_sundials.jl b/test/test_sundials.jl index f0b582190..7764a2fdc 100644 --- a/test/test_sundials.jl +++ b/test/test_sundials.jl @@ -23,7 +23,7 @@ solver_list = [ # :BCG, # :PCG, # :TFQMR, - :KLU, + # :KLU, ] #time span From c89e46a5ab8caaf1a3c50728b217efeba49a464e Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Fri, 31 May 2024 09:05:34 -0400 Subject: [PATCH 19/76] remove CRC.@ignore_derivatives --- src/base/caches.jl | 6 ++-- src/base/device_wrapper.jl | 4 +-- src/base/jacobian.jl | 6 ++-- src/base/nlsolve_wrapper.jl | 20 +++++------ src/base/perturbations.jl | 28 +++++++-------- src/base/sensitivity_analysis.jl | 2 +- src/base/simulation.jl | 26 +++++++------- src/base/simulation_initialization.jl | 34 +++++++++---------- src/base/simulation_results.jl | 4 +-- .../generator_components/init_avr.jl | 28 +++++++-------- .../generator_components/init_machine.jl | 22 ++++++------ .../generator_components/init_shaft.jl | 2 +- .../generator_components/init_tg.jl | 14 ++++---- src/initialization/init_device.jl | 20 +++++------ .../inverter_components/init_converter.jl | 4 +-- .../inverter_components/init_filter.jl | 2 +- .../init_frequency_estimator.jl | 4 +-- .../inverter_components/init_inner.jl | 8 ++--- src/models/device.jl | 10 +++--- src/models/generator_models/avr_models.jl | 2 +- src/models/generator_models/machine_models.jl | 2 +- src/models/generator_models/pss_models.jl | 2 +- src/models/generator_models/shaft_models.jl | 2 +- src/models/generator_models/tg_models.jl | 2 +- src/models/inverter_models/DCside_models.jl | 2 +- .../inverter_models/converter_models.jl | 2 +- src/models/inverter_models/filter_models.jl | 2 +- .../frequency_estimator_models.jl | 2 +- .../inverter_models/inner_control_models.jl | 2 +- .../inverter_models/outer_control_models.jl | 2 +- src/models/saturation_models.jl | 4 +-- src/post_processing/post_proc_generator.jl | 2 +- src/post_processing/post_proc_inverter.jl | 6 ++-- 33 files changed, 139 insertions(+), 139 deletions(-) diff --git a/src/base/caches.jl b/src/base/caches.jl index eb8eb2f0f..5c63ace93 100644 --- a/src/base/caches.jl +++ b/src/base/caches.jl @@ -22,7 +22,7 @@ end function JacobianCache{U}(F, inputs::SimulationInputs) where {U <: ForwardDiff.Dual} n_inj = get_injection_n_states(inputs) n_branches = get_branches_n_states(inputs) - CRC.@ignore_derivatives @debug "injection ode size = $n_inj branches ode size = $n_branches" + @debug "injection ode size = $n_inj branches ode size = $n_branches" bus_count = get_bus_count(inputs) inner_vars_count = get_inner_vars_count(inputs) n_global_vars = length(keys(get_global_vars_update_pointers(inputs))) @@ -80,11 +80,11 @@ end function SimCache(f!, inputs::SimulationInputs) n_inj = get_injection_n_states(inputs) n_branches = get_branches_n_states(inputs) - CRC.@ignore_derivatives @debug "injection ode size = $n_inj branches ode size = $n_branches" + @debug "injection ode size = $n_inj branches ode size = $n_branches" bus_count = get_bus_count(inputs) inner_vars_count = get_inner_vars_count(inputs) n_global_vars = length(keys(get_global_vars_update_pointers(inputs))) - global_vars = CRC.@ignore_derivatives setindex!( + global_vars = setindex!( zeros(Real, n_global_vars), 1.0, GLOBAL_VAR_SYS_FREQ_INDEX, diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index bbad10e16..4cf7dd935 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -484,9 +484,9 @@ get_bus_ix(wrapper::StaticLoadWrapper) = wrapper.bus_ix function set_connection_status(wrapper::Union{StaticWrapper, DynamicWrapper}, val::Int) if val == 0 - CRC.@ignore_derivatives @debug "Generator $(PSY.get_name(wrapper)) status set to off" + @debug "Generator $(PSY.get_name(wrapper)) status set to off" elseif val == 1 - CRC.@ignore_derivatives @debug "Generator $(PSY.get_name(wrapper)) status set to on" + @debug "Generator $(PSY.get_name(wrapper)) status set to on" else error("Invalid status $val. It can only take values 1 or 0") end diff --git a/src/base/jacobian.jl b/src/base/jacobian.jl index 67a7c30b2..cb38e7bc5 100644 --- a/src/base/jacobian.jl +++ b/src/base/jacobian.jl @@ -118,7 +118,7 @@ function JacobianFunctionWrapper( m_ = (residual, x) -> m!(residual, x, p, 0.0) jconfig = ForwardDiff.JacobianConfig(m_, similar(x0), x0, ForwardDiff.Chunk(x0)) Jf = (Jv, x) -> begin - CRC.@ignore_derivatives @debug "Evaluating Jacobian Function" + @debug "Evaluating Jacobian Function" ForwardDiff.jacobian!(Jv, m_, zeros(n), x, jconfig) return end @@ -158,7 +158,7 @@ function JacobianFunctionWrapper( m_ = (residual, x) -> m!(residual, zeros(n), x, p, 0.0) jconfig = ForwardDiff.JacobianConfig(m_, similar(x0), x0, ForwardDiff.Chunk(x0)) Jf = (Jv, x) -> begin - CRC.@ignore_derivatives @debug "Evaluating Jacobian Function" + @debug "Evaluating Jacobian Function" ForwardDiff.jacobian!(Jv, m_, zeros(n), x, jconfig) return end @@ -199,7 +199,7 @@ function JacobianFunctionWrapper( n = length(x0) Jf = (Jv, x, h, t) -> begin - CRC.@ignore_derivatives @debug "Evaluating Jacobian Function" + @debug "Evaluating Jacobian Function" m_ = (residual, x) -> m!(residual, x, h, p, t) jconfig = ForwardDiff.JacobianConfig(m_, similar(x0), x0, ForwardDiff.Chunk(x0)) diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index df9d65a1d..19a101d99 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -62,11 +62,11 @@ function _convergence_check( solv::NonlinearSolve.AbstractNonlinearSolveAlgorithm, ) if converged(sys_solve) - CRC.@ignore_derivatives @warn( + @warn( "Initialization non-linear solve succeeded with a tolerance of $(tol) using solver $(solv). Saving solution." ) else - CRC.@ignore_derivatives @warn( + @warn( "Initialization non-linear solve convergence failed with a tolerance of $(tol) using solver $(solv), initial conditions do not meet conditions for an stable equilibrium.\nAttempting again with reduced numeric tolerance and using another solver" ) end @@ -75,14 +75,14 @@ end function _sorted_residuals(residual::Vector{Float64}) if isapprox(sum(abs.(residual)), 0.0; atol = STRICT_NLSOLVE_F_TOLERANCE) - CRC.@ignore_derivatives @debug "Residual is zero with tolerance $(STRICT_NLSOLVE_F_TOLERANCE)" + @debug "Residual is zero with tolerance $(STRICT_NLSOLVE_F_TOLERANCE)" return end ix_sorted = sortperm(abs.(residual); rev = true) show_residual = min(10, length(residual)) for i in 1:show_residual ix = ix_sorted[i] - CRC.@ignore_derivatives @debug ix abs(residual[ix]) + @debug ix abs(residual[ix]) end return end @@ -92,10 +92,10 @@ function _check_residual( inputs::SimulationInputs, tolerance::Float64, ) - CRC.@ignore_derivatives @debug _sorted_residuals(residual) + @debug _sorted_residuals(residual) val, ix = findmax(residual) sum_residual = sum(abs.(residual)) - CRC.@ignore_derivatives @info "Residual from initial guess: max = $(val) at $ix, total = $sum_residual" + @info "Residual from initial guess: max = $(val) at $ix, total = $sum_residual" if sum_residual > tolerance state_map = make_global_state_map(inputs) for (k, val) in state_map @@ -149,7 +149,7 @@ function refine_initial_condition!( break end for solv in [NonlinearSolve.TrustRegion(), NonlinearSolve.NewtonRaphson()] - CRC.@ignore_derivatives @debug "Start NLSolve System Run with $(solv) and F_tol = $tol" + @debug "Start NLSolve System Run with $(solv) and F_tol = $tol" show_trace = sim.console_level <= Logging.Info sys_solve = _nlsolve_call( initial_guess, @@ -162,7 +162,7 @@ function refine_initial_condition!( ) failed(sys_solve) && return BUILD_FAILED converged = _convergence_check(sys_solve, tol, solv) - CRC.@ignore_derivatives @debug "Write initial guess vector using $solv with tol = $tol convergence = $converged" + @debug "Write initial guess vector using $solv with tol = $tol convergence = $converged" initial_guess .= sys_solve.zero if converged break @@ -180,7 +180,7 @@ function refine_initial_condition!( f!(residual, initial_guess, parameters) if !converged || (sum(residual) > MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE) _check_residual(residual, inputs, MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE) - CRC.@ignore_derivatives @warn( + @warn( "Initialization didn't found a solution to desired tolerances.\\ Initial conditions do not meet conditions for an stable equilibrium. \\ Simulation might fail" @@ -189,7 +189,7 @@ Simulation might fail" pf_diff = abs.(powerflow_solution .- initial_guess[bus_range]) if maximum(pf_diff) > MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE - CRC.@ignore_derivatives @warn "The resulting voltages in the initial conditions differ from the power flow results" + @warn "The resulting voltages in the initial conditions differ from the power flow results" end return end diff --git a/src/base/perturbations.jl b/src/base/perturbations.jl index a0a4a2b8e..ac354fad2 100644 --- a/src/base/perturbations.jl +++ b/src/base/perturbations.jl @@ -92,7 +92,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::BranchImped end return (integrator) -> begin - CRC.@ignore_derivatives @debug "Changing impedance line $(PSY.get_name(branch)) by a factor of $(pert.multiplier)" + @debug "Changing impedance line $(PSY.get_name(branch)) by a factor of $(pert.multiplier)" ybus_update!(inputs, branch, mult) end @@ -102,7 +102,7 @@ end function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::BranchTrip) branch = _get_branch_for_perturbation(sys, pert) return (integrator) -> begin - CRC.@ignore_derivatives @debug "Tripping line $(PSY.get_name(branch))" + @debug "Tripping line $(PSY.get_name(branch))" ybus_update!(inputs, branch, -1.0) end return @@ -371,7 +371,7 @@ function get_affect(inputs::SimulationInputs, ::PSY.System, pert::NetworkSwitch) return (integrator) -> begin # TODO: This code can be more performant using SparseMatrix methods for (i, v) in enumerate(pert.ybus_rectangular) - CRC.@ignore_derivatives @debug "Changing Ybus network" + @debug "Changing Ybus network" get_ybus(inputs)[i] = v end return @@ -546,9 +546,9 @@ function get_affect(inputs::SimulationInputs, ::PSY.System, pert::GeneratorTrip) return (integrator) -> begin wrapped_device = get_dynamic_injectors(inputs)[wrapped_device_ix] ix_range = get_ix_range(wrapped_device) - CRC.@ignore_derivatives @debug "Changing connection status $(PSY.get_name(wrapped_device)), setting states $ix_range to 0.0" + @debug "Changing connection status $(PSY.get_name(wrapped_device)), setting states $ix_range to 0.0" if integrator.du !== nothing - CRC.@ignore_derivatives @debug "setting du $ix_range to 0.0" + @debug "setting du $ix_range to 0.0" integrator.du[ix_range] .= 0.0 end integrator.u[ix_range] .= 0.0 @@ -589,7 +589,7 @@ mutable struct LoadChange <: Perturbation ) # Currently I'm assumming P_ref and Q_ref are constant impedance to if signal ∈ [:P_ref, :Q_ref] - CRC.@ignore_derivatives @warn( + @warn( "P_ref and Q_ref signals will be deprecated. It will be assumed as a change in constant impedance for StandardLoads and a change in constant power for PowerLoads. Allowed signals are $(ACCEPTED_LOADCHANGE_REFS)" ) end @@ -616,7 +616,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) wrapped_device_ix = _find_zip_load_ix(inputs, pert.device) ld = pert.device if !PSY.get_available(ld) - CRC.@ignore_derivatives @error( + @error( "Load $(PSY.get_name(ld)) is unavailable. Perturbation ignored" ) return @@ -644,7 +644,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) Q_power = get_Q_power(wrapped_zip) set_P_power!(wrapped_zip, P_power + P_change) set_Q_power!(wrapped_zip, Q_power + Q_change) - CRC.@ignore_derivatives @debug "Changing load at bus $(PSY.get_name(wrapped_zip)) $(pert.signal) to $(pert.ref_value)" + @debug "Changing load at bus $(PSY.get_name(wrapped_zip)) $(pert.signal) to $(pert.ref_value)" return end elseif isa(ld, PSY.StandardLoad) @@ -698,7 +698,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) Q_exp_old = exp_params.Q_exp exp_params.P_exp = P_exp_old + P_change exp_params.Q_exp = Q_exp_old + Q_change - CRC.@ignore_derivatives @debug "Removing exponential load entry $(ld_name) at wrapper $(PSY.get_name(wrapped_zip))" + @debug "Removing exponential load entry $(ld_name) at wrapper $(PSY.get_name(wrapped_zip))" return end else @@ -732,7 +732,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) wrapped_device_ix = _find_zip_load_ix(inputs, pert.device) ld = pert.device if !PSY.get_available(ld) - CRC.@ignore_derivatives @error( + @error( "Load $(PSY.get_name(ld)) is unavailable. Perturbation ignored" ) return @@ -748,7 +748,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) Q_power = get_Q_power(wrapped_zip) set_P_power!(wrapped_zip, P_power - P_trip) set_Q_power!(wrapped_zip, Q_power - Q_trip) - CRC.@ignore_derivatives @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" + @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end elseif isa(ld, PSY.StandardLoad) @@ -777,7 +777,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) Q_impedance = get_Q_impedance(wrapped_zip) set_P_impedance!(wrapped_zip, P_impedance - P_impedance_trip) set_Q_impedance!(wrapped_zip, Q_impedance - Q_impedance_trip) - CRC.@ignore_derivatives @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" + @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end elseif isa(ld, PSY.ExponentialLoad) @@ -790,7 +790,7 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) tuple_ix = exp_names[ld_name] deleteat!(exp_params, tuple_ix) delete!(exp_names, ld_name) - CRC.@ignore_derivatives @debug "Removing exponential load entry $(ld_name) at wrapper $(PSY.get_name(wrapped_zip))" + @debug "Removing exponential load entry $(ld_name) at wrapper $(PSY.get_name(wrapped_zip))" return end end @@ -835,7 +835,7 @@ end function get_affect(::SimulationInputs, ::PSY.System, pert::PerturbState) return (integrator) -> begin - CRC.@ignore_derivatives @debug "Modifying state" + @debug "Modifying state" integrator.u[pert.index] += pert.value return end diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 1f32e5eb7..cb6528d6e 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -119,7 +119,7 @@ function get_indices_in_parameter_vector(sim, device_param_pairs) if ix !== nothing wrapped_device = sim.inputs_init.static_injectors[ix] else - CRC.@ignore_derivatives @warn "Device $device_name not found in dynamic or static injectors" + @warn "Device $device_name not found in dynamic or static injectors" return nothing end end diff --git a/src/base/simulation.jl b/src/base/simulation.jl index 383bbba3e..1b5907156 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -207,10 +207,10 @@ function Simulation( end function reset!(sim::Simulation{T}) where {T <: SimulationModel} - CRC.@ignore_derivatives @info "Rebuilding the simulation after reset" + @info "Rebuilding the simulation after reset" sim.status = BUILD_INCOMPLETE build!(sim) - CRC.@ignore_derivatives @info "Simulation reset to status $(sim.status)" + @info "Simulation reset to status $(sim.status)" return end @@ -278,9 +278,9 @@ function _get_jacobian(sim::Simulation{MassMatrixModel}) end function _build_perturbations!(sim::Simulation) - CRC.@ignore_derivatives @info "Attaching Perturbations" + @info "Attaching Perturbations" if isempty(sim.perturbations) - CRC.@ignore_derivatives @debug "The simulation has no perturbations" + @debug "The simulation has no perturbations" return SciMLBase.CallbackSet(), [0.0] end inputs = get_simulation_inputs(sim) @@ -304,7 +304,7 @@ function _add_callback!( sim::Simulation, inputs::SimulationInputs, ) where {T <: Perturbation} - CRC.@ignore_derivatives @debug pert + @debug pert condition = (x, t, integrator) -> t in [pert.time] affect = get_affect(inputs, get_system(sim), pert) callback_vector[ix] = SciMLBase.DiscreteCallback(condition, affect) @@ -481,7 +481,7 @@ function build!(sim; kwargs...) sortby = :firstexec, compact = true, ) - CRC.@ignore_derivatives @info "\n$(String(take!(string_buffer)))\n" + @info "\n$(String(take!(string_buffer)))\n" #end end close(logger) @@ -494,10 +494,10 @@ function simulation_pre_step!(sim::Simulation) "The Simulation status is $(sim.status). Can not continue, correct your inputs and build the simulation again.", ) elseif sim.status == BUILT - CRC.@ignore_derivatives @debug "Simulation status is $(sim.status)." + @debug "Simulation status is $(sim.status)." elseif sim.status == SIMULATION_FINALIZED reset!(sim) - CRC.@ignore_derivatives @info "The Simulation status is $(sim.status). Resetting the simulation" + @info "The Simulation status is $(sim.status). Resetting the simulation" else error("Simulation status is $(sim.status). Can't continue.") end @@ -515,8 +515,8 @@ function _filter_kwargs(kwargs) end function _execute!(sim::Simulation, solver; kwargs...) - CRC.@ignore_derivatives @debug "status before execute" sim.status - CRC.@ignore_derivatives simulation_pre_step!(sim) + @debug "status before execute" sim.status + simulation_pre_step!(sim) sim.status = SIMULATION_STARTED time_log = Dict{Symbol, Any}() if get(kwargs, :auto_abstol, false) @@ -525,7 +525,7 @@ function _execute!(sim::Simulation, solver; kwargs...) else callbacks = SciMLBase.CallbackSet((), tuple(sim.callbacks...)) end - progress_enable = CRC.@ignore_derivatives _prog_meter_enabled() + progress_enable = _prog_meter_enabled() solution, time_log[:timed_solve_time], time_log[:solve_bytes_alloc], @@ -549,7 +549,7 @@ function _execute!(sim::Simulation, solver; kwargs...) solution, ) else - CRC.@ignore_derivatives @error( + @error( "The simulation failed with return code $(solution.retcode)" ) sim.status = SIMULATION_FAILED @@ -577,7 +577,7 @@ function execute!(sim::Simulation, solver; kwargs...) try _execute!(sim, solver; kwargs...) catch e - CRC.@ignore_derivatives @error "Execution failed" exception = + @error "Execution failed" exception = (e, catch_backtrace()) sim.status = SIMULATION_FAILED end diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index 9652ae27f..8c6a5599a 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -5,23 +5,23 @@ function power_flow_solution!( ) res = PF.solve_ac_powerflow!(sys) if !res - CRC.@ignore_derivatives @error("PowerFlow failed to solve") + @error("PowerFlow failed to solve") return BUILD_FAILED end bus_size = length(PSY.get_bus_numbers(sys)) - CRC.@ignore_derivatives @debug "Updating bus voltage magnitude and angle to match power flow result" + @debug "Updating bus voltage magnitude and angle to match power flow result" for bus in PSY.get_components(PSY.Bus, sys) bus_n = PSY.get_number(bus) bus_ix = get_lookup(inputs)[bus_n] initial_guess[bus_ix] = PSY.get_magnitude(bus) * cos(PSY.get_angle(bus)) initial_guess[bus_ix + bus_size] = PSY.get_magnitude(bus) * sin(PSY.get_angle(bus)) - CRC.@ignore_derivatives @debug "$(PSY.get_name(bus)) V_r = $(initial_guess[bus_ix]), V_i = $(initial_guess[bus_ix + bus_size])" + @debug "$(PSY.get_name(bus)) V_r = $(initial_guess[bus_ix]), V_i = $(initial_guess[bus_ix + bus_size])" end return BUILD_INCOMPLETE end function initialize_static_injection!(inputs::SimulationInputs) - CRC.@ignore_derivatives @debug "Updating Source internal voltage magnitude and angle" + @debug "Updating Source internal voltage magnitude and angle" static_injection_devices = get_static_injectors(inputs) parameters = get_parameters(inputs) if !isempty(static_injection_devices) @@ -38,16 +38,16 @@ function initialize_dynamic_injection!( inputs::SimulationInputs, system::PSY.System, ) - CRC.@ignore_derivatives @debug "Updating Dynamic Injection Component Initial Guess" + @debug "Updating Dynamic Injection Component Initial Guess" initial_inner_vars = zeros(get_inner_vars_count(inputs)) parameters = get_parameters(inputs) for dynamic_device in get_dynamic_injectors(inputs) - static = CRC.@ignore_derivatives PSY.get_component( + static = PSY.get_component( dynamic_device.static_type, system, PSY.get_name(dynamic_device), ) - CRC.@ignore_derivatives @debug "Initializing $(PSY.get_name(dynamic_device)) - $(typeof(dynamic_device.device))" + @debug "Initializing $(PSY.get_name(dynamic_device)) - $(typeof(dynamic_device.device))" _inner_vars = @view initial_inner_vars[get_inner_vars_index(dynamic_device)] _parameters = @view parameters[_get_wrapper_name(dynamic_device)] _states = @view initial_guess[get_ix_range(dynamic_device)] @@ -67,9 +67,9 @@ function initialize_dynamic_branches!( inputs::SimulationInputs, ) parameters = get_parameters(inputs) - CRC.@ignore_derivatives @debug "Initializing Dynamic Branches" + @debug "Initializing Dynamic Branches" for br in get_dynamic_branches(inputs) - CRC.@ignore_derivatives @debug "$(PSY.get_name(br)) - $(typeof(br))" + @debug "$(PSY.get_name(br)) - $(typeof(br))" wrapper_name = _get_wrapper_name(br) _parameters = @view parameters[wrapper_name] _states = @view initial_guess[get_ix_range(br)] @@ -103,7 +103,7 @@ function check_valid_values(initial_guess::Vector{Float64}, inputs::SimulationIn end if !isempty(invalid_initial_guess) - CRC.@ignore_derivatives @error( + @error( "Invalid initial condition values $invalid_initial_guess" ) return BUILD_FAILED @@ -138,17 +138,17 @@ function _initialize_state_space( ) where {T <: SimulationModel} inputs = get_simulation_inputs(sim) sim.x0 = _get_flat_start(inputs) - CRC.@ignore_derivatives @info("Pre-Initializing Simulation States") + @info("Pre-Initializing Simulation States") @assert sim.status == BUILD_INCOMPLETE while sim.status == BUILD_INCOMPLETE - CRC.@ignore_derivatives @debug "Start state intialization routine" + @debug "Start state intialization routine" sim.status = power_flow_solution!(sim.x0, get_system(sim), inputs) sim.status = initialize_static_injection!(inputs) sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) if has_dyn_lines(inputs) sim.status = initialize_dynamic_branches!(sim.x0, inputs) else - CRC.@ignore_derivatives @debug "No Dynamic Branches in the system" + @debug "No Dynamic Branches in the system" end sim.status = check_valid_values(sim.x0, inputs) end @@ -160,18 +160,18 @@ function _initialize_state_space( sim::Simulation{T}, ::Val{DEVICES_ONLY}, ) where {T <: SimulationModel} - CRC.@ignore_derivatives @info("Pre-Initializing Simulation States") + @info("Pre-Initializing Simulation States") inputs = get_simulation_inputs(sim) #GET INNER VARS, PARAMETERS, AND STATES AT THIS LEVEL ... @assert sim.status == BUILD_INCOMPLETE while sim.status == BUILD_INCOMPLETE - CRC.@ignore_derivatives @debug "Start state intialization routine" + @debug "Start state intialization routine" sim.status = initialize_static_injection!(inputs) sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) if has_dyn_lines(inputs) sim.status = initialize_dynamic_branches!(sim.x0, inputs) else - CRC.@ignore_derivatives @debug "No Dynamic Branches in the system" + @debug "No Dynamic Branches in the system" end sim.status = check_valid_values(sim.x0, inputs) end @@ -198,7 +198,7 @@ function _initialize_state_space( ), ) end - CRC.@ignore_derivatives @warn( + @warn( "Using existing initial conditions value for simulation initialization" ) sim.x0 = deepcopy(sim.x0_init) diff --git a/src/base/simulation_results.jl b/src/base/simulation_results.jl index 7db94f07f..38bf4b5f9 100644 --- a/src/base/simulation_results.jl +++ b/src/base/simulation_results.jl @@ -37,7 +37,7 @@ global index for a state. """ function _post_proc_state_series(solution, ix::Int, dt::Nothing) - ix_t = CRC.@ignore_derivatives unique(i -> solution.t[i], eachindex(solution.t)) + ix_t = unique(i -> solution.t[i], eachindex(solution.t)) ts = solution.t[ix_t] state = solution[ix, ix_t] return ts, state @@ -65,7 +65,7 @@ function post_proc_state_series( ) global_state_index = get_global_index(res) if !haskey(global_state_index, ref[1]) - CRC.@ignore_derivatives @error "$(keys(global_state_index))" + @error "$(keys(global_state_index))" error("State $(ref[2]) device $(ref[1]) not found in the system. ") end ix = get(global_state_index[ref[1]], ref[2], 0) diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index 04ffedfc9..c500605ef 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -83,7 +83,7 @@ function initialize_avr!( abstol = STRICT_NLSOLVE_F_TOLERANCE, ) if !SciMLBase.successful_retcode(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else @@ -151,7 +151,7 @@ function initialize_avr!( x0 = [1.0, Vf0, Vf0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else @@ -169,7 +169,7 @@ function initialize_avr!( y_ll1, _ = lead_lag(sol_x0[1] - Vm, sol_x0[2], K0, T2, T1) y_ll2, _ = lead_lag(y_ll1, K0 * sol_x0[3], 1.0, K0 * T4, K0 * T3) if (y_ll2 > Va_max) || (y_ll2 < Va_min) - CRC.@ignore_derivatives @error( + @error( "Regulator Voltage V_r = $(y_ll2) outside the limits" ) end @@ -225,7 +225,7 @@ function initialize_avr!( x0 = [1.0] sol = NLsolve.nlsolve(f_Ve!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else @@ -237,7 +237,7 @@ function initialize_avr!( V_FE0 = Kd * Xad_Ifd0 + Ke * V_e0 + Se0 * V_e0 V_r20 = V_FE0 if (V_r20 > Vr_max) || (V_r20 < Vr_min) - CRC.@ignore_derivatives @error( + @error( "Regulator Voltage V_R = $(V_r20) outside the limits" ) end @@ -274,7 +274,7 @@ function initialize_avr!( x0 = [V_ref0, V_r10, V_r20, V_e0, V_r30] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else @@ -334,14 +334,14 @@ function initialize_avr!( abstol = STRICT_NLSOLVE_F_TOLERANCE, ) if !SciMLBase.successful_retcode(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else sol_x0 = sol.u if (sol_x0[2] >= V_max + BOUNDS_TOLERANCE) || (sol_x0[2] <= V_min - BOUNDS_TOLERANCE) - CRC.@ignore_derivatives @error( + @error( "Vr limits for AVR in $(PSY.get_name(dynamic_device)) (Vr = $(sol_x0[2])), outside its limits V_max = $V_max, Vmin = $V_min. Consider updating the operating point." ) end @@ -419,7 +419,7 @@ function initialize_avr!( x0 = [1.0, Vf0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else # if converge @@ -427,7 +427,7 @@ function initialize_avr!( Vr2_0 = (sol_x0[2] + Ta_Tb * (sol_x0[1] - Vm)) * K # K * V_LL #check the limits if (Vr2_0 >= V_max + BOUNDS_TOLERANCE) || (Vr2_0 <= V_min - BOUNDS_TOLERANCE) - CRC.@ignore_derivatives @error( + @error( "Vr limits for AVR in $(PSY.get_name(dynamic_device)) (Vr = $(sol_x0[2])), outside its limits V_max = $V_max, Vmin = $V_min. Consider updating the operating point." ) end @@ -475,7 +475,7 @@ function initialize_avr!( # Check limits to field voltage if (Vt * Vr_min - Kc * Ifd > Vf0) || (Vf0 > Vt * Vr_max - Kc * Ifd) - CRC.@ignore_derivatives @error( + @error( "Field Voltage for AVR in $(PSY.get_name(dynamic_device)) is $(Vf0) pu, which is outside its limits. Consider updating the operating point." ) end @@ -541,7 +541,7 @@ function initialize_avr!( x0 = [10.0] # initial guess for Ve sol = NLsolve.nlsolve(f_Ve!, x0) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else @@ -553,7 +553,7 @@ function initialize_avr!( VFE = Kd * Ifd0 + Ke * Ve + Se * Ve Vr2 = VFE if (Vr2 > Vr_max) || (Vr2 < Vr_min) - CRC.@ignore_derivatives @error("Regulator Voltage V_R = $(Vr2) outside the limits") + @error("Regulator Voltage V_R = $(Vr2) outside the limits") end Vr3 = -(Kf / Tf) * VFE Tc_Tb_ratio = Tb <= eps() ? 0.0 : Tc / Tb @@ -608,7 +608,7 @@ function initialize_avr!( # Check limits to field voltage if (Vt * Vr_min > Vf0) || (Vf0 > Vt * Vr_max - Kc * Ifd) - CRC.@ignore_derivatives @error( + @error( "Field Voltage for AVR in $(PSY.get_name(dynamic_device)) is $(Vf0) pu, which is outside its limits. Consider updating the operating point." ) end diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index 65341c844..20446fd8e 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -55,7 +55,7 @@ function initialize_mach_shaft!( abstol = STRICT_NLSOLVE_F_TOLERANCE, ) if !SciMLBase.successful_retcode(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else @@ -146,7 +146,7 @@ function initialize_mach_shaft!( abstol = STRICT_NLSOLVE_F_TOLERANCE, ) if !SciMLBase.successful_retcode(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else @@ -250,7 +250,7 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[1], V_dq0[2], V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else @@ -348,7 +348,7 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[1], V_dq0[2], V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else @@ -456,7 +456,7 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else @@ -562,7 +562,7 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[1], V_dq0[2], V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else @@ -664,7 +664,7 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, 1.0, V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else @@ -837,7 +837,7 @@ function initialize_mach_shaft!( abstol = STRICT_NLSOLVE_F_TOLERANCE, ) if !SciMLBase.successful_retcode(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else @@ -965,7 +965,7 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, Vf0, eq_p0, ψ_kd0, ψq_pp0, Xad_Ifd0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else @@ -1104,7 +1104,7 @@ function initialize_mach_shaft!( x0 = [δ0, τm0, Vf0, eq_p0, ψ_kd0, ψq_pp0, Xad_Ifd0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else @@ -1203,7 +1203,7 @@ static::PSY.StaticInjection, x0 = [δ0, τm0, 1.0, V_dq0[2], -V_dq0[1], 1.0, 0.0, 0.0] sol = NLsolve.nlsolve(f!, x0) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn("Initialization in Machine $(PSY.get_name(static)) failed") + @warn("Initialization in Machine $(PSY.get_name(static)) failed") else sol_x0 = sol.zero #Update terminal voltages diff --git a/src/initialization/generator_components/init_shaft.jl b/src/initialization/generator_components/init_shaft.jl index 99cd66562..2fc24c1a4 100644 --- a/src/initialization/generator_components/init_shaft.jl +++ b/src/initialization/generator_components/init_shaft.jl @@ -82,7 +82,7 @@ function initialize_shaft!( x0 = [τm0, δ0, δ0, δ0, δ0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn("Initialization in Shaft failed") + @warn("Initialization in Shaft failed") else sol_x0 = sol.zero inner_vars[τm_var] = sol_x0[1] #τm diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index f07f8ab9f..f530522db 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -59,7 +59,7 @@ function initialize_tg!( ] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization of Turbine Governor $(PSY.get_name(static)) failed" ) else @@ -71,7 +71,7 @@ function initialize_tg!( tg_ix = get_local_state_ix(dynamic_device, PSY.TGTypeI) tg_states = @view device_states[tg_ix] if (sol_x0[2] > V_max) || (sol_x0[2] < V_min) - CRC.@ignore_derivatives @error( + @error( "Valve limits for TG in $(PSY.get_name(dynamic_device)) (x_g1 = $(sol_x0[2])), outside its limits V_max = $V_max, Vmin = $V_min. Consider updating the operating point." ) end @@ -110,7 +110,7 @@ function initialize_tg!( x0 = [τm0, 0.0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization of Turbine Governor $(PSY.get_name(static)) failed" ) else @@ -161,7 +161,7 @@ function initialize_tg!( x0 = [1.0 / inv_R, τm0, τm0, τm0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @error( + @error( "Initialization of Turbine Governor $(PSY.get_name(static)) failed" ) else @@ -253,12 +253,12 @@ function initialize_tg!( abstol = STRICT_NLSOLVE_F_TOLERANCE, ) if !SciMLBase.successful_retcode(sol) - CRC.@ignore_derivatives @warn("Initialization in TG failed") + @warn("Initialization in TG failed") else sol_x0 = sol.u if (sol_x0[2] >= V_max + BOUNDS_TOLERANCE) || (sol_x0[2] <= V_min - BOUNDS_TOLERANCE) - CRC.@ignore_derivatives @error( + @error( "Valve limits for TG in $(PSY.get_name(dynamic_device)) (x_g1 = $(sol_x0[2])), outside its limits V_max = $V_max, Vmin = $V_min. Consider updating the operating point." ) end @@ -324,7 +324,7 @@ function initialize_tg!( x0 = [P0, 0, (r * Tr) * P0 / R, P0 / R, P0 / R] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization of Turbine Governor $(PSY.get_name(static)) failed" ) else diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index 2771c3950..ebebe8048 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -94,7 +94,7 @@ function initialize_static_device!( ) if !SciMLBase.successful_retcode(sol) - CRC.@ignore_derivatives @warn("Initialization in Source failed") + @warn("Initialization in Source failed") else sol_x0 = sol.u #Update terminal voltages @@ -142,7 +142,7 @@ function initialize_dynamic_device!( x0 = [V_R, V_I] sol = NLsolve.nlsolve(f!, x0) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn("Initialization in Periodic Variable Source failed") + @warn("Initialization in Periodic Variable Source failed") else sol_x0 = sol.zero #Update terminal voltages @@ -285,7 +285,7 @@ function initialize_dynamic_device!( end sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Ind. Motor $(PSY.get_name(device)) failed" ) else @@ -396,7 +396,7 @@ function initialize_dynamic_device!( end sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Ind. Motor $(PSY.get_name(device)) failed" ) else @@ -456,11 +456,11 @@ function initialize_dynamic_device!( vr2 = thy if (thy > Vmax) || (thy < Vmin) - CRC.@ignore_derivatives @error("Thyristor state thy = $(thy) outside the limits") + @error("Thyristor state thy = $(thy) outside the limits") end if (vr2 > 1) || (vr2 < Rmin / Rbase) - CRC.@ignore_derivatives @error("Regulator state vr2 = $(vr2) outside the limits") + @error("Regulator state vr2 = $(vr2) outside the limits") end device_states[1] = K * (V_abs - V_ref0) # thy device_states[2] = 0.0 # vr1 @@ -556,7 +556,7 @@ function initialize_dynamic_device!( end sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Active Load $(PSY.get_name(device)) failed" ) else @@ -614,13 +614,13 @@ function initialize_dynamic_device!( Iq_cmd = Iq / Mult Ip_min, Ip_max, Iq_min, Iq_max = current_limit_logic(dynamic_device, Ip_cmd, Iq_cmd) if Ip_cmd >= Ip_max + BOUNDS_TOLERANCE || Ip_min - BOUNDS_TOLERANCE >= Ip_cmd - CRC.@ignore_derivatives @error( + @error( "Inverter $(PSY.get_name(static)) active current $(Ip_cmd) out of limits $(Ip_min) $(Ip_max). Check Power Flow or Parameters" ) end if Iq_cmd >= Iq_max + BOUNDS_TOLERANCE || Iq_min - BOUNDS_TOLERANCE >= Iq_cmd - CRC.@ignore_derivatives @error( + @error( "Inverter $(PSY.get_name(static)) reactive current $(Iq_cmd) out of limits $(Iq_min) $(Iq_max). Check Power Flow or Parameters" ) end @@ -655,7 +655,7 @@ function initialize_dynamic_device!( device_states[9] = Pord device_states[10] = Ip else - CRC.@ignore_derivatives @error "Unsupported value of Freq_Flag" + @error "Unsupported value of Freq_Flag" end #See Note 2 on PSSE Documentation diff --git a/src/initialization/inverter_components/init_converter.jl b/src/initialization/inverter_components/init_converter.jl index 085a6eba1..5f264ee0f 100644 --- a/src/initialization/inverter_components/init_converter.jl +++ b/src/initialization/inverter_components/init_converter.jl @@ -72,7 +72,7 @@ function initialize_converter!( _, Lv_pnt1 = PSY.get_Lv_pnts(converter) if (Iq < Io_lim) || (V_t > Vo_lim) || (V_t < Lv_pnt1) - CRC.@ignore_derivatives @error( + @error( "Power flow solution outside of inverter limits $(PSY.get_name(static)). Update parameters." ) end @@ -125,7 +125,7 @@ function initialize_converter!( _, Lv_pnt1 = PSY.get_Lv_pnts(converter) if (Iq < Io_lim) || (V_t > Vo_lim) || (V_t < Lv_pnt1) - CRC.@ignore_derivatives @error( + @error( "Power flow solution outside of inverter limits $(PSY.get_name(static)). Update parameters." ) end diff --git a/src/initialization/inverter_components/init_filter.jl b/src/initialization/inverter_components/init_filter.jl index 637bc0472..2eb766053 100644 --- a/src/initialization/inverter_components/init_filter.jl +++ b/src/initialization/inverter_components/init_filter.jl @@ -66,7 +66,7 @@ function initialize_filter!( abstol = STRICT_NLSOLVE_F_TOLERANCE, ) if !SciMLBase.successful_retcode(sol) - CRC.@ignore_derivatives @warn( + @warn( "Initialization in Filter failed $(PSY.get_name(static))" ) else diff --git a/src/initialization/inverter_components/init_frequency_estimator.jl b/src/initialization/inverter_components/init_frequency_estimator.jl index a83f17d7f..3d00db073 100644 --- a/src/initialization/inverter_components/init_frequency_estimator.jl +++ b/src/initialization/inverter_components/init_frequency_estimator.jl @@ -51,7 +51,7 @@ function initialize_frequency_estimator!( abstol = STRICT_NLSOLVE_F_TOLERANCE, ) if !SciMLBase.successful_retcode(sol) - CRC.@ignore_derivatives @warn("Initialization in PLL failed") + @warn("Initialization in PLL failed") else sol_x0 = sol.u @@ -115,7 +115,7 @@ function initialize_frequency_estimator!( x0 = [Vpll_q0, ϵ_pll0, θ0_pll] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn("Initialization in PLL failed") + @warn("Initialization in PLL failed") else sol_x0 = sol.zero diff --git a/src/initialization/inverter_components/init_inner.jl b/src/initialization/inverter_components/init_inner.jl index 807c3a464..54ac6d4fb 100644 --- a/src/initialization/inverter_components/init_inner.jl +++ b/src/initialization/inverter_components/init_inner.jl @@ -108,7 +108,7 @@ function initialize_inner!( abstol = STRICT_NLSOLVE_F_TOLERANCE, ) if !SciMLBase.successful_retcode(sol) - CRC.@ignore_derivatives @warn("Initialization in Inner Control failed") + @warn("Initialization in Inner Control failed") else sol_x0 = sol.u #Update angle: @@ -216,7 +216,7 @@ function initialize_inner!( x0 = [0.0, 0.0] sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) if !NLsolve.converged(sol) - CRC.@ignore_derivatives @warn("Initialization in Inner Control failed") + @warn("Initialization in Inner Control failed") else sol_x0 = sol.zero #Update Converter modulation @@ -279,13 +279,13 @@ function initialize_inner!( current_limit_logic(inner_control, Val(PQ_Flag), V_t, Ip_oc, Iq_cmd) if Ip_oc >= Ip_max + BOUNDS_TOLERANCE || Ip_min - BOUNDS_TOLERANCE >= Ip_oc - CRC.@ignore_derivatives @error( + @error( "Inverter $(PSY.get_name(static)) active current $(Ip_oc) out of limits $(Ip_min) $(Ip_max). Check Power Flow or Parameters" ) end if Iq_oc >= Iq_max + BOUNDS_TOLERANCE || Iq_min - BOUNDS_TOLERANCE >= Iq_oc - CRC.@ignore_derivatives @error( + @error( "Inverter $(PSY.get_name(static)) reactive current $(Iq_oc) out of limits $(Iq_min) $(Iq_max). Check Power Flow or Parameters" ) end diff --git a/src/models/device.jl b/src/models/device.jl index 3d4a1cbad..7428cdc4f 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -310,7 +310,7 @@ function mass_matrix_pvs_entries!( pvs::DynamicWrapper{PSY.PeriodicVariableSource}, global_index::ImmutableDict{Symbol, Int64}, ) - CRC.@ignore_derivatives @debug "Using default mass matrix entries $pvs" + @debug "Using default mass matrix entries $pvs" end function device!( @@ -774,7 +774,7 @@ function mass_matrix_induction_entries!( ) where { T <: Union{PSY.SingleCageInductionMachine, PSY.SimplifiedSingleCageInductionMachine}, } - CRC.@ignore_derivatives @debug "Using default mass matrix entries $ind" + @debug "Using default mass matrix entries $ind" end """ @@ -961,7 +961,7 @@ function mass_matrix_csvgn1_entries!( csvgn1::DynamicWrapper{PSY.CSVGN1}, global_index::ImmutableDict{Symbol, Int64}, ) - CRC.@ignore_derivatives @debug "Using default mass matrix entries $csvgn1" + @debug "Using default mass matrix entries $csvgn1" end """ @@ -1344,7 +1344,7 @@ function _mdl_ode_AggregateDistributedGenerationA!( elseif Pf_Flag == 0 _, dQ_V_dt = low_pass_mass_matrix(Q_ref / max(Vmeas, 0.01), Q_V, 1.0, T_iq) else - CRC.@ignore_derivatives @error "Unsupported value of PQ_Flag" + @error "Unsupported value of PQ_Flag" end #STATE Iq @@ -1489,7 +1489,7 @@ function _mdl_ode_AggregateDistributedGenerationA!( elseif Pf_Flag == 0 _, dQ_V_dt = low_pass_mass_matrix(Q_ref / max(Vmeas, 0.01), Q_V, 1.0, T_iq) else - CRC.@ignore_derivatives @error "Unsupported value of PQ_Flag" + @error "Unsupported value of PQ_Flag" end #STATE Iq diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index 5125be413..8141f9d51 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -3,7 +3,7 @@ function mass_matrix_avr_entries!( avr::T, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {T <: PSY.AVR} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $T" + @debug "Using default mass matrix entries $T" return end diff --git a/src/models/generator_models/machine_models.jl b/src/models/generator_models/machine_models.jl index ecc21c520..fb9708e89 100644 --- a/src/models/generator_models/machine_models.jl +++ b/src/models/generator_models/machine_models.jl @@ -3,7 +3,7 @@ function mass_matrix_machine_entries!( machine::M, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {M <: PSY.Machine} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $M" + @debug "Using default mass matrix entries $M" end """ diff --git a/src/models/generator_models/pss_models.jl b/src/models/generator_models/pss_models.jl index f9af17568..fba77bfc9 100644 --- a/src/models/generator_models/pss_models.jl +++ b/src/models/generator_models/pss_models.jl @@ -3,7 +3,7 @@ function mass_matrix_pss_entries!( ::P, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {P <: PSY.PSS} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $P" + @debug "Using default mass matrix entries $P" end function mass_matrix_pss_entries!( diff --git a/src/models/generator_models/shaft_models.jl b/src/models/generator_models/shaft_models.jl index 5a17cd5e2..be8bd8f40 100644 --- a/src/models/generator_models/shaft_models.jl +++ b/src/models/generator_models/shaft_models.jl @@ -3,7 +3,7 @@ function mass_matrix_shaft_entries!( shaft::S, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {S <: PSY.Shaft} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $S" + @debug "Using default mass matrix entries $S" end function mdl_shaft_ode!( diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index 00f67b420..ec2ad184b 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -3,7 +3,7 @@ function mass_matrix_tg_entries!( tg::TG, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {TG <: PSY.TurbineGov} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $TG" + @debug "Using default mass matrix entries $TG" end function mass_matrix_tg_entries!( diff --git a/src/models/inverter_models/DCside_models.jl b/src/models/inverter_models/DCside_models.jl index ac0b85088..a7288129e 100644 --- a/src/models/inverter_models/DCside_models.jl +++ b/src/models/inverter_models/DCside_models.jl @@ -3,7 +3,7 @@ function mass_matrix_DCside_entries!( dc_side::DC, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {DC <: PSY.DCSource} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $DC" + @debug "Using default mass matrix entries $DC" end function mdl_DCside_ode!( diff --git a/src/models/inverter_models/converter_models.jl b/src/models/inverter_models/converter_models.jl index cd2303f57..f4d4ea5df 100644 --- a/src/models/inverter_models/converter_models.jl +++ b/src/models/inverter_models/converter_models.jl @@ -3,7 +3,7 @@ function mass_matrix_converter_entries!( converter::C, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {C <: PSY.Converter} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $C" + @debug "Using default mass matrix entries $C" end function mdl_converter_ode!( diff --git a/src/models/inverter_models/filter_models.jl b/src/models/inverter_models/filter_models.jl index 99a503822..acb5b796f 100644 --- a/src/models/inverter_models/filter_models.jl +++ b/src/models/inverter_models/filter_models.jl @@ -4,7 +4,7 @@ function mass_matrix_filter_entries!( global_index::Base.ImmutableDict{Symbol, Int64}, f0::Float64, ) where {F <: PSY.Filter} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $F" + @debug "Using default mass matrix entries $F" return end diff --git a/src/models/inverter_models/frequency_estimator_models.jl b/src/models/inverter_models/frequency_estimator_models.jl index 61996f8a7..455aa1d33 100644 --- a/src/models/inverter_models/frequency_estimator_models.jl +++ b/src/models/inverter_models/frequency_estimator_models.jl @@ -3,7 +3,7 @@ function mass_matrix_freq_estimator_entries!( freq_estimator::P, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {P <: PSY.FrequencyEstimator} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $P" + @debug "Using default mass matrix entries $P" end function mdl_freq_estimator_ode!( diff --git a/src/models/inverter_models/inner_control_models.jl b/src/models/inverter_models/inner_control_models.jl index 7f88c2c2d..fed883266 100644 --- a/src/models/inverter_models/inner_control_models.jl +++ b/src/models/inverter_models/inner_control_models.jl @@ -3,7 +3,7 @@ function mass_matrix_inner_entries!( inner_control::IC, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {IC <: PSY.InnerControl} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $IC" + @debug "Using default mass matrix entries $IC" return end diff --git a/src/models/inverter_models/outer_control_models.jl b/src/models/inverter_models/outer_control_models.jl index be5285621..968af222a 100644 --- a/src/models/inverter_models/outer_control_models.jl +++ b/src/models/inverter_models/outer_control_models.jl @@ -3,7 +3,7 @@ function mass_matrix_outer_entries!( outer_control::O, global_index::Base.ImmutableDict{Symbol, Int64}, ) where {O <: PSY.OuterControl} - CRC.@ignore_derivatives @debug "Using default mass matrix entries $O" + @debug "Using default mass matrix entries $O" end ##################################################### diff --git a/src/models/saturation_models.jl b/src/models/saturation_models.jl index 0a7cef89e..6e6d3ff28 100644 --- a/src/models/saturation_models.jl +++ b/src/models/saturation_models.jl @@ -176,14 +176,14 @@ function current_limit_logic( Ip_max = I_max end else - CRC.@ignore_derivatives @error "Unsupported value of PQ_Flag" + @error "Unsupported value of PQ_Flag" end if Gen_Flag == 1 Ip_min = 0 elseif Gen_Flag == 0 Ip_min = -Ip_max else - CRC.@ignore_derivatives @error "Unsupported value of Gen_Flag" + @error "Unsupported value of Gen_Flag" end Iq_min = -Iq_max return Ip_min, Ip_max, Iq_min, Iq_max diff --git a/src/post_processing/post_proc_generator.jl b/src/post_processing/post_proc_generator.jl index 1f3cfb26c..ceba942e2 100644 --- a/src/post_processing/post_proc_generator.jl +++ b/src/post_processing/post_proc_generator.jl @@ -528,7 +528,7 @@ function _field_current( res::SimulationResults, dt::Union{Nothing, Float64, Vector{Float64}}, ) where {M <: PSY.Machine} - CRC.@ignore_derivatives @warn( + @warn( "Field current is not supported in the machine type $(M). Returning zeros." ) ts, _ = post_proc_state_series(res, (name, :δ), dt) diff --git a/src/post_processing/post_proc_inverter.jl b/src/post_processing/post_proc_inverter.jl index 94cf9cf82..e1d517417 100644 --- a/src/post_processing/post_proc_inverter.jl +++ b/src/post_processing/post_proc_inverter.jl @@ -45,7 +45,7 @@ function compute_field_current( V_I::Vector{Float64}, dt::Union{Nothing, Float64, Vector{Float64}}, ) where {G <: PSY.DynamicInverter} - CRC.@ignore_derivatives @warn( + @warn( "Field current does not exist in inverters. Returning zeros." ) return (nothing, zeros(length(V_R))) @@ -61,7 +61,7 @@ function compute_field_voltage( dynamic_device::G, dt::Union{Nothing, Float64, Vector{Float64}}, ) where {G <: PSY.DynamicInverter} - CRC.@ignore_derivatives @warn( + @warn( "Field voltage does not exist in inverters. Returning zeros." ) _, state = _post_proc_state_series(res.solution, 1, dt) @@ -78,7 +78,7 @@ function compute_mechanical_torque( dynamic_device::G, dt::Union{Nothing, Float64, Vector{Float64}}, ) where {G <: PSY.DynamicInverter} - CRC.@ignore_derivatives @warn( + @warn( "Mechanical torque is not used in inverters. Returning zeros." ) _, state = _post_proc_state_series(res.solution, 1, dt) From 5fb081f002e5bacf5791aad2e214c8a6bfd8c0a5 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 5 Jun 2024 11:11:32 -0400 Subject: [PATCH 20/76] enzyme working without any initialization --- src/PowerSimulationsDynamics.jl | 9 +- src/base/sensitivity_analysis.jl | 290 +++++++++++++------------------ src/base/simulation.jl | 2 +- test/test_case_enzyme.jl | 195 +++++---------------- 4 files changed, 163 insertions(+), 333 deletions(-) diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index ae85bdb86..b596bcc91 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -61,9 +61,8 @@ export is_valid export transform_load_to_constant_impedance export transform_load_to_constant_current export transform_load_to_constant_power -#export get_parameter_values -#export get_forward_function -#export get_gradient_function +export get_parameter_values +export get_sensitivity_functions ####################################### Package Imports #################################### import Logging @@ -136,7 +135,6 @@ include("base/nlsolve_wrapper.jl") include("base/simulation_initialization.jl") include("base/small_signal.jl") include("base/model_validation.jl") -#include("base/sensitivity_analysis.jl") #Common Models include("models/branch.jl") @@ -197,6 +195,9 @@ include("post_processing/post_proc_results.jl") include("post_processing/post_proc_loads.jl") include("post_processing/post_proc_source.jl") +#Sensitivity Analysis +include("base/sensitivity_analysis.jl") + #Utils include("utils/psy_utils.jl") include("utils/immutable_dicts.jl") diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index cb6528d6e..89a896b07 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -1,190 +1,134 @@ -""" - function get_parameter_sensitivity_function!( - sim::Simulation, - device_parameter_pairs::Vector{Tuple{String, Type{T}, Symbol}}, - f::function, - ) - -Gets a function for taking gradients with respect to parameters. -# Arguments -- `sim::Simulation` : Initialized simulation object -- `device_parameter_pairs::Vector{Tuple{String, Type{T}, Symbol}}` : Tuple used to identify the parameter, via the device name, as a `String`, the type of the Device or DynamicComponent, and the parameter as a `Symbol`. -- `f::function` : User provided function with two inputs: a simulation and an additional input which can be used for data (```f(sim::Simulation, data::Any)```) The output must be a scalar value. This function can include executing the simulation and post-processing of results. - -# Example -```julia -function f(sim::Simulation) - execute!(sim, Rodas5()) - res = read_results(sim) - _, δ = get_state_series(res, ("generator-1", :δ)) - sum(δ) -end -g = get_parameter_sensitivity_function!(sim, ("generator-1", SingleMass, :H), f) -Zygote.gradient(g, [2.0]); -``` -""" -function get_parameter_sensitivity_function!(sim, device_param_pairs, f) - indices = get_indices_in_parameter_vector(sim, device_param_pairs) - if indices === nothing - return nothing - end - sim_level = get_required_initialization_level(sim, device_param_pairs) - if sim_level === nothing - return nothing - end - reset!(sim) - @assert sim.status == BUILT - sim.initialize_level = sim_level - sensitivity_function = (p, data) -> - begin - sim.inputs = deepcopy(sim.inputs_init) - set_parameters!(sim, indices, p) - reset!(sim) - return f(sim, data) - end - return sensitivity_function -end - -""" - function get_parameter_sensitivity_function!( - sim::Simulation, - device_parameter_pairs::Vector{Tuple{String, Type{T}, Symbol}}, - f::function, - ) - -get_parameter_sensitivity_values can be used in conjunction with get_parameter_sensitivity_function! to get the starting values of the parameters for taking gradients. - -# Arguments -- `sim::Simulation` : Initialized simulation object -- `device_parameter_pairs::Vector{Tuple{String, Type{T}, Symbol}}` : Tuple used to identify the parameter, via the device name, as a `String`, the type of the Device or DynamicComponent, and the parameter as a `Symbol`. - -# Example -```julia -function f(sim::Simulation) - execute!(sim, Rodas5()) - res = read_results(sim) - _, δ = get_state_series(res, ("generator-1", :δ)) - sum(δ) -end -g = get_parameter_sensitivity_function!(sim, ("generator-1", SingleMass, :H), f) -p = get_parameter_sensitivity_values(sim, ("generator-1", SingleMass, :H)) -Zygote.gradient(g, p); -``` -""" -function get_parameter_sensitivity_values(sim, device_param_pairs) - indices = get_indices_in_parameter_vector(sim, device_param_pairs) - param_vector = sim.inputs.parameters - return param_vector[indices] -end - -function _append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Device} - return s -end -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.AVR} = Symbol(s, :_AVR) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Machine} = Symbol(s, :_Machine) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.PSS} = Symbol(s, :_PSS) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Shaft} = Symbol(s, :_Shaft) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.TurbineGov} = Symbol(s, :_TurbineGov) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Converter} = Symbol(s, :_Converter) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.DCSource} = Symbol(s, :_DCSource) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.Filter} = Symbol(s, :_Filter) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.FrequencyEstimator} = - Symbol(s, :_FrequencyEstimator) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.InnerControl} = - Symbol(s, :_InnerControl) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.OuterControl} = - @error "Specify PSY.ActivePowerControl or PSY.ReactivePowerControl" -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.ActivePowerControl} = - Symbol(s, :_ActivePowerControl) -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.ReactivePowerControl} = - Symbol(s, :_ReactivePowerControl) - -_append_symbol(s::Symbol, ::Type{T}) where {T <: PSY.InverterLimiter} = - Symbol(s, :_InverterLimiter) - -function get_indices_in_parameter_vector(sim, device_param_pairs) +function get_indices_in_parameter_vector(p, device_param_pairs) indices = Int[] - for (device_name, component_type, param_symbol) in device_param_pairs - ix = findfirst( - x -> PSY.get_name(x.device) == device_name, - sim.inputs_init.dynamic_injectors, - ) - if ix !== nothing - wrapped_device = sim.inputs_init.dynamic_injectors[ix] - else - ix = findfirst( - x -> PSY.get_name(x.device) == device_name, - sim.inputs_init.static_injectors, - ) - if ix !== nothing - wrapped_device = sim.inputs_init.static_injectors[ix] - else - @warn "Device $device_name not found in dynamic or static injectors" - return nothing - end - end - full_symbol = _append_symbol(param_symbol, component_type) - external_ix = get_p_range(wrapped_device) - internal_ix = findfirst(isequal(full_symbol), get_params_symbol(wrapped_device)) - if internal_ix === nothing - @warn "Parameter :$param_symbol of $component_type not found." + for tuple in device_param_pairs + label = join((tuple[1], "params", tuple[2:end]...), ".") + ix = ComponentArrays.label2index(p, label)[1] + if ix === nothing + @error "Index not found for entry $tuple" return nothing end - global_ix = external_ix[internal_ix] - push!(indices, global_ix) - return indices + push!(indices, ix) end + return indices end -function get_required_initialization_level(sim, device_param_pairs) +function get_required_initialization_level(device_param_pairs) #Don't n eed the values. init_level = INITIALIZED - for (device_name, component_type, param_symbol) in device_param_pairs - metadata = get_params_metadata(component_type(nothing)) - symbols = [m.symbol for m in metadata] - full_symbol = _append_symbol(param_symbol, component_type) - ix = findfirst(isequal(full_symbol), symbols) - metadata_entry = metadata[ix] - if metadata_entry.in_mass_matrix == true - @warn "Parameter :$param_symbol of $component_type appears in mass matrix -- not supported" - return - end - if metadata_entry.in_network == true - @warn "Parameter :$param_symbol of $component_type appears in network -- not supported" - return - end - if metadata_entry.impacts_ic == true - @warn "Parameter :$param_symbol of $component_type appears in initialization -- not supported" - return - end - if metadata_entry.impacts_pf == true - @warn "Parameter :$param_symbol of $component_type impacts power flow -- not supported" - return - end - end + #TODO - check parameters and return appropriate init_level return init_level end -function make_buffer(a) - buf = Zygote.Buffer(a) - for i in eachindex(a) - buf[i] = a[i] +function get_indices_in_state_vector(sim, state_data) + @assert sim.results !== nothing + res = sim.results + global_state_index = get_global_index(res) + state_ixs = Vector{Int64}(undef, length(state_data)) + for (ix, ref) in enumerate(state_data) + if !haskey(global_state_index, ref[1]) + @error "$(keys(global_state_index))" + error("State $(ref[2]) device $(ref[1]) not found in the system. ") + end + state_ixs[ix] = get(global_state_index[ref[1]], ref[2], 0) end - return buf + return state_ixs end -function make_array(b) - return copy(b) +function get_parameter_values(sim, device_param_pairs) + p = sim.inputs.parameters + ixs = get_indices_in_parameter_vector(p, device_param_pairs) + if ixs === nothing + return nothing + else + return p[ixs] + end end -#TODO - try to go back to making simulation inputs mutable and not using Accessors.jl? -#https://fluxml.ai/Zygote.jl/latest/limitations/#mutable-structs-1 -#https://github.com/FluxML/Zygote.jl/issues/1127 -function set_parameters!(sim, indices, params) - inputs = sim.inputs - parameter_buffer = make_buffer(inputs.parameters) - for (ix, p) in zip(indices, params) - parameter_buffer[ix] = p +#TODO - think more carefully about how data should be included so it works with with Optimization API. +#TODO - avoid code repetition with _execute! by defining functions appropriately. +#TODO - extend for initialization - first for H... +#TODO - extend for parameters that require initialization. +function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; kwargs...) + init_level = get_required_initialization_level(param_data) + p = sim.inputs.parameters + param_ixs = get_indices_in_parameter_vector(p, param_data) + state_ixs = get_indices_in_state_vector(sim, state_data) + init_level = get_required_initialization_level(param_data) + sim_inputs = deepcopy(sim.inputs_init) + if get(kwargs, :auto_abstol, false) + cb = AutoAbstol(true, get(kwargs, :abstol, 1e-9)) + callbacks = + SciMLBase.CallbackSet((), tuple(push!(sim.callbacks, cb)...)) + else + callbacks = SciMLBase.CallbackSet((), tuple(sim.callbacks...)) + end + tstops = if !isempty(sim.tstops) + [sim.tstops[1] ÷ 2, sim.tstops...] #Note: Don't need to make a tuple because it is in ODEproblem. not a kwarg + else + [] + end + + prob_old = sim.problem + f_old = prob_old.f + f_new = SciMLBase.ODEFunction{true}( + f_old.f; + mass_matrix = f_old.mass_matrix, + ) + + prob_new = SciMLBase.remake( + prob_old; + f = f_new, + tstops = tstops, + advance_to_tstop = !isempty(tstops), + initializealg = SciMLBase.NoInit(), + callback = callbacks, + kwargs..., + ) + if param_ixs === nothing + return nothing + else + function f_enzyme(p, sim_inputs, prob, data) + p_new = sim_inputs.parameters + p_new[param_ixs] .= p + # TODO - INSERT APPROPRIATE INITIALIZATION HERE WHICH MODIFIES p - Add initialization_level as a (contstant) input? + prob_new = SciMLBase.remake(prob; p = p_new) + sol = SciMLBase.solve(prob_new, solver) + + @assert length(state_ixs) == 1 #Hardcode for single state for now + ix = state_ixs[1] + ix_t = unique(i -> sol.t[i], eachindex(sol.t)) + state = sol[ix, ix_t] + + return f_loss(state, data) + end + function f_forward(p, data) + f_enzyme( + p, + deepcopy(sim.inputs_init), + prob_new, + data, + ) + end + function f_grad(p, data) + dp = Enzyme.make_zero(p) + sim_inputs = deepcopy(sim.inputs_init) + dsim_inputs = Enzyme.make_zero(sim_inputs) + dprob_new = Enzyme.make_zero(prob_new) + ddata = Enzyme.make_zero(data) + Enzyme.autodiff( + Enzyme.Reverse, + f_enzyme, + Enzyme.Active, + Enzyme.Duplicated(p, dp), + Enzyme.Duplicated(sim_inputs, dsim_inputs), + Enzyme.Duplicated(prob_new, dprob_new), + Enzyme.Duplicated(data, ddata), + ) + return dp + end + f_forward, f_grad end - Accessors.@reset inputs.parameters = make_array(parameter_buffer) - sim.inputs = inputs end + +#Inactive Rules +#Enzyme.EnzymeRules.inactive(::typeof(SimulationResults), args...) = nothing +#Enzyme.EnzymeRules.inactive(::typeof(get_activepower_branch_flow), args...) = nothing diff --git a/src/base/simulation.jl b/src/base/simulation.jl index 1b5907156..ecab2a19d 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -236,7 +236,6 @@ function _build_inputs!(sim::Simulation{T}) where {T <: SimulationModel} simulation_system, sim.frequency_reference, ) - sim.inputs_init = deepcopy(sim.inputs) @debug "Simulation Inputs Created" return end @@ -456,6 +455,7 @@ function _build!(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} TimerOutputs.@timeit BUILD_TIMER "Make DiffEq Problem" begin _get_diffeq_problem(sim, model, jacobian) end + sim.inputs_init = deepcopy(sim.inputs) @info "Simulations status = $(sim.status)" else @error "The simulation couldn't be initialized correctly. Simulations status = $(sim.status)" diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index 9a026a394..ee13e0e1c 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -1,4 +1,3 @@ - """ Case 1: This case study defines a classical machine against an infinite bus. Sensitivitiy @@ -25,7 +24,7 @@ using PlotlyJS #BacksolveAdjoint prone to instabilities whenever the Lipschitz constant is sufficiently large (stiff equations, PDE discretizations, and many other contexts) #For ForwardDiffSensitivity, convert_tspan=true is needed for hybrid equations. -sim = Simulation( +sim = Simulation!( MassMatrixModel, omib_sys, pwd(), @@ -33,161 +32,47 @@ sim = Simulation( s_change, ) -#JULIA CRASHES - the problem has the Jacobian... -#= function f(p_in, sim ) - prob = sim.problem - prob_new = remake(prob, u0 = vcat(sim.problem.u0[1:end-1], p_in)) - #display(prob_new) - sol = solve(prob_new, Rodas4(), abstol =1e-9, reltol=1e-9) - u1 = [u[1] for u in sol.u] - #u6 = [u[6] for u in sol.u] - return sum(abs.(u1)) -end -p = [1.0000001] -f(p, sim) -dp = make_zero(p) -dsim = make_zero(sim) -#Would be huge if this works! -=# -#= prob = sim.problem -function f(p_in, prob_in ) - prob_new = remake(prob_in, u0 = vcat(prob_in.u0[1:end-1], p_in)) - sum(solve(prob_new, Rodas4(), abstol =1e-9, reltol=1e-9)) -end -p = [1.0000001] -f(p, prob) -dp_zygote = Zygote.gradient((p)->f(p, prob), p) =# +#GET GROUND TRUTH DATA +H_gt = + get_H(get_shaft(get_component(DynamicGenerator, omib_sys, "generator-102-1"))) +execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) +res = read_results(sim) +t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) -#THIS EXACT THING WORKS IF THE PROBLEM DOESN"T COME FROM A SIMULATION... -prob = sim.problem -ode_f = prob.f -new_f = ODEFunction( - ode_f.f; - mass_matrix = ode_f.mass_matrix, - jac = nothing, - tgrad = ode_f.tgrad, -) -new_prob = ODEProblem(new_f, prob.u0, prob.tspan, prob.p) -function f(p_in, prob_in) - prob_new = remake(prob_in; u0 = vcat(prob_in.u0[1:(end - 1)], p_in)) - sum(solve(prob_new, Rodas4(); abstol = 1e-9, reltol = 1e-9)) -end -p = [1.0000002] -f(p, new_prob) -dp = make_zero(p) -dprob = make_zero(new_prob) -Enzyme.autodiff(Reverse, f, Active, Duplicated(p, dp), Duplicated(new_prob, dprob)) #Would be huge if this works! -dp_zygote2 = Zygote.gradient((p) -> f(p, new_prob), p)[1] -dp -dp_zygote2 - -##Now pass in the full sim... -sim = Simulation( - MassMatrixModel, - omib_sys, - pwd(), - (0.0, 5.0), - s_change, -) -sim.problem.f.jac -prob = sim.problem -ode_f = prob.f -new_f = ODEFunction( - ode_f.f; - mass_matrix = ode_f.mass_matrix, - jac = nothing, - tgrad = ode_f.tgrad, -) -new_prob = ODEProblem(new_f, prob.u0, prob.tspan, prob.p) -sim.problem = new_prob -sim.problem.f.jac +#GET PARAMETER VALUES +p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) +#get_parameter_values(sim, [("InfBus", :X_th), ("generator-102-1", :Shaft, :H)]) +#get_parameter_values(sim, [("InfBus", :X_th)]) -#= #JULIA CRASHES... -#f2 = sim.problem.f.f #system model... Just a function. -function f(p_in, sim_in) - prob = sim_in.problem - #ode_f = prob.f - #new_f = ODEFunction{true}(f2)#; mass_matrix = ode_f.mass_matrix, jac = nothing, tgrad = ode_f.tgrad) - #new_prob = ODEProblem{true}(new_f, prob.u0, prob.tspan, prob.p) - prob_new = remake(prob, u0 = vcat(prob.u0[1:end-1], p_in)) - sum(solve(prob_new, Rodas4(), abstol =1e-9, reltol=1e-9)) +#DEFINE LOSS FUNCTION +function f_loss(δ, δ_gt) + #display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + return sum(abs.(δ - δ_gt)) end -p = [1.0000002] -f(p, sim) -dp = make_zero(p) -dsim= make_zero(sim) -Enzyme.autodiff(Reverse, f, Active, Duplicated(p, dp), Duplicated(sim, dsim)) #Would be huge if this works! -dp_zygote2 = Zygote.gradient((p)->f(p, sim), p)[1] -dp -dp_zygote2 -## =# -#PASS ONLY PROBLEM AND SIM INPUTS... In case it is some other part of Sim that causes the problem . -#= - fds -=# +#GET SENSITIVITY FUNCTIONS +f_forward, f_grad = get_sensitivity_functions( + sim, + [("generator-102-1", :Shaft, :H)], + [("generator-102-1", :δ)], + Rodas4(), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, +) -#= -@testset "Test Gradients - Mass Matrix no delays" begin - path = mktempdir() - try - sim = Simulation!( - MassMatrixModel, - omib_sys, - path, - (0.0, 5.0), - s_change, - ) - H_gt = - get_H(get_shaft(get_component(DynamicGenerator, omib_sys, "generator-102-1"))) - execute!(sim, Rodas5(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) - res = read_results(sim) - t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) - for solver in [FBDF(), Rodas5(), QNDF()] - for tol in [1e-6, 1e-9] - function f(sim, δ_gt) - execute!( - sim, - solver; - sensealg = ForwardDiffSensitivity(), - abstol = tol, - reltol = tol, - dtmax = 0.005, - saveat = 0.005, - ) - res = read_results(sim) - t, δ = get_state_series(res, ("generator-102-1", :δ)) - display(plot(scatter(; x = t, y = δ))) - return sum(abs.(δ - δ_gt)) - end - p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) - f_forward = - get_forward_function(f, sim, δ_gt, [("generator-102-1", :Shaft, :H)]) - @error p - @error f_forward([3.148]) - @error f_forward([3.0]) - #@error Enzyme.make_zero(sim) - f_grad = - get_gradient_function(f, sim, δ_gt, [("generator-102-1", :Shaft, :H)]) - f_grad([3.148]) - #f_grad = get_tradient_function - #p = PSID.get_parameter_sensitivity_values(sim, [("generator-102-1", SingleMass, :H)]) - #@error Zygote.gradient(g, [3.15])[1][1] - #= @test isapprox( - Zygote.gradient((p) -> g(p, δ_gt), [3.14])[1][1], - -8.0, - atol = 1.0, - ) - @test isapprox( - Zygote.gradient((p) -> g(p, δ_gt), [3.15])[1][1], - 8.0, - atol = 1.0, - ) =# - end - end - finally - @info("removing test files") - rm(path; force = true, recursive = true) - end -end - =# +loss_zero = f_forward(p, δ_gt) +loss_non_zero_1 = f_forward([3.2], δ_gt) +loss_non_zero_2 = f_forward(p, δ_gt .* 2) +@test loss_zero == 0.0 +@test loss_non_zero_1 != 0.0 +@test loss_non_zero_2 != 0.0 +grad_zero = f_grad(p, δ_gt) +grad_nonzero_1 = f_grad([3.14], δ_gt) +grad_nonzero_2 = f_grad([3.15], δ_gt) +@test isapprox(grad_zero[1], 0.0, atol = 1.0) +@test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) +@test isapprox(grad_nonzero_2[1], 8.0, atol = 1.0) From 42c210340c73641f51ad81067c61422d1ed36112 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 5 Jun 2024 13:00:32 -0400 Subject: [PATCH 21/76] add static_device to wrapper --- src/base/device_wrapper.jl | 24 +++++++----------------- src/base/simulation_initialization.jl | 6 +----- src/base/simulation_inputs.jl | 9 ++++++++- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index 4cf7dd935..5a826c304 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -32,10 +32,9 @@ status, and allocate the required indexes of the state space and parameter space """ struct DynamicWrapper{T <: PSY.DynamicInjection} device::T - reactive_power::Float64 system_base_power::Float64 system_base_frequency::Float64 - static_type::Type{<:PSY.StaticInjection} + static_device::PSY.StaticInjection bus_category::Type{<:BusCategory} connection_status::Base.RefValue{Float64} inner_vars_index::Vector{Int} @@ -49,10 +48,9 @@ struct DynamicWrapper{T <: PSY.DynamicInjection} function DynamicWrapper( device::T, - reactive_power::Float64, system_base_power::Float64, system_base_frequency::Float64, - static_type::Type{<:PSY.StaticInjection}, + static_device::PSY.StaticInjection, bus_category::Type{<:BusCategory}, connection_status::Base.RefValue{Float64}, inner_vars_index, @@ -68,10 +66,9 @@ struct DynamicWrapper{T <: PSY.DynamicInjection} new{T}( device, - reactive_power, system_base_power, system_base_frequency, - static_type, + static_device, bus_category, connection_status, Vector{Int}(inner_vars_index), @@ -119,18 +116,11 @@ function DynamicWrapper( device_states = PSY.get_states(dynamic_device) component_state_mapping, input_port_mapping = state_port_mappings(dynamic_device, device_states) - # Consider the special case when the static device is StandardLoad - if isa(static_device, PSY.StandardLoad) - reactive_power = PF.get_total_q(static_device) - else - reactive_power = PSY.get_reactive_power(static_device) - end return DynamicWrapper( dynamic_device, - reactive_power, sys_base_power, sys_base_freq, - T, + static_device, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), inner_var_range, @@ -174,7 +164,7 @@ function DynamicWrapper( dynamic_device, sys_base_power, sys_base_freq, - PSY.ThermalStandard, + static_device, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), inner_var_range, @@ -216,7 +206,7 @@ function DynamicWrapper( dynamic_device, sys_base_power, sys_base_freq, - PSY.Source, + static_device, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], Base.Ref(1.0), collect(inner_var_range), @@ -254,7 +244,7 @@ function _index_port_mapping!( end get_device(wrapper::DynamicWrapper) = wrapper.device -get_reactive_power(wrapper::DynamicWrapper) = wrapper.reactive_power +get_static_device(wrapper::DynamicWrapper) = wrapper.static_device get_device_type(::DynamicWrapper{T}) where {T <: PSY.DynamicInjection} = T get_bus_category(wrapper::DynamicWrapper) = wrapper.bus_category get_inner_vars_index(wrapper::DynamicWrapper) = wrapper.inner_vars_index diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index 8c6a5599a..1e27b4f1b 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -42,11 +42,7 @@ function initialize_dynamic_injection!( initial_inner_vars = zeros(get_inner_vars_count(inputs)) parameters = get_parameters(inputs) for dynamic_device in get_dynamic_injectors(inputs) - static = PSY.get_component( - dynamic_device.static_type, - system, - PSY.get_name(dynamic_device), - ) + static = get_static_device(dynamic_device) @debug "Initializing $(PSY.get_name(dynamic_device)) - $(typeof(dynamic_device.device))" _inner_vars = @view initial_inner_vars[get_inner_vars_index(dynamic_device)] _parameters = @view parameters[_get_wrapper_name(dynamic_device)] diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index c4472ba0f..1fbd7a4e5 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -184,11 +184,18 @@ function _add_parameters(initial_parameters, wrapped_devices) p = get_params(wrapped_device) name = _get_wrapper_name(wrapped_device) if isa(wrapped_device, DynamicWrapper) + # Consider the special case when the static device is StandardLoad + static_device = get_static_device(wrapped_device) + if isa(static_device, PSY.StandardLoad) + reactive_power = PF.get_total_q(static_device) + else + reactive_power = PSY.get_reactive_power(static_device) + end refs = ( V_ref = PSY.get_V_ref(get_device(wrapped_device)), ω_ref = PSY.get_ω_ref(get_device(wrapped_device)), P_ref = PSY.get_P_ref(get_device(wrapped_device)), - Q_ref = get_reactive_power(wrapped_device), + Q_ref = reactive_power, ) elseif isa(wrapped_device, StaticWrapper) device = get_device(wrapped_device) From 32d979fbff46e2bb4505c89f907c47bea73270d0 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Fri, 7 Jun 2024 11:20:10 -0400 Subject: [PATCH 22/76] 4 tests passing --- src/base/sensitivity_analysis.jl | 25 ++++++-- src/base/simulation.jl | 8 ++- src/base/simulation_initialization.jl | 89 +++++++++++++++------------ 3 files changed, 76 insertions(+), 46 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 89a896b07..e6da6e488 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -12,7 +12,7 @@ function get_indices_in_parameter_vector(p, device_param_pairs) return indices end -function get_required_initialization_level(device_param_pairs) #Don't n eed the values. +function get_required_initialization_level(sys, device_param_pairs) init_level = INITIALIZED #TODO - check parameters and return appropriate init_level return init_level @@ -48,11 +48,11 @@ end #TODO - extend for initialization - first for H... #TODO - extend for parameters that require initialization. function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; kwargs...) - init_level = get_required_initialization_level(param_data) + init_level = get_required_initialization_level(sim.sys, param_data) p = sim.inputs.parameters param_ixs = get_indices_in_parameter_vector(p, param_data) state_ixs = get_indices_in_state_vector(sim, state_data) - init_level = get_required_initialization_level(param_data) + init_level = get_required_initialization_level(sim.sys, param_data) sim_inputs = deepcopy(sim.inputs_init) if get(kwargs, :auto_abstol, false) cb = AutoAbstol(true, get(kwargs, :abstol, 1e-9)) @@ -86,11 +86,18 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; if param_ixs === nothing return nothing else - function f_enzyme(p, sim_inputs, prob, data) + x0 = deepcopy(sim.x0_init) + sys = deepcopy(sim.sys) + function f_enzyme(p, x0, sys, sim_inputs, prob, data) p_new = sim_inputs.parameters p_new[param_ixs] .= p - # TODO - INSERT APPROPRIATE INITIALIZATION HERE WHICH MODIFIES p - Add initialization_level as a (contstant) input? - prob_new = SciMLBase.remake(prob; p = p_new) + _initialize_state_space( + x0, + sim_inputs, + sys, + Val(init_level), + ) + prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) sol = SciMLBase.solve(prob_new, solver) @assert length(state_ixs) == 1 #Hardcode for single state for now @@ -103,6 +110,8 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; function f_forward(p, data) f_enzyme( p, + x0, + sys, deepcopy(sim.inputs_init), prob_new, data, @@ -110,6 +119,8 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; end function f_grad(p, data) dp = Enzyme.make_zero(p) + dx0 = Enzyme.make_zero(x0) + dsys = Enzyme.make_zero(sys) sim_inputs = deepcopy(sim.inputs_init) dsim_inputs = Enzyme.make_zero(sim_inputs) dprob_new = Enzyme.make_zero(prob_new) @@ -119,6 +130,8 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; f_enzyme, Enzyme.Active, Enzyme.Duplicated(p, dp), + Enzyme.Duplicated(x0, dx0), + Enzyme.Duplicated(sys, dsys), Enzyme.Duplicated(sim_inputs, dsim_inputs), Enzyme.Duplicated(prob_new, dprob_new), Enzyme.Duplicated(data, ddata), diff --git a/src/base/simulation.jl b/src/base/simulation.jl index ecab2a19d..b7efec8d8 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -249,9 +249,13 @@ function _get_flat_start(inputs::SimulationInputs) end function _pre_initialize_simulation!(sim::Simulation) - _initialize_state_space(sim, Val(sim.initialize_level)) + sys = get_system(sim) + inputs = get_simulation_inputs(sim) + @assert sim.status == BUILD_INCOMPLETE + sim.x0 = _get_starting_initialization(sim, inputs, Val(sim.initialize_level)) + sim.status = _initialize_state_space(sim.x0, inputs, sys, Val(sim.initialize_level)) return -end +end function _get_jacobian(sim::Simulation{ResidualModel}) inputs = get_simulation_inputs(sim) diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index 1e27b4f1b..6d0d309fa 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -36,7 +36,6 @@ end function initialize_dynamic_injection!( initial_guess::AbstractArray, inputs::SimulationInputs, - system::PSY.System, ) @debug "Updating Dynamic Injection Component Initial Guess" initial_inner_vars = zeros(get_inner_vars_count(inputs)) @@ -125,69 +124,85 @@ function set_Q_ref!(array, value) @view(array["refs"])["Q_ref"] = value end +function _get_starting_initialization( + sim::Simulation, + inputs::SimulationInputs, + ::Union{Val{POWERFLOW_AND_DEVICES}, Val{FLAT_START}}, +) + return _get_flat_start(inputs) +end + +function _get_starting_initialization( + sim::Simulation, + inputs::SimulationInputs, + ::Union{Val{DEVICES_ONLY}, Val{INITIALIZED}}, +) + return deepcopy(sim.x0_init) +end + # Default implementation for both models. This implementation is to future proof if there is # a divergence between the required build methods -#PASS x0 and inputs, but not the full simulation not sim....? function _initialize_state_space( - sim::Simulation{T}, + x0::AbstractArray, + inputs::SimulationInputs, + sys::PSY.System, ::Val{POWERFLOW_AND_DEVICES}, -) where {T <: SimulationModel} - inputs = get_simulation_inputs(sim) - sim.x0 = _get_flat_start(inputs) +) + #x0 = _get_flat_start(inputs) @info("Pre-Initializing Simulation States") - @assert sim.status == BUILD_INCOMPLETE - while sim.status == BUILD_INCOMPLETE + status = BUILD_INCOMPLETE + while status == BUILD_INCOMPLETE @debug "Start state intialization routine" - sim.status = power_flow_solution!(sim.x0, get_system(sim), inputs) - sim.status = initialize_static_injection!(inputs) - sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) + status = power_flow_solution!(x0, sys, inputs) + status = initialize_static_injection!(inputs) + status = initialize_dynamic_injection!(x0, inputs) if has_dyn_lines(inputs) - sim.status = initialize_dynamic_branches!(sim.x0, inputs) + status = initialize_dynamic_branches!(x0, inputs) else @debug "No Dynamic Branches in the system" end - sim.status = check_valid_values(sim.x0, inputs) + status = check_valid_values(x0, inputs) end + return status end -#GET rid of try catch at that level. -#GET rid of timing at that level function _initialize_state_space( - sim::Simulation{T}, + x0::AbstractArray, + inputs::SimulationInputs, + sys::PSY.System, ::Val{DEVICES_ONLY}, -) where {T <: SimulationModel} +) @info("Pre-Initializing Simulation States") - inputs = get_simulation_inputs(sim) - #GET INNER VARS, PARAMETERS, AND STATES AT THIS LEVEL ... - @assert sim.status == BUILD_INCOMPLETE - while sim.status == BUILD_INCOMPLETE + status = BUILD_INCOMPLETE + while status == BUILD_INCOMPLETE @debug "Start state intialization routine" - sim.status = initialize_static_injection!(inputs) - sim.status = initialize_dynamic_injection!(sim.x0, inputs, get_system(sim)) + status = initialize_static_injection!(inputs) + status = initialize_dynamic_injection!(x0, inputs) if has_dyn_lines(inputs) - sim.status = initialize_dynamic_branches!(sim.x0, inputs) + status = initialize_dynamic_branches!(x0, inputs) else @debug "No Dynamic Branches in the system" end - sim.status = check_valid_values(sim.x0, inputs) + status = check_valid_values(x0, inputs) end + return status end function _initialize_state_space( - sim::Simulation{T}, + x0::AbstractArray, + inputs::SimulationInputs, + sys::PSY.System, ::Val{FLAT_START}, -) where {T <: SimulationModel} - simulation_inputs = get_simulation_inputs(sim) - sim.x0 = _get_flat_start(simulation_inputs) +) end function _initialize_state_space( - sim::Simulation{T}, + x0::AbstractArray, + inputs::SimulationInputs, + sys::PSY.System, ::Val{INITIALIZED}, -) where {T <: SimulationModel} - simulation_inputs = get_simulation_inputs(sim) - @assert sim.status == BUILD_INCOMPLETE - if length(sim.x0) != get_variable_count(simulation_inputs) +) + if length(x0) != get_variable_count(inputs) throw( IS.ConflictingInputsError( "The size of the provided initial state space does not match the model's state space.", @@ -197,9 +212,7 @@ function _initialize_state_space( @warn( "Using existing initial conditions value for simulation initialization" ) - sim.x0 = deepcopy(sim.x0_init) - sim.status = SIMULATION_INITIALIZED - return + return SIMULATION_INITIALIZED end """ @@ -264,7 +277,7 @@ function set_operating_point!( while status == BUILD_INCOMPLETE status = power_flow_solution!(x0_init, system, inputs) status = initialize_static_injection!(inputs) - status = initialize_dynamic_injection!(x0_init, inputs, system) + status = initialize_dynamic_injection!(x0_init, inputs) status = initialize_dynamic_branches!(x0_init, inputs) status = SIMULATION_INITIALIZED end From 3d6e18ef71890cd0ebe919153291cc16c29b3178 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 11 Jun 2024 16:50:07 -0400 Subject: [PATCH 23/76] specify in place --- src/base/nlsolve_wrapper.jl | 31 ++----------------- .../init_frequency_estimator.jl | 2 +- .../inverter_components/init_inner.jl | 2 +- 3 files changed, 5 insertions(+), 30 deletions(-) diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index 19a101d99..5f430ddb4 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -44,7 +44,7 @@ function _nlsolve_call( show_trace::Bool, ) f = SciMLBase.NonlinearFunction(f_eval; jac = jacobian) - prob = NonlinearSolve.NonlinearProblem(f, initial_guess, p) + prob = NonlinearSolve.NonlinearProblem{true}(f, initial_guess, p) sol = NonlinearSolve.solve( prob, solver; @@ -131,7 +131,6 @@ function refine_initial_condition!( sim::Simulation, model::SystemModel, jacobian::JacobianFunctionWrapper, - ::Val{POWERFLOW_AND_DEVICES}, ) @assert sim.status != BUILD_INCOMPLETE converged = false @@ -182,8 +181,8 @@ function refine_initial_condition!( _check_residual(residual, inputs, MINIMAL_ACCEPTABLE_NLSOLVE_F_TOLERANCE) @warn( "Initialization didn't found a solution to desired tolerances.\\ -Initial conditions do not meet conditions for an stable equilibrium. \\ -Simulation might fail" + Initial conditions do not meet conditions for an stable equilibrium. \\ + Simulation might fail" ) end @@ -193,27 +192,3 @@ Simulation might fail" end return end - -function refine_initial_condition!( - sim::Simulation, - model::SystemModel, - jacobian::JacobianFunctionWrapper, - ::Val{DEVICES_ONLY}, -) - refine_initial_condition!(sim, model, jacobian, Val(POWERFLOW_AND_DEVICES)) -end - -function refine_initial_condition!( - sim::Simulation, - model::SystemModel, - jacobian::JacobianFunctionWrapper, - ::Val{FLAT_START}, -) -end -function refine_initial_condition!( - sim::Simulation, - model::SystemModel, - jacobian::JacobianFunctionWrapper, - ::Val{INITIALIZED}, -) -end diff --git a/src/initialization/inverter_components/init_frequency_estimator.jl b/src/initialization/inverter_components/init_frequency_estimator.jl index 3d00db073..8a2e02d79 100644 --- a/src/initialization/inverter_components/init_frequency_estimator.jl +++ b/src/initialization/inverter_components/init_frequency_estimator.jl @@ -43,7 +43,7 @@ function initialize_frequency_estimator!( end x0 = [Vpll_d0, Vpll_q0, ϵ_pll0, θ0_pll] - prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); diff --git a/src/initialization/inverter_components/init_inner.jl b/src/initialization/inverter_components/init_inner.jl index 54ac6d4fb..98aa36aba 100644 --- a/src/initialization/inverter_components/init_inner.jl +++ b/src/initialization/inverter_components/init_inner.jl @@ -100,7 +100,7 @@ function initialize_inner!( out[8] = Vq_cnv_ref - V_dq_cnv0[q] end x0 = [θ0_oc, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); From ca9eb9d56ca960eff490092d743fd83c193a96e6 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 11 Jun 2024 16:52:52 -0400 Subject: [PATCH 24/76] re-init working for OMIB case (H) --- src/base/sensitivity_analysis.jl | 20 +++++--- src/base/simulation.jl | 40 +++++++++++---- src/base/simulation_initialization.jl | 50 +------------------ .../generator_components/init_avr.jl | 4 +- .../generator_components/init_machine.jl | 13 +++-- .../generator_components/init_tg.jl | 2 +- src/initialization/init_device.jl | 2 +- .../inverter_components/init_filter.jl | 2 +- 8 files changed, 56 insertions(+), 77 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index e6da6e488..eab78981f 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -88,16 +88,18 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; else x0 = deepcopy(sim.x0_init) sys = deepcopy(sim.sys) - function f_enzyme(p, x0, sys, sim_inputs, prob, data) + function f_enzyme(p, x0, sys, sim_inputs, prob, data, init_level) #Make separate f_enzymes depending on init_level? p_new = sim_inputs.parameters p_new[param_ixs] .= p - _initialize_state_space( - x0, - sim_inputs, - sys, - Val(init_level), - ) - prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) + if init_level == POWERFLOW_AND_DEVICES + @error "POWERFLOW AND DEVICES -- not yet supported" + #_initialize_powerflow_and_devices!(x0, inputs, sys) + elseif init_level == DEVICES_ONLY + @error "DEVICES ONLY" + elseif init_level == INITIALIZED + _initialize_devices_only!(x0, sim_inputs) + end + prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) sol = SciMLBase.solve(prob_new, solver) @assert length(state_ixs) == 1 #Hardcode for single state for now @@ -115,6 +117,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; deepcopy(sim.inputs_init), prob_new, data, + init_level, ) end function f_grad(p, data) @@ -135,6 +138,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; Enzyme.Duplicated(sim_inputs, dsim_inputs), Enzyme.Duplicated(prob_new, dprob_new), Enzyme.Duplicated(data, ddata), + Enzyme.Const(init_level), ) return dp end diff --git a/src/base/simulation.jl b/src/base/simulation.jl index b7efec8d8..32ac693b2 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -252,10 +252,30 @@ function _pre_initialize_simulation!(sim::Simulation) sys = get_system(sim) inputs = get_simulation_inputs(sim) @assert sim.status == BUILD_INCOMPLETE - sim.x0 = _get_starting_initialization(sim, inputs, Val(sim.initialize_level)) - sim.status = _initialize_state_space(sim.x0, inputs, sys, Val(sim.initialize_level)) + if sim.initialize_level == POWERFLOW_AND_DEVICES + sim.x0 = _get_flat_start(inputs) + sim.status = _initialize_powerflow_and_devices!(sim.x0, inputs, sys) + elseif sim.initialize_level == DEVICE_ONLY + sim.x0 = deepcopy(sim.x0_init) + sim.status = _initialize_devices_only!(sim.x0, inputs) + elseif sim.initialize_level == FLAT_START + sim.x0 = _get_flat_start(inputs) + elseif sim.initialize_level == INITILAIZED + sim.x0 = deepcopy(sim.x0_init) + if length(x0) != get_variable_count(inputs) + throw( + IS.ConflictingInputsError( + "The size of the provided initial state space does not match the model's state space.", + ), + ) + end + @warn( + "Using existing initial conditions value for simulation initialization" + ) + sim.status = SIMULATION_INITIALIZED + end return -end +end function _get_jacobian(sim::Simulation{ResidualModel}) inputs = get_simulation_inputs(sim) @@ -446,12 +466,14 @@ function _build!(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} model = T(simulation_inputs, get_x0(sim), SimCache) end TimerOutputs.@timeit BUILD_TIMER "Initial Condition NLsolve refinement" begin - refine_initial_condition!( - sim, - model, - jacobian, - Val(sim.initialize_level), - ) + if (sim.initialize_level == POWERFLOW_AND_DEVICES) || + (sim.initialize_level == DEVICES_ONLY) + refine_initial_condition!( + sim, + model, + jacobian, + ) + end end TimerOutputs.@timeit BUILD_TIMER "Build Perturbations" begin _build_perturbations!(sim) diff --git a/src/base/simulation_initialization.jl b/src/base/simulation_initialization.jl index 6d0d309fa..02e3abf06 100644 --- a/src/base/simulation_initialization.jl +++ b/src/base/simulation_initialization.jl @@ -124,29 +124,12 @@ function set_Q_ref!(array, value) @view(array["refs"])["Q_ref"] = value end -function _get_starting_initialization( - sim::Simulation, - inputs::SimulationInputs, - ::Union{Val{POWERFLOW_AND_DEVICES}, Val{FLAT_START}}, -) - return _get_flat_start(inputs) -end - -function _get_starting_initialization( - sim::Simulation, - inputs::SimulationInputs, - ::Union{Val{DEVICES_ONLY}, Val{INITIALIZED}}, -) - return deepcopy(sim.x0_init) -end - # Default implementation for both models. This implementation is to future proof if there is # a divergence between the required build methods -function _initialize_state_space( +function _initialize_powerflow_and_devices!( x0::AbstractArray, inputs::SimulationInputs, sys::PSY.System, - ::Val{POWERFLOW_AND_DEVICES}, ) #x0 = _get_flat_start(inputs) @info("Pre-Initializing Simulation States") @@ -166,11 +149,9 @@ function _initialize_state_space( return status end -function _initialize_state_space( +function _initialize_devices_only!( x0::AbstractArray, inputs::SimulationInputs, - sys::PSY.System, - ::Val{DEVICES_ONLY}, ) @info("Pre-Initializing Simulation States") status = BUILD_INCOMPLETE @@ -188,33 +169,6 @@ function _initialize_state_space( return status end -function _initialize_state_space( - x0::AbstractArray, - inputs::SimulationInputs, - sys::PSY.System, - ::Val{FLAT_START}, -) -end - -function _initialize_state_space( - x0::AbstractArray, - inputs::SimulationInputs, - sys::PSY.System, - ::Val{INITIALIZED}, -) - if length(x0) != get_variable_count(inputs) - throw( - IS.ConflictingInputsError( - "The size of the provided initial state space does not match the model's state space.", - ), - ) - end - @warn( - "Using existing initial conditions value for simulation initialization" - ) - return SIMULATION_INITIALIZED -end - """ Returns a Dictionary with the resulting initial conditions of the simulation """ diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index c500605ef..bc7da15f3 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -75,7 +75,7 @@ function initialize_avr!( out[3] = (Kf / Tf) * Vf0 + Vr2 #16.12b end x0 = [1.0, Vf0, Vf0] - prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); @@ -326,7 +326,7 @@ function initialize_avr!( out[2] = V_in * (1 - Ta_Tb) - Vr end x0 = [1.0, Vf0] - prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index 20446fd8e..94669cf80 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -31,13 +31,12 @@ function initialize_mach_shaft!( τm0 = real(V * conj(I)) @assert isapprox(τm0, P0; atol = STRICT_NLSOLVE_F_TOLERANCE) τm0, P0 #To solve: δ, τm, Vf0 - function f!(out, x, params) + p_nl = [R, Xd_p, V_R, V_I, P0, Q0] + function f!(out, x, p_nl) δ = x[1] τm = x[2] Vf0 = x[3] - - R = params[:R] - Xd_p = params[:Xd_p] + R, Xd_p, V_R, V_I, P0, Q0 = p_nl V_dq = ri_dq(δ) * [V_R; V_I] i_d = (1.0 / (R^2 + Xd_p^2)) * (Xd_p * (Vf0 - V_dq[2]) - R * V_dq[1]) #15.36 i_q = (1.0 / (R^2 + Xd_p^2)) * (Xd_p * V_dq[1] + R * (Vf0 - V_dq[2])) #15.36 @@ -47,7 +46,7 @@ function initialize_mach_shaft!( out[3] = Q0 - (V_dq[2] * i_d - V_dq[1] * i_q) #Output Reactive Power end x0 = [δ0, τm0, 1.0] - prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, p_nl) sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); @@ -138,7 +137,7 @@ function initialize_mach_shaft!( end V_dq0 = ri_dq(δ0) * [V_R; V_I] x0 = [δ0, τm0, 1.0, V_dq0[2], V_dq0[1]] - prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); @@ -829,7 +828,7 @@ function initialize_mach_shaft!( end x0 = [δ0, τm0, Vf0, eq_p0, ed_p0, ψ_kd0, ψ_kq0, Xad_Ifd0] - prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index f530522db..4d32c6800 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -245,7 +245,7 @@ function initialize_tg!( out[3] = (Pm - D_T * Δω) - τm0 end x0 = [1.0 / inv_R, τm0, τm0] - prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index ebebe8048..a59f10722 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -85,7 +85,7 @@ function initialize_static_device!( R_th * (V_I_internal - V_I) / Zmag - X_th * (V_R_internal - V_R) / Zmag - I_I end x0 = [V_R, V_I] - prob = NonlinearSolve.NonlinearProblem(f!, x0, params) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); diff --git a/src/initialization/inverter_components/init_filter.jl b/src/initialization/inverter_components/init_filter.jl index 2eb766053..bb23df773 100644 --- a/src/initialization/inverter_components/init_filter.jl +++ b/src/initialization/inverter_components/init_filter.jl @@ -58,7 +58,7 @@ function initialize_filter!( out[6] = Vi_filter - V_I - rg * Ii_filter - ω_sys * lg * Ir_filter end x0 = [V_R, V_I, Ir_filter, Ii_filter, V_R, V_I] - prob = NonlinearSolve.NonlinearProblem(f!, x0, p) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, p) sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); From bc26b911b0dd8d194f9b78f59dd9ca1a411e189d Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 11 Jun 2024 17:17:47 -0400 Subject: [PATCH 25/76] make wrappers mutable --- src/base/branch_wrapper.jl | 6 +++--- src/base/device_wrapper.jl | 20 ++++++++++---------- test/runtests.jl | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/base/branch_wrapper.jl b/src/base/branch_wrapper.jl index 9b96d733f..8596718c6 100644 --- a/src/base/branch_wrapper.jl +++ b/src/base/branch_wrapper.jl @@ -2,11 +2,11 @@ Wraps DynamicBranch devices from PowerSystems to handle changes in controls and connection status, and allocate the required indexes of the state space. """ -struct BranchWrapper +mutable struct BranchWrapper branch::PSY.DynamicBranch system_base_power::Float64 system_base_frequency::Float64 - connection_status::Base.RefValue{Float64} + connection_status::Float64 bus_ix_from::Int bus_ix_to::Int ix_range::Vector{Int} @@ -26,7 +26,7 @@ struct BranchWrapper branch, sys_base_power, sys_base_freq, - Base.Ref(1.0), + 1.0, bus_ix_from, bus_ix_to, ix_range, diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index 5a826c304..d1a226c25 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -30,13 +30,13 @@ get_delays( Wraps DynamicInjection devices from PowerSystems to handle changes in controls and connection status, and allocate the required indexes of the state space and parameter space. """ -struct DynamicWrapper{T <: PSY.DynamicInjection} +mutable struct DynamicWrapper{T <: PSY.DynamicInjection} device::T system_base_power::Float64 system_base_frequency::Float64 static_device::PSY.StaticInjection bus_category::Type{<:BusCategory} - connection_status::Base.RefValue{Float64} + connection_status::Float64 inner_vars_index::Vector{Int} ix_range::Vector{Int} ode_range::Vector{Int} @@ -52,7 +52,7 @@ struct DynamicWrapper{T <: PSY.DynamicInjection} system_base_frequency::Float64, static_device::PSY.StaticInjection, bus_category::Type{<:BusCategory}, - connection_status::Base.RefValue{Float64}, + connection_status::Float64, inner_vars_index, ix_range, ode_range, @@ -122,7 +122,7 @@ function DynamicWrapper( sys_base_freq, static_device, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], - Base.Ref(1.0), + 1.0, inner_var_range, ix_range, ode_range, @@ -166,7 +166,7 @@ function DynamicWrapper( sys_base_freq, static_device, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], - Base.Ref(1.0), + 1.0, inner_var_range, ix_range, ode_range, @@ -208,7 +208,7 @@ function DynamicWrapper( sys_base_freq, static_device, BUS_MAP[PSY.get_bustype(PSY.get_bus(static_device))], - Base.Ref(1.0), + 1.0, collect(inner_var_range), collect(ix_range), collect(ode_range), @@ -328,9 +328,9 @@ function get_input_port_ix(wrapper::DynamicWrapper, ::T) where {T <: PSY.Dynamic return get_input_port_ix(wrapper, T) end -struct StaticWrapper{T <: PSY.StaticInjection, V} +mutable struct StaticWrapper{T <: PSY.StaticInjection, V} device::T - connection_status::Base.RefValue{Float64} + connection_status::Float64 bus_ix::Int ext::Dict{String, Any} end @@ -339,7 +339,7 @@ function DynamicWrapper(device::T, bus_ix::Int) where {T <: PSY.Device} bus = PSY.get_bus(device) StaticWrapper{T, BUS_MAP[PSY.get_bustype(bus)]}( device, - Base.Ref(1.0), + 1.0, Vector{Int}(), bus_ix, Dict{String, Any}(), @@ -350,7 +350,7 @@ function StaticWrapper(device::T, bus_ix::Int) where {T <: PSY.Source} bus = PSY.get_bus(device) return StaticWrapper{T, BUS_MAP[PSY.get_bustype(bus)]}( device, - Base.Ref(1.0), + 1.0, bus_ix, Dict{String, Any}(), ) diff --git a/test/runtests.jl b/test/runtests.jl index e1a8766e4..856a0c46b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -108,7 +108,7 @@ function get_logging_level(env_name::String, default) end function run_tests() - console_level = get_logging_level("SYS_CONSOLE_LOG_LEVEL", "Error") + console_level = get_logging_level("SYS_CONSOLE_LOG_LEVEL", "Debug") console_logger = ConsoleLogger(stderr, console_level) file_level = get_logging_level("SYS_LOG_LEVEL", "Info") From 7bf1f14f41ecef0bbda48dcf85f1475117e775a3 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 24 Jun 2024 08:13:26 -0400 Subject: [PATCH 26/76] parameters that require reinitialization --- Project.toml | 2 +- src/PowerSimulationsDynamics.jl | 3 +- src/base/nlsolve_wrapper.jl | 28 ++++ src/base/sensitivity_analysis.jl | 46 ++++-- src/base/simulation_inputs.jl | 93 +++++++++++- src/utils/parameters.jl | 247 ++++++++++++++++--------------- test/test_case_enzyme.jl | 154 +++++++++++++------ 7 files changed, 394 insertions(+), 179 deletions(-) diff --git a/Project.toml b/Project.toml index c656355a5..9a7d1de68 100644 --- a/Project.toml +++ b/Project.toml @@ -31,7 +31,7 @@ ComponentArrays = "0.15" DataFrames = "1" DataStructures = "~0.18" DocStringExtensions = "~0.9" -Enzyme = "0.12" +Enzyme = "<0.12.17" FastClosures = "^0.3" ForwardDiff = "~v0.10" InfrastructureSystems = "^1.21" diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index b596bcc91..8361316a6 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -75,6 +75,7 @@ import ForwardDiff import SparseArrays import LinearAlgebra import Base.to_index +import Base.length import NonlinearSolve import PrettyTables import Base.ImmutableDict @@ -121,6 +122,7 @@ include("base/device_wrapper.jl") include("base/branch_wrapper.jl") include("base/frequency_reference.jl") include("base/simulation_model.jl") +include("utils/parameters.jl") include("base/simulation_inputs.jl") include("base/perturbations.jl") include("base/caches.jl") @@ -204,6 +206,5 @@ include("utils/immutable_dicts.jl") include("utils/print.jl") include("utils/kwargs_check.jl") include("utils/logging.jl") -include("utils/parameters.jl") end # module diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index 5f430ddb4..03716f400 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -127,6 +127,34 @@ function _check_residual( return end +function _refine_initial_condition!(x0, p, prob) + function ff(u, x0, p) + prob.f.f(u, x0, p, 0.0) + end + #residual = similar(x0) + #ff(residual, x0, p) #Error: ERROR: AssertionError: length(getcolptr(S)) == size(S, 2) + 1 && (getcolptr(S))[end] - 1 == length(rowvals(S)) == length(nonzeros(S)) + #_check_residual(residual, inputs, MAX_INIT_RESIDUAL) + solver = NonlinearSolve.TrustRegion() + probnl = NonlinearSolve.NonlinearProblem{true}(ff, x0, p) + #for tol in [STRICT_NLSOLVE_F_TOLERANCE, RELAXED_NLSOLVE_F_TOLERANCE] #ERROR: Enzyme execution failed., Enzyme: Non-constant keyword argument found for Tuple{UInt64, typeof(Core.kwcall), Duplicated{@NamedTuple{reltol::Float64, abstol::Float64}}, + for solver in [NonlinearSolve.TrustRegion(), NonlinearSolve.NewtonRaphson()] + sol = NonlinearSolve.solve( + probnl, + solver; + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + maxiters = MAX_NLSOLVE_INTERATIONS, + ) + converged = SciMLBase.successful_retcode(sol) + x0 .= sol.u + if converged + break + end + end + #end + return nothing +end + function refine_initial_condition!( sim::Simulation, model::SystemModel, diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index eab78981f..b9cb415a3 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -12,10 +12,31 @@ function get_indices_in_parameter_vector(p, device_param_pairs) return indices end -function get_required_initialization_level(sys, device_param_pairs) - init_level = INITIALIZED - #TODO - check parameters and return appropriate init_level - return init_level +function get_required_initialization_level(p_metadata, param_ixs) + #Check for invalid parameters + for metadata_entry in p_metadata[param_ixs] + if metadata_entry.type === DEVICE_SETPOINT + @error "The parameter given is unsupported because it is a device setpoint." + return nothing + end + if metadata_entry.in_mass_matrix === DEVICE_SETPOINT + @error "The parameter given is not yet supported because it appears in the mass matrix" + return nothing + end + end + #Check for parameters which change the power flow + for metadata_entry in p_metadata[param_ixs] + if metadata_entry.type === NETWORK_PARAM || metadata_entry.type === NETWORK_SETPOINT + return POWERFLOW_AND_DEVICES + end + end + #Check for parameters which change device initialization + for metadata_entry in p_metadata[param_ixs] + if metadata_entry.impacts_ic == true + return DEVICES_ONLY + end + end + return INITIALIZED end function get_indices_in_state_vector(sim, state_data) @@ -43,16 +64,15 @@ function get_parameter_values(sim, device_param_pairs) end end -#TODO - think more carefully about how data should be included so it works with with Optimization API. -#TODO - avoid code repetition with _execute! by defining functions appropriately. -#TODO - extend for initialization - first for H... -#TODO - extend for parameters that require initialization. function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; kwargs...) - init_level = get_required_initialization_level(sim.sys, param_data) + p_metadata = sim.inputs.parameters_metadata p = sim.inputs.parameters param_ixs = get_indices_in_parameter_vector(p, param_data) + init_level = get_required_initialization_level(p_metadata, param_ixs) + if init_level === nothing + return nothing + end state_ixs = get_indices_in_state_vector(sim, state_data) - init_level = get_required_initialization_level(sim.sys, param_data) sim_inputs = deepcopy(sim.inputs_init) if get(kwargs, :auto_abstol, false) cb = AutoAbstol(true, get(kwargs, :abstol, 1e-9)) @@ -95,9 +115,11 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; @error "POWERFLOW AND DEVICES -- not yet supported" #_initialize_powerflow_and_devices!(x0, inputs, sys) elseif init_level == DEVICES_ONLY - @error "DEVICES ONLY" - elseif init_level == INITIALIZED + @info "Reinitializing devices only" _initialize_devices_only!(x0, sim_inputs) + _refine_initial_condition!(x0, p_new, prob) + elseif init_level == INITIALIZED + @info "I.C.s not impacted by parameter change" end prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) sol = SciMLBase.solve(prob_new, solver) diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index 1fbd7a4e5..ca26cc117 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -19,6 +19,7 @@ mutable struct SimulationInputs DAE_vector::Vector{Bool} mass_matrix::LinearAlgebra.Diagonal{Float64} parameters::ComponentArrays.ComponentVector{Float64} + parameters_metadata::ComponentArrays.ComponentVector{ParamsMetadata} constant_lags::Vector end @@ -66,8 +67,15 @@ function SimulationInputs( initial_parameters = _add_parameters(initial_parameters, wrapped_injectors) initial_parameters = _add_parameters(initial_parameters, wrapped_loads) initial_parameters = _add_parameters(initial_parameters, wrapped_static_injectors) + #initial_parameters = _add_bus_parameters(initial_parameters, PSY.get_components(PSY.ACBus, sys)) #For extending sensitivity API to Power Flow + parameter_metadata = ComponentArrays.ComponentVector{ParamsMetadata}() + parameter_metadata = _add_parameters_metadata(parameter_metadata, wrapped_branches) + parameter_metadata = _add_parameters_metadata(parameter_metadata, wrapped_injectors) + parameter_metadata = _add_parameters_metadata(parameter_metadata, wrapped_loads) + parameter_metadata = + _add_parameters_metadata(parameter_metadata, wrapped_static_injectors) end - + @assert length(initial_parameters) == length(parameter_metadata) mass_matrix = _make_mass_matrix(wrapped_injectors, n_vars, n_buses) DAE_vector = _make_DAE_vector(mass_matrix, n_vars, n_buses) _adjust_states!( @@ -104,6 +112,7 @@ function SimulationInputs( DAE_vector, mass_matrix, initial_parameters, + parameter_metadata, delays, ) end @@ -179,6 +188,88 @@ function _get_wrapper_name(wrapped_device::BranchWrapper) Symbol(PSY.get_name(get_branch(wrapped_device))) end +# For Extending Sensitivity API to Power Flow +#= function _add_bus_parameters(initial_parameters, buses) + for bus in buses + name = Symbol(PSY.get_name(bus)) + bus_type = PSY.get_bustype(bus) + if bus_type === PSY.ACBusTypes.REF + refs = ( + V_ref = PSY.get_magnitude(bus), + θ_ref = PSY.get_angle(bus), + P_ref = 0.0, + Q_ref = 0.0, + ) + else #TODO- set appropriate references for PV and PQ buses. + refs = ( + V_ref = 0.0, + θ_ref = 0.0, + P_ref = 0.0, + Q_ref = 0.0, + ) + end + initial_parameters = ComponentArrays.ComponentVector( + initial_parameters; + name => ( + refs = refs, + ), + ) + end + return initial_parameters +end =# + +function _add_parameters_metadata(parameter_metadata, wrapped_devices) + for wrapped_device in wrapped_devices + p_metadata = get_params_metadata(wrapped_device) + name = _get_wrapper_name(wrapped_device) + if isa(wrapped_device, DynamicWrapper) + # Consider the special case when the static device is StandardLoad + static_device = get_static_device(wrapped_device) + if isa(static_device, PSY.StandardLoad) + reactive_power = PF.get_total_q(static_device) + else + reactive_power = PSY.get_reactive_power(static_device) + end + refs_metadata = ( + V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + ω_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + P_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + Q_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + ) + elseif isa(wrapped_device, StaticWrapper) + device = get_device(wrapped_device) + refs_metadata = ( + V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + θ_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + P_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + Q_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + ) + + elseif isa(wrapped_device, StaticLoadWrapper) + refs = ( + V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + θ_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + P_power = ParamsMetadata(DEVICE_SETPOINT, false, true), + P_current = ParamsMetadata(DEVICE_SETPOINT, false, true), + P_impedance = ParamsMetadata(DEVICE_SETPOINT, false, true), + Q_power = ParamsMetadata(DEVICE_SETPOINT, false, true), + Q_current = ParamsMetadata(DEVICE_SETPOINT, false, true), + Q_impedance = ParamsMetadata(DEVICE_SETPOINT, false, true), + ) + else + refs = (;) + end + parameter_metadata = ComponentArrays.ComponentVector( + parameter_metadata; + name => ( + params = p_metadata, + refs = refs_metadata, + ), + ) + end + return parameter_metadata +end + function _add_parameters(initial_parameters, wrapped_devices) for wrapped_device in wrapped_devices p = get_params(wrapped_device) diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index a001c1fbe..a2d7efd8c 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -1,8 +1,17 @@ + +@enum PARAM_TYPES begin + DEVICE_PARAM = 0 + DEVICE_SETPOINT = 1 + NETWORK_PARAM = 2 + NETWORK_SETPOINT = 3 +end + struct ParamsMetadata + type::PARAM_TYPES in_mass_matrix::Bool - in_network::Bool impacts_ic::Bool end +Base.length(::ParamsMetadata) = 1 function get_params(x) @error "Parameters not yet defined for component: $(typeof(x))" @@ -37,8 +46,8 @@ get_params_metadata(x::PSY.DynamicBranch) = get_params_metadata(PSY.get_branch(x get_params(x::PSY.Line) = (r = PSY.get_r(x), x = PSY.get_x(x)) get_params_metadata(::PSY.Line) = ( - r = ParamsMetadata(false, true, true), - x = ParamsMetadata(false, true, true), + r = ParamsMetadata(NETWORK_PARAM, false, true), + x = ParamsMetadata(NETWORK_PARAM, false, true), ) get_params(::StaticLoadWrapper) = (;) get_params_metadata(::StaticLoadWrapper) = (;) @@ -74,16 +83,16 @@ get_params(x::PSY.LCLFilter) = rg = PSY.get_rg(x), ) get_params_metadata(::PSY.LCLFilter) = ( - lf = ParamsMetadata(true, false, true), - rf = ParamsMetadata(false, false, true), - cf = ParamsMetadata(true, false, true), - lg = ParamsMetadata(true, false, true), - rg = ParamsMetadata(false, false, true), + lf = ParamsMetadata(DEVICE_PARAM, true, true), + rf = ParamsMetadata(DEVICE_PARAM, false, true), + cf = ParamsMetadata(DEVICE_PARAM, true, true), + lg = ParamsMetadata(DEVICE_PARAM, true, true), + rg = ParamsMetadata(DEVICE_PARAM, false, true), ) get_params(x::PSY.RLFilter) = (rf = PSY.get_rf(x), lf = PSY.get_lf(x)) get_params_metadata(::PSY.RLFilter) = ( - rf = ParamsMetadata(false, false, true), - lf = ParamsMetadata(false, false, true), + rf = ParamsMetadata(DEVICE_PARAM, false, true), + lf = ParamsMetadata(DEVICE_PARAM, false, true), ) #OUTER CONTROL, @@ -99,9 +108,9 @@ get_params_metadata(x::PSY.OuterControl) = ( get_params(x::PSY.VirtualInertia) = (Ta = PSY.get_Ta(x), kd = PSY.get_kd(x), kω = PSY.get_kω(x)) get_params_metadata(::PSY.VirtualInertia) = ( - Ta = ParamsMetadata(false, false, false), - kd = ParamsMetadata(false, false, false), - kω = ParamsMetadata(false, false, false), + Ta = ParamsMetadata(DEVICE_PARAM, false, false), + kd = ParamsMetadata(DEVICE_PARAM, false, false), + kω = ParamsMetadata(DEVICE_PARAM, false, false), ) #Note: Removed fbdd_pnts from parameters because it is not a NamedTuple get_params(x::PSY.ActiveRenewableControllerAB) = ( @@ -118,35 +127,35 @@ get_params(x::PSY.ActiveRenewableControllerAB) = ( T_pord = PSY.get_T_pord(x), ) get_params_metadata(::PSY.ActiveRenewableControllerAB) = ( - K_pg = ParamsMetadata(false, false, false), - K_ig = ParamsMetadata(false, false, true), - T_p = ParamsMetadata(false, false, true), + K_pg = ParamsMetadata(DEVICE_PARAM, false, false), + K_ig = ParamsMetadata(DEVICE_PARAM, false, true), + T_p = ParamsMetadata(DEVICE_PARAM, false, true), fe_lim = ( - min = ParamsMetadata(false, false, false), - max = ParamsMetadata(false, false, false), + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), ), P_lim = ( - min = ParamsMetadata(false, false, false), - max = ParamsMetadata(false, false, false), + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), ), - T_g = ParamsMetadata(false, false, false), - D_dn = ParamsMetadata(false, false, false), - D_up = ParamsMetadata(false, false, false), + T_g = ParamsMetadata(DEVICE_PARAM, false, false), + D_dn = ParamsMetadata(DEVICE_PARAM, false, false), + D_up = ParamsMetadata(DEVICE_PARAM, false, false), dP_lim = ( - min = ParamsMetadata(false, false, false), - max = ParamsMetadata(false, false, false), + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), ), P_lim_innem_inner = ( - min = ParamsMetadata(false, false, false), - max = ParamsMetadata(false, false, false), + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), ), - T_pord = ParamsMetadata(false, false, false), + T_pord = ParamsMetadata(DEVICE_PARAM, false, false), ) #REACTIVE POWER CONTROL get_params(x::PSY.ReactivePowerDroop) = (kq = PSY.get_kq(x), ωf = PSY.get_ωf(x)) get_params_metadata(::PSY.ReactivePowerDroop) = ( - kq = ParamsMetadata(false, false, false), - ωf = ParamsMetadata(false, false, false), + kq = ParamsMetadata(DEVICE_PARAM, false, false), + ωf = ParamsMetadata(DEVICE_PARAM, false, false), ) get_params(x::PSY.ReactiveRenewableControllerAB) = ( T_fltr = PSY.get_T_fltr(x), @@ -167,34 +176,34 @@ get_params(x::PSY.ReactiveRenewableControllerAB) = ( K_qi = PSY.get_K_qi(x), ) get_params_metadata(::PSY.ReactiveRenewableControllerAB) = - (T_fltr = ParamsMetadata(false, false, false), - K_p = ParamsMetadata(false, false, false), - K_i = ParamsMetadata(false, false, true), - T_ft = ParamsMetadata(false, false, false), - T_fv = ParamsMetadata(false, false, false), - V_frz = ParamsMetadata(false, false, false), - R_c = ParamsMetadata(false, false, true), - X_c = ParamsMetadata(false, false, true), - K_c = ParamsMetadata(false, false, true), + (T_fltr = ParamsMetadata(DEVICE_PARAM, false, false), + K_p = ParamsMetadata(DEVICE_PARAM, false, false), + K_i = ParamsMetadata(DEVICE_PARAM, false, true), + T_ft = ParamsMetadata(DEVICE_PARAM, false, false), + T_fv = ParamsMetadata(DEVICE_PARAM, false, false), + V_frz = ParamsMetadata(DEVICE_PARAM, false, false), + R_c = ParamsMetadata(DEVICE_PARAM, false, true), + X_c = ParamsMetadata(DEVICE_PARAM, false, true), + K_c = ParamsMetadata(DEVICE_PARAM, false, true), e_lim = ( - min = ParamsMetadata(false, false, false), - max = ParamsMetadata(false, false, false), + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), ), Q_lim = ( - min = ParamsMetadata(false, false, false), - max = ParamsMetadata(false, false, false), + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), ), - T_p = ParamsMetadata(false, false, true), + T_p = ParamsMetadata(DEVICE_PARAM, false, true), Q_lim_inner = ( - min = ParamsMetadata(false, false, false), - max = ParamsMetadata(false, false, false), + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), ), V_lim = ( - min = ParamsMetadata(false, false, false), - max = ParamsMetadata(false, false, false), + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), ), - K_qp = ParamsMetadata(false, false, false), - K_qi = ParamsMetadata(false, false, true), + K_qp = ParamsMetadata(DEVICE_PARAM, false, false), + K_qi = ParamsMetadata(DEVICE_PARAM, false, true), ) #= = PSY.get_dbd_pnts(x)[1], @@ -218,16 +227,16 @@ get_params(x::PSY.VoltageModeControl) = ( kad = PSY.get_kad(x), ) get_params_metadata(::PSY.VoltageModeControl) = ( - kpv = ParamsMetadata(false, false, true), - kiv = ParamsMetadata(false, false, true), - kffv = ParamsMetadata(false, false, true), - rv = ParamsMetadata(false, false, true), - lv = ParamsMetadata(false, false, true), - kpc = ParamsMetadata(false, false, true), - kic = ParamsMetadata(false, false, true), - kffi = ParamsMetadata(false, false, true), - ωad = ParamsMetadata(false, false, false), - kad = ParamsMetadata(false, false, true), + kpv = ParamsMetadata(DEVICE_PARAM, false, true), + kiv = ParamsMetadata(DEVICE_PARAM, false, true), + kffv = ParamsMetadata(DEVICE_PARAM, false, true), + rv = ParamsMetadata(DEVICE_PARAM, false, true), + lv = ParamsMetadata(DEVICE_PARAM, false, true), + kpc = ParamsMetadata(DEVICE_PARAM, false, true), + kic = ParamsMetadata(DEVICE_PARAM, false, true), + kffi = ParamsMetadata(DEVICE_PARAM, false, true), + ωad = ParamsMetadata(DEVICE_PARAM, false, false), + kad = ParamsMetadata(DEVICE_PARAM, false, true), ) #= get_params(x::PSY.RECurrentControlB) = [ @@ -263,7 +272,8 @@ get_params_metadata(::PSY.RECurrentControlB) = [ =# #DC SOURCE get_params(x::PSY.FixedDCSource) = (voltage = PSY.get_voltage(x),) -get_params_metadata(::PSY.FixedDCSource) = (voltage = ParamMetadata(false, false, false),) +get_params_metadata(::PSY.FixedDCSource) = + (voltage = ParamMetadata(DEVICE_PARAM, false, false),) #FREQ ESTIMATOR get_params(x::PSY.KauraPLL) = ( @@ -272,9 +282,9 @@ get_params(x::PSY.KauraPLL) = ( ki_pll = PSY.get_ki_pll(x), ) get_params_metadata(::PSY.KauraPLL) = ( - ω_lp = ParamsMetadata(false, false, false), - kp_pll = ParamsMetadata(false, false, true), - ki_pll = ParamsMetadata(false, false, true), + ω_lp = ParamsMetadata(DEVICE_PARAM, false, false), + kp_pll = ParamsMetadata(DEVICE_PARAM, false, true), + ki_pll = ParamsMetadata(DEVICE_PARAM, false, true), ) #= get_params(x::PSY.FixedFrequency) = [PSY.get_frequency(x)] get_params_metadata(::PSY.FixedFrequency) = @@ -347,9 +357,9 @@ end get_params(x::PSY.BaseMachine) = (R = PSY.get_R(x), Xd_p = PSY.get_Xd_p(x), eq_p = PSY.get_eq_p(x)) get_params_metadata(::PSY.BaseMachine) = ( - R = ParamsMetadata(false, false, true), - Xd_p = ParamsMetadata(false, false, true), - eq_p = ParamsMetadata(false, false, true), + R = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_p = ParamsMetadata(DEVICE_PARAM, false, true), + eq_p = ParamsMetadata(DEVICE_PARAM, false, true), ) get_params(x::PSY.OneDOneQMachine) = ( R = PSY.get_R(x), @@ -361,13 +371,13 @@ get_params(x::PSY.OneDOneQMachine) = ( Tq0_p = PSY.get_Tq0_p(x), ) get_params_metadata(::PSY.OneDOneQMachine) = ( - R = PartamsMetadata(false, false, true), - Xd = PartamsMetadata(false, false, true), - Xq = PartamsMetadata(false, false, true), - Xd_p = PartamsMetadata(false, false, true), - Xq_p = PartamsMetadata(false, false, true), - Td0_p = PartamsMetadata(false, false, false), - Tq0_p = PartamsMetadata(false, false, false), + R = PartamsMetadata(DEVICE_PARAM, false, true), + Xd = PartamsMetadata(DEVICE_PARAM, false, true), + Xq = PartamsMetadata(DEVICE_PARAM, false, true), + Xd_p = PartamsMetadata(DEVICE_PARAM, false, true), + Xq_p = PartamsMetadata(DEVICE_PARAM, false, true), + Td0_p = PartamsMetadata(DEVICE_PARAM, false, false), + Tq0_p = PartamsMetadata(DEVICE_PARAM, false, false), ) #= #TODO - SimpleMarconatoMachine @@ -453,22 +463,22 @@ get_params( get_params_metadata( ::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, ) = ( - R = ParamsMetadata(false, false, true), - Td0_p = ParamsMetadata(false, false, true), - Td0_pp = ParamsMetadata(false, false, true), - Tq0_p = ParamsMetadata(false, false, true), - Tq0_pp = ParamsMetadata(false, false, true), - Xd = ParamsMetadata(false, false, true), - Xq = ParamsMetadata(false, false, true), - Xd_p = ParamsMetadata(false, false, true), - Xq_p = ParamsMetadata(false, false, true), - Xd_pp = ParamsMetadata(false, false, true), - Xl = ParamsMetadata(false, false, true), - γ_d1 = ParamsMetadata(false, false, true), - γ_q1 = ParamsMetadata(false, false, true), - γ_d2 = ParamsMetadata(false, false, true), - γ_q2 = ParamsMetadata(false, false, true), - γ_qd = ParamsMetadata(false, false, true), + R = ParamsMetadata(DEVICE_PARAM, false, true), + Td0_p = ParamsMetadata(DEVICE_PARAM, false, true), + Td0_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Tq0_p = ParamsMetadata(DEVICE_PARAM, false, true), + Tq0_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Xd = ParamsMetadata(DEVICE_PARAM, false, true), + Xq = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_p = ParamsMetadata(DEVICE_PARAM, false, true), + Xq_p = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Xl = ParamsMetadata(DEVICE_PARAM, false, true), + γ_d1 = ParamsMetadata(DEVICE_PARAM, false, true), + γ_q1 = ParamsMetadata(DEVICE_PARAM, false, true), + γ_d2 = ParamsMetadata(DEVICE_PARAM, false, true), + γ_q2 = ParamsMetadata(DEVICE_PARAM, false, true), + γ_qd = ParamsMetadata(DEVICE_PARAM, false, true), ) #= get_params( x::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, @@ -506,8 +516,8 @@ get_params_metadata( #SHAFTS get_params(x::PSY.SingleMass) = (H = PSY.get_H(x), D = PSY.get_D(x)) get_params_metadata(::PSY.SingleMass) = ( - H = ParamsMetadata(false, false, false), - D = ParamsMetadata(false, false, false), + H = ParamsMetadata(DEVICE_PARAM, false, false), + D = ParamsMetadata(DEVICE_PARAM, false, false), ) #= get_params(x::PSY.FiveMassShaft) = [ @@ -570,15 +580,15 @@ get_params(x::PSY.AVRTypeI) = ( Be = PSY.get_Be(x), ) get_params_metadata(::PSY.AVRTypeI) = ( - Ka = ParamsMetadata(false, false, true), - Ke = ParamsMetadata(false, false, true), - Kf = ParamsMetadata(false, false, true), - Ta = ParamsMetadata(false, false, false), - Te = ParamsMetadata(false, false, false), - Tf = ParamsMetadata(false, false, true), - Tr = ParamsMetadata(false, false, false), - Ae = ParamsMetadata(false, false, true), - Be = ParamsMetadata(false, false, true), + Ka = ParamsMetadata(DEVICE_PARAM, false, true), + Ke = ParamsMetadata(DEVICE_PARAM, false, true), + Kf = ParamsMetadata(DEVICE_PARAM, false, true), + Ta = ParamsMetadata(DEVICE_PARAM, false, false), + Te = ParamsMetadata(DEVICE_PARAM, false, false), + Tf = ParamsMetadata(DEVICE_PARAM, false, true), + Tr = ParamsMetadata(DEVICE_PARAM, false, false), + Ae = ParamsMetadata(DEVICE_PARAM, false, true), + Be = ParamsMetadata(DEVICE_PARAM, false, true), ) get_params(x::PSY.SEXS) = ( Ta_Tb = PSY.get_Ta_Tb(x), @@ -588,13 +598,13 @@ get_params(x::PSY.SEXS) = ( V_lim = PSY.get_V_lim(x), ) get_params_metadata(::PSY.SEXS) = ( - Ta_Tb = ParamsMetadata(false, false, true), - Tb = ParamsMetadata(false, false, false), - K = ParamsMetadata(false, false, true), - Te = ParamsMetadata(false, false, false), + Ta_Tb = ParamsMetadata(DEVICE_PARAM, false, true), + Tb = ParamsMetadata(DEVICE_PARAM, false, false), + K = ParamsMetadata(DEVICE_PARAM, false, true), + Te = ParamsMetadata(DEVICE_PARAM, false, false), V_lim = ( - min = ParamsMetadata(false, false, true), - max = ParamsMetadata(false, false, true), + min = ParamsMetadata(DEVICE_PARAM, false, true), + max = ParamsMetadata(DEVICE_PARAM, false, true), ), ) #= get_params(x::PSY.AVRTypeII) = [ @@ -717,7 +727,8 @@ get_params_metadata(::PSY.EXAC1) = [ =# #TurbineGov get_params(x::PSY.TGFixed) = (; efficiency = PSY.get_efficiency(x)) -get_params_metadata(::PSY.TGFixed) = (; efficiency = ParamsMetadata(false, false, true)) +get_params_metadata(::PSY.TGFixed) = + (; efficiency = ParamsMetadata(DEVICE_PARAM, false, true)) #= get_params(x::PSY.TGTypeII) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_T2(x)] get_params_metadata(::PSY.TGTypeII) = [ @@ -778,15 +789,15 @@ get_params(x::PSY.SteamTurbineGov1) = ( D_T = PSY.get_D_T(x), ) get_params_metadata(::PSY.SteamTurbineGov1) = ( - R = ParamsMetadata(false, false, true), - T1 = ParamsMetadata(false, false, true), + R = ParamsMetadata(DEVICE_PARAM, false, true), + T1 = ParamsMetadata(DEVICE_PARAM, false, true), valve_position = ( - min = ParamsMetadata(false, false, true), - max = ParamsMetadata(false, false, true), + min = ParamsMetadata(DEVICE_PARAM, false, true), + max = ParamsMetadata(DEVICE_PARAM, false, true), ), - T2 = ParamsMetadata(false, false, true), - T3 = ParamsMetadata(false, false, true), - D_T = ParamsMetadata(false, false, true), + T2 = ParamsMetadata(DEVICE_PARAM, false, true), + T3 = ParamsMetadata(DEVICE_PARAM, false, true), + D_T = ParamsMetadata(DEVICE_PARAM, false, true), ) #= get_params(x::PSY.HydroTurbineGov) = [ PSY.get_R(x), @@ -819,7 +830,7 @@ get_params_metadata(::PSY.HydroTurbineGov) = [ #PSS get_params(x::PSY.PSSFixed) = (; V_pss = PSY.get_V_pss(x)) -get_params_metadata(::PSY.PSSFixed) = (; V_pss = ParamsMetadata(false, false, false)) +get_params_metadata(::PSY.PSSFixed) = (; V_pss = ParamsMetadata(DEVICE_PARAM, false, false)) #= get_params(x::PSY.STAB1) = [ PSY.get_KT(x), @@ -846,8 +857,8 @@ get_params(x::PSY.Source) = ( X_th = PSY.get_X_th(x), ) get_params_metadata(::PSY.Source) = ( - R_th = ParamsMetadata(false, false, true), - X_th = ParamsMetadata(false, false, true), + R_th = ParamsMetadata(DEVICE_PARAM, false, true), + X_th = ParamsMetadata(DEVICE_PARAM, false, true), ) #Parameters not implemented for PeriodicVariableSource - requires change in PSY Struct to have information required to construct and deconstruct parameter vector #= diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index ee13e0e1c..0905e467d 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -23,56 +23,118 @@ using PlotlyJS #ReverseDiffVJP and EnzymeVJP only options compatible with Hybrid DEs (DEs with callbacks) #BacksolveAdjoint prone to instabilities whenever the Lipschitz constant is sufficiently large (stiff equations, PDE discretizations, and many other contexts) #For ForwardDiffSensitivity, convert_tspan=true is needed for hybrid equations. +@testset "Test Gradients - OMIB; H" begin + path = mktempdir() + try + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) -sim = Simulation!( - MassMatrixModel, - omib_sys, - pwd(), - (0.0, 5.0), - s_change, -) + #GET GROUND TRUTH DATA + execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) -#GET GROUND TRUTH DATA -H_gt = - get_H(get_shaft(get_component(DynamicGenerator, omib_sys, "generator-102-1"))) -execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) -res = read_results(sim) -t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) -#GET PARAMETER VALUES -p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) -#get_parameter_values(sim, [("InfBus", :X_th), ("generator-102-1", :Shaft, :H)]) -#get_parameter_values(sim, [("InfBus", :X_th)]) + function f_loss(δ, δ_gt) + #display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + return sum(abs.(δ - δ_gt)) + end -#DEFINE LOSS FUNCTION -function f_loss(δ, δ_gt) - #display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) - return sum(abs.(δ - δ_gt)) + #GET SENSITIVITY FUNCTIONS + f_forward, f_grad = get_sensitivity_functions( + sim, + [("generator-102-1", :Shaft, :H)], + [("generator-102-1", :δ)], + Rodas4(), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + + loss_zero = f_forward(p, δ_gt) + loss_non_zero_1 = f_forward([3.2], δ_gt) + loss_non_zero_2 = f_forward(p, δ_gt .* 2) + @test loss_zero == 0.0 + @test loss_non_zero_1 != 0.0 + @test loss_non_zero_2 != 0.0 + grad_zero = f_grad(p, δ_gt) + grad_nonzero_1 = f_grad([3.14], δ_gt) + grad_nonzero_2 = f_grad([3.15], δ_gt) + @test isapprox(grad_zero[1], 0.0, atol = 1.0) + @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) + @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end end -#GET SENSITIVITY FUNCTIONS -f_forward, f_grad = get_sensitivity_functions( - sim, - [("generator-102-1", :Shaft, :H)], - [("generator-102-1", :δ)], - Rodas4(), - f_loss; - sensealg = ForwardDiffSensitivity(), - abstol = 1e-9, - reltol = 1e-9, - dtmax = 0.005, - saveat = 0.005, -) +@testset "Test Gradients - OMIB; Xd_p" begin + path = mktempdir() + try + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + + #GET GROUND TRUTH DATA + execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-102-1", :Machine, :Xd_p)]) -loss_zero = f_forward(p, δ_gt) -loss_non_zero_1 = f_forward([3.2], δ_gt) -loss_non_zero_2 = f_forward(p, δ_gt .* 2) -@test loss_zero == 0.0 -@test loss_non_zero_1 != 0.0 -@test loss_non_zero_2 != 0.0 -grad_zero = f_grad(p, δ_gt) -grad_nonzero_1 = f_grad([3.14], δ_gt) -grad_nonzero_2 = f_grad([3.15], δ_gt) -@test isapprox(grad_zero[1], 0.0, atol = 1.0) -@test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) -@test isapprox(grad_nonzero_2[1], 8.0, atol = 1.0) + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing + function f_loss(δ, δ_gt) + #plot_traces(δ, δ_gt) + return sum(abs.(δ - δ_gt)) + end + + #GET SENSITIVITY FUNCTIONS + f_forward, f_grad = get_sensitivity_functions( + sim, + [("generator-102-1", :Machine, :Xd_p)], + [("generator-102-1", :δ)], + Rodas4(), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + + loss_zero = f_forward(p, δ_gt) + loss_non_zero_1 = f_forward(p * 1.01, δ_gt) + loss_non_zero_2 = f_forward(p * 0.99, δ_gt) + @test isapprox(loss_zero, 0.0, atol = 1e-9) + @test loss_non_zero_1 != 0.0 + @test loss_non_zero_2 != 0.0 + grad_zero = f_grad(p, δ_gt) + grad_nonzero_1 = f_grad(p * 1.01, δ_gt) + grad_nonzero_2 = f_grad(p * 0.99, δ_gt) + @test isapprox(grad_zero[1], 497, atol = 1.0) + @test isapprox(grad_nonzero_1[1], 499.0, atol = 1.0) + @test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end From bfe70266ff5ab34e063907aff1d9d61348b1b8f7 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 24 Jun 2024 10:44:44 -0400 Subject: [PATCH 27/76] add simple test in Optimization problem --- test/Project.toml | 2 ++ test/runtests.jl | 5 ++-- test/test_case_enzyme.jl | 62 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index d024b9159..d61612060 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -11,6 +11,8 @@ InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" +Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba" +OptimizationOptimisers = "42dfb2eb-d2b4-4451-abcd-913932933ac1" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" PowerFlows = "94fada2c-fd9a-4e89-8d82-81405f5cb4f6" diff --git a/test/runtests.jl b/test/runtests.jl index 856a0c46b..c4794f80d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -22,9 +22,8 @@ Enzyme.API.looseTypeAnalysis!(true) #Required for using component arrays with E Enzyme.API.maxtypeoffset!(1024) Enzyme.API.maxtypedepth!(20) using Zygote -## -#using Optimization #incompatible with latest Enzyme -#using OptimizationOptimisers +using Optimization +using OptimizationOptimisers import Aqua Aqua.test_unbound_args(PowerSimulationsDynamics) diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index 0905e467d..4027a2d33 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -79,6 +79,68 @@ using PlotlyJS end end +@testset "Test Optimization - OMIB; H" begin + path = mktempdir() + try + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + + #GET GROUND TRUTH DATA + execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) + + function f_loss(δ, δ_gt) + #display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + return sum(abs.(δ - δ_gt)) + end + + #GET SENSITIVITY FUNCTIONS + f_forward, f_grad = get_sensitivity_functions( + sim, + [("generator-102-1", :Shaft, :H)], + [("generator-102-1", :δ)], + Rodas4(), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + #H_values = [] + #loss_values = [] + function callback(u, l) + #push!(H_values, u.u[1]) + #push!(loss_values, l) + return false + end + optfun = OptimizationFunction{false}( + (u, p) -> f_forward(u, δ_gt); + grad = (res, u, p) -> res .= f_grad(u, δ_gt), + ) + optprob = OptimizationProblem{false}(optfun, [3.14]) + sol = Optimization.solve( + optprob, + OptimizationOptimisers.Adam(0.002); + callback = callback, + maxiters = 3, + ) + @test isapprox(sol.u[1], 3.144000187737475, atol = 1e-6) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + @testset "Test Gradients - OMIB; Xd_p" begin path = mktempdir() try From 38541f73d42db7816c9b2de9f3b1223d0dbcd4cc Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 24 Jun 2024 10:52:12 -0400 Subject: [PATCH 28/76] add degov; extend senseitivity to delays (incomplete, test still fails) --- src/base/sensitivity_analysis.jl | 18 +++- src/base/simulation_inputs.jl | 2 +- .../generator_components/init_tg.jl | 4 +- src/models/generator_models/tg_models.jl | 22 ++--- src/utils/parameters.jl | 20 ++++ test/test_case_enzyme.jl | 92 +++++++++++++++++++ 6 files changed, 139 insertions(+), 19 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index b9cb415a3..e5c4c7a68 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -89,11 +89,19 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; prob_old = sim.problem f_old = prob_old.f - f_new = SciMLBase.ODEFunction{true}( - f_old.f; - mass_matrix = f_old.mass_matrix, - ) - + if typeof(prob_old) <: SciMLBase.ODEProblem + f_new = SciMLBase.ODEFunction{true}( + f_old.f; + mass_matrix = f_old.mass_matrix, + ) + elseif typeof(prob_old) <: SciMLBase.DDEProblem + f_new = SciMLBase.DDEFunction{true}( + f_old.f; + mass_matrix = f_old.mass_matrix, + ) + else + @error "Problem type not supported" + end prob_new = SciMLBase.remake( prob_old; f = f_new, diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index ca26cc117..ed7b3180d 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -246,7 +246,7 @@ function _add_parameters_metadata(parameter_metadata, wrapped_devices) ) elseif isa(wrapped_device, StaticLoadWrapper) - refs = ( + refs_metadata = ( V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), θ_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), P_power = ParamsMetadata(DEVICE_SETPOINT, false, true), diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index 4d32c6800..e4dc4d76f 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -181,7 +181,7 @@ end function initialize_tg!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.DEGOV, P}}, inner_vars::AbstractVector, @@ -190,7 +190,7 @@ function initialize_tg!( #Get mechanical torque to SyncMach τm0 = inner_vars[τm_var] PSY.set_P_ref!(tg, τm0) - set_P_ref(dynamic_device, τm0) + set_P_ref!(p, τm0) #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index ec2ad184b..a5fd2f9b6 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -328,7 +328,7 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.DEGOV, P}}, @@ -337,7 +337,7 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - P_ref = get_P_ref(device) + P_ref = p[:refs][:P_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.DEGOV) @@ -355,15 +355,15 @@ function mdl_tg_ode!( ω = @view device_states[external_ix] #Get Parameters - tg = PSY.get_prime_mover(device) - T1 = PSY.get_T1(tg) - T2 = PSY.get_T2(tg) - T3 = PSY.get_T3(tg) - K = PSY.get_K(tg) - T4 = PSY.get_T4(tg) - T5 = PSY.get_T5(tg) - T6 = PSY.get_T6(tg) - Td = PSY.get_Td(tg) + params = p[:params][:TurbineGov] + T1 = params[:T1] + T2 = params[:T2] + T3 = params[:T3] + K = params[:K] + T4 = params[:T4] + T5 = params[:T5] + T6 = params[:T6] + Td = params[:Td] #Compute block derivatives Δω = ω[1] - 1.0 diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index a2d7efd8c..e9068706b 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -729,6 +729,26 @@ get_params_metadata(::PSY.EXAC1) = [ get_params(x::PSY.TGFixed) = (; efficiency = PSY.get_efficiency(x)) get_params_metadata(::PSY.TGFixed) = (; efficiency = ParamsMetadata(DEVICE_PARAM, false, true)) +get_params(x::PSY.DEGOV) = ( + T1 = PSY.get_T1(x), + T2 = PSY.get_T2(x), + T3 = PSY.get_T3(x), + K = PSY.get_K(x), + T4 = PSY.get_T4(x), + T5 = PSY.get_T5(x), + T6 = PSY.get_T6(x), + Td = PSY.get_Td(x), +) +get_params_metadata(::PSY.DEGOV) = ( + T1 = ParamsMetadata(DEVICE_PARAM, true, false), + T2 = ParamsMetadata(DEVICE_PARAM, true, false), + T3 = ParamsMetadata(DEVICE_PARAM, false, false), + K = ParamsMetadata(DEVICE_PARAM, false, false), + T4 = ParamsMetadata(DEVICE_PARAM, false, false), + T5 = ParamsMetadata(DEVICE_PARAM, true, false), + T6 = ParamsMetadata(DEVICE_PARAM, true, false), + Td = ParamsMetadata(DEVICE_PARAM, false, false), +) #= get_params(x::PSY.TGTypeII) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_T2(x)] get_params_metadata(::PSY.TGTypeII) = [ diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index 4027a2d33..f69de76d2 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -141,6 +141,98 @@ end end end +function add_degov_to_omib!(omib_sys) + gen = get_component(ThermalStandard, omib_sys, "generator-102-1") + dyn_gen = get_component(DynamicGenerator, omib_sys, "generator-102-1") + new_gov = PSY.DEGOV(; + T1 = 0.0, + T2 = 0.0, + T3 = 0.0, + K = 18.0, + T4 = 12.0, + T5 = 5.0, + T6 = 0.2, + Td = 0.5, + P_ref = 0.0, + ) + dyn_gen_new = DynamicGenerator(; + name = get_name(dyn_gen), + ω_ref = get_ω_ref(dyn_gen), + machine = get_machine(dyn_gen), + shaft = get_shaft(dyn_gen), + avr = get_avr(dyn_gen), + prime_mover = new_gov, + pss = get_pss(dyn_gen), + base_power = get_base_power(dyn_gen), + ) + remove_component!(omib_sys, dyn_gen) + add_component!(omib_sys, dyn_gen_new, gen) +end + +#= @testset "Test Gradients - OMIB; H; Delays" begin + path = mktempdir() + try + add_degov_to_omib!(omib_sys) + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + + #GET GROUND TRUTH DATA + execute!( + sim, + MethodOfSteps(Rodas4(; autodiff = false)); + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) + + function f_loss(δ, δ_gt) + #display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + return sum(abs.(δ - δ_gt)) + end + + #GET SENSITIVITY FUNCTIONS + f_forward, f_grad = get_sensitivity_functions( + sim, + [("generator-102-1", :Shaft, :H)], + [("generator-102-1", :δ)], + MethodOfSteps(Rodas4()), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + + loss_zero = f_forward(p, δ_gt) + loss_non_zero_1 = f_forward([3.2], δ_gt) + loss_non_zero_2 = f_forward(p, δ_gt .* 2) + @test loss_zero == 0.0 + @test loss_non_zero_1 != 0.0 + @test loss_non_zero_2 != 0.0 + grad_zero = f_grad(p, δ_gt) + grad_nonzero_1 = f_grad([3.14], δ_gt) + grad_nonzero_2 = f_grad([3.15], δ_gt) + @test isapprox(grad_zero[1], 0.0, atol = 1.0) + @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) + @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end =# + @testset "Test Gradients - OMIB; Xd_p" begin path = mktempdir() try From c36759ec1c336a57c79f264feb3286ec30697476 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 24 Jun 2024 15:03:47 -0400 Subject: [PATCH 29/76] loosen enzyme loading requirements --- src/PowerSimulationsDynamics.jl | 11 +---------- test/runtests.jl | 4 +--- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index 8361316a6..162cc686d 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -85,17 +85,8 @@ import PowerNetworkMatrices import TimerOutputs import FastClosures: @closure import Enzyme -Enzyme.API.runtimeActivity!(true) +Enzyme.API.runtimeActivity!(true) #Needed for "activity unstable" code: https://enzymead.github.io/Enzyme.jl/stable/faq/ Enzyme.API.looseTypeAnalysis!(true) #Required for using component arrays with Enzyme -Enzyme.API.maxtypeoffset!(1024) -Enzyme.API.maxtypedepth!(20) -#Enzyme.API.runtimeActivity!(true) -#= Generally, the preferred solution to these type of activity unstable codes should be to make -your variables all activity-stable (e.g. always containing differentiable memory or always - containing non-differentiable memory). However, with care, Enzyme does support "Runtime Activity" - as a way to differentiate these programs without having to modify your code. =# -#Enzyme.API.looseTypeAnalysis!(true) #Best guess if it cannot determine the type; this was needed for using ComponentArrays/ODEFunction -#Enzyme.API.maxtypedepth!(20) import ChainRulesCore import ComponentArrays diff --git a/test/runtests.jl b/test/runtests.jl index c4794f80d..14ec6567b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -17,10 +17,8 @@ import LinearAlgebra using Logging using SciMLSensitivity using Enzyme -Enzyme.API.runtimeActivity!(true) +Enzyme.API.runtimeActivity!(true) #Needed for "activity unstable" code: https://enzymead.github.io/Enzyme.jl/stable/faq/ Enzyme.API.looseTypeAnalysis!(true) #Required for using component arrays with Enzyme -Enzyme.API.maxtypeoffset!(1024) -Enzyme.API.maxtypedepth!(20) using Zygote using Optimization using OptimizationOptimisers From a2a305dc48088217f8171fb82570b620172fcb25 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 24 Jun 2024 18:36:09 -0400 Subject: [PATCH 30/76] update enzyme (one bad release) --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 9a7d1de68..c656355a5 100644 --- a/Project.toml +++ b/Project.toml @@ -31,7 +31,7 @@ ComponentArrays = "0.15" DataFrames = "1" DataStructures = "~0.18" DocStringExtensions = "~0.9" -Enzyme = "<0.12.17" +Enzyme = "0.12" FastClosures = "^0.3" ForwardDiff = "~v0.10" InfrastructureSystems = "^1.21" From 8c5b54736f8a6134cb7c059e0288075854c75af9 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 24 Jun 2024 18:38:07 -0400 Subject: [PATCH 31/76] passes test_base and test_enzyme --- src/base/device_wrapper.jl | 4 +- src/base/perturbations.jl | 64 +++++++++-------- src/base/simulation.jl | 6 +- src/base/simulation_inputs.jl | 3 +- .../generator_components/init_tg.jl | 33 +++++---- src/models/generator_models/tg_models.jl | 17 +++-- src/utils/parameters.jl | 69 ++++++++++--------- test/test_base.jl | 18 ++--- 8 files changed, 111 insertions(+), 103 deletions(-) diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index d1a226c25..801855f4f 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -480,8 +480,8 @@ function set_connection_status(wrapper::Union{StaticWrapper, DynamicWrapper}, va else error("Invalid status $val. It can only take values 1 or 0") end - wrapper.connection_status[] = Float64(val) + wrapper.connection_status = Float64(val) end get_connection_status(wrapper::Union{StaticWrapper, DynamicWrapper}) = - wrapper.connection_status[] + wrapper.connection_status diff --git a/src/base/perturbations.jl b/src/base/perturbations.jl index ac354fad2..bac87b205 100644 --- a/src/base/perturbations.jl +++ b/src/base/perturbations.jl @@ -474,8 +474,10 @@ function get_affect(inputs::SimulationInputs, ::PSY.System, pert::ControlReferen wrapped_device_ix = _find_device_index(inputs, pert.device) return (integrator) -> begin wrapped_device = get_dynamic_injectors(inputs)[wrapped_device_ix] + wrapped_device_name = _get_wrapper_name(wrapped_device) + refs = @view(@view(integrator.p[wrapped_device_name])[:refs]) @debug "Changing $(PSY.get_name(wrapped_device)) $(pert.signal) to $(pert.ref_value)" - getfield(wrapped_device, pert.signal)[] = pert.ref_value + refs[pert.signal] = pert.ref_value return end end @@ -640,10 +642,12 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) ) end wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] - P_power = get_P_power(wrapped_zip) - Q_power = get_Q_power(wrapped_zip) - set_P_power!(wrapped_zip, P_power + P_change) - set_Q_power!(wrapped_zip, Q_power + Q_change) + wrapped_zip_name = _get_wrapper_name(wrapped_zip) + refs = @view(@view(integrator.p[wrapped_zip_name])[:refs]) + P_power = refs[:P_power] + Q_power = refs[:Q_power] + refs[:P_power] = P_power + P_change + refs[:Q_power] = Q_power + Q_change @debug "Changing load at bus $(PSY.get_name(wrapped_zip)) $(pert.signal) to $(pert.ref_value)" return end @@ -651,37 +655,33 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) return (integrator) -> begin base_power_conversion = PSY.get_base_power(ld) / sys_base_power wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] + wrapped_zip_name = _get_wrapper_name(wrapped_zip) + refs = @view(@view(integrator.p[wrapped_zip_name])[:refs]) # List all cases for StandardLoad changes if signal ∈ [:P_ref, :P_ref_impedance] P_old = PSY.get_impedance_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - P_impedance = get_P_impedance(wrapped_zip) - set_P_impedance!(wrapped_zip, P_impedance + P_change) + refs[:P_impedance] = refs[:P_impedance] + P_change elseif signal ∈ [:Q_ref, :Q_ref_impedance] Q_old = PSY.get_impedance_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - Q_impedance = get_Q_impedance(wrapped_zip) - set_Q_impedance!(wrapped_zip, Q_impedance + Q_change) + refs[:Q_impedance] = refs[:Q_impedance] + Q_change elseif signal == :P_ref_power P_old = PSY.get_constant_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - P_power = get_P_power(wrapped_zip) - set_P_power!(wrapped_zip, P_power + P_change) + refs[:P_power] = refs[:P_power] + P_change elseif signal == :Q_ref_power Q_old = PSY.get_constant_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - Q_power = get_Q_power(wrapped_zip) - set_Q_power!(wrapped_zip, Q_power + Q_change) + refs[:Q_power] = refs[:Q_power] + Q_change elseif signal == :P_ref_current P_old = PSY.get_current_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - P_current = get_P_current(wrapped_zip) - set_P_current!(wrapped_zip, P_current + P_change) + refs[:P_current] = refs[:P_current] + P_change elseif signal == :Q_ref_current Q_old = PSY.get_current_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - Q_current = get_Q_current(wrapped_zip) - set_Q_current!(wrapped_zip, Q_current + Q_change) + refs[:Q_current] = refs[:Q_current] + Q_change else error("It should never be here. Should have failed in the constructor.") end @@ -690,6 +690,8 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) return (integrator) -> begin ld_name = PSY.get_name(ld) wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] + wrapped_zip_name = _get_wrapper_name(wrapped_zip) + refs = @view(@view(integrator.p[wrapped_zip_name])[:refs]) exp_names = get_exp_names(wrapped_zip) exp_vects = get_exp_params(wrapped_zip) tuple_ix = exp_names[ld_name] @@ -744,10 +746,10 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) return (integrator) -> begin PSY.set_available!(ld, false) wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] - P_power = get_P_power(wrapped_zip) - Q_power = get_Q_power(wrapped_zip) - set_P_power!(wrapped_zip, P_power - P_trip) - set_Q_power!(wrapped_zip, Q_power - Q_trip) + wrapped_zip_name = _get_wrapper_name(wrapped_zip) + refs = @view(@view(integrator.p[wrapped_zip_name])[:refs]) + refs[:P_power] = refs[:P_power] - P_trip + refs[:Q_power] = refs[:Q_power] - Q_trip @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end @@ -762,21 +764,17 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) return (integrator) -> begin PSY.set_available!(ld, false) wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] + wrapped_zip_name = _get_wrapper_name(wrapped_zip) + refs = @view(@view(integrator.p[wrapped_zip_name])[:refs]) # Update Constant Power - P_power = get_P_power(wrapped_zip) - Q_power = get_Q_power(wrapped_zip) - set_P_power!(wrapped_zip, P_power - P_power_trip) - set_Q_power!(wrapped_zip, Q_power - Q_power_trip) + refs[:P_power] = refs[:P_power] - P_power_trip + refs[:Q_power] = refs[:Q_power] - Q_power_trip # Update Constant Current - P_current = get_P_current(wrapped_zip) - Q_current = get_Q_current(wrapped_zip) - set_P_current!(wrapped_zip, P_current - P_current_trip) - set_Q_current!(wrapped_zip, Q_current - Q_current_trip) + refs[:P_current] = refs[:P_current] - P_current_trip + refs[:Q_current] = refs[:Q_current] - Q_current_trip # Update Constant Impedance - P_impedance = get_P_impedance(wrapped_zip) - Q_impedance = get_Q_impedance(wrapped_zip) - set_P_impedance!(wrapped_zip, P_impedance - P_impedance_trip) - set_Q_impedance!(wrapped_zip, Q_impedance - Q_impedance_trip) + refs[:P_impedance] = refs[:P_impedance] - P_impedance_trip + refs[:Q_impedance] = refs[:Q_impedance] - Q_impedance_trip @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end diff --git a/src/base/simulation.jl b/src/base/simulation.jl index 32ac693b2..550c128c9 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -255,14 +255,14 @@ function _pre_initialize_simulation!(sim::Simulation) if sim.initialize_level == POWERFLOW_AND_DEVICES sim.x0 = _get_flat_start(inputs) sim.status = _initialize_powerflow_and_devices!(sim.x0, inputs, sys) - elseif sim.initialize_level == DEVICE_ONLY + elseif sim.initialize_level == DEVICES_ONLY sim.x0 = deepcopy(sim.x0_init) sim.status = _initialize_devices_only!(sim.x0, inputs) elseif sim.initialize_level == FLAT_START sim.x0 = _get_flat_start(inputs) - elseif sim.initialize_level == INITILAIZED + elseif sim.initialize_level == INITIALIZED sim.x0 = deepcopy(sim.x0_init) - if length(x0) != get_variable_count(inputs) + if length(sim.x0) != get_variable_count(inputs) throw( IS.ConflictingInputsError( "The size of the provided initial state space does not match the model's state space.", diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index ed7b3180d..1bd2b3dc2 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -237,7 +237,6 @@ function _add_parameters_metadata(parameter_metadata, wrapped_devices) Q_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), ) elseif isa(wrapped_device, StaticWrapper) - device = get_device(wrapped_device) refs_metadata = ( V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), θ_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), @@ -257,7 +256,7 @@ function _add_parameters_metadata(parameter_metadata, wrapped_devices) Q_impedance = ParamsMetadata(DEVICE_SETPOINT, false, true), ) else - refs = (;) + refs_metadata = (;) end parameter_metadata = ComponentArrays.ComponentVector( parameter_metadata; diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index e4dc4d76f..b3b64fe2f 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -128,7 +128,7 @@ end function initialize_tg!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.GasTG, P}}, inner_vars::AbstractVector, @@ -140,17 +140,22 @@ function initialize_tg!( tg = PSY.get_prime_mover(dynamic_device) #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.GasTG) - internal_params = @view device_parameters[local_ix_params] - R, _, _, _, AT, Kt, V_min, V_max, D_turb = internal_params + params = p[:params][:TurbineGov] + R = params[:R] inv_R = R < eps() ? 0.0 : (1.0 / R) - function f!(out, x) + function f!(out, x, params) P_ref = x[1] x_g1 = x[2] x_g2 = x[3] x_g3 = x[4] + AT = params[:AT] + Kt = params[:Kt] + V_min = params[:V_lim][:min] + V_max = params[:V_lim][:max] + D_turb = params[:D_turb] + x_in = min((P_ref - inv_R * Δω), (AT + Kt * (AT - x_g3))) out[1] = (x_in - x_g1) #dx_g1/dt x_g1_sat = V_min < x_g1 < V_max ? x_g1 : max(V_min, min(V_max, x_g1)) @@ -159,16 +164,20 @@ function initialize_tg!( out[4] = (x_g2 - D_turb * Δω) - τm0 end x0 = [1.0 / inv_R, τm0, τm0, τm0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) - @error( - "Initialization of Turbine Governor $(PSY.get_name(static)) failed" - ) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) + @warn("Initialization in TG failed") else - sol_x0 = sol.zero + sol_x0 = sol.u #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - set_P_ref(dynamic_device, sol_x0[1]) + set_P_ref!(p, sol_x0[1]) #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index a5fd2f9b6..8e4241441 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -201,7 +201,7 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.GasTG, P}}, @@ -210,7 +210,7 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - P_ref = get_P_ref(device) + P_ref = p[:refs][:P_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.GasTG) @@ -226,9 +226,16 @@ function mdl_tg_ode!( ω = @view device_states[external_ix] #Get Parameters - local_ix_params = get_local_parameter_ix(device, PSY.GasTG) - internal_params = @view device_parameters[local_ix_params] - R, T1, T2, T3, AT, Kt, V_min, V_max, D_turb = internal_params + params = p[:params][:TurbineGov] + R = params[:R] + T1 = params[:T1] + T2 = params[:T2] + T3 = params[:T3] + AT = params[:AT] + Kt = params[:Kt] + V_min = params[:V_lim][:min] + V_max = params[:V_lim][:max] + D_turb = params[:D_turb] inv_R = R < eps() ? 0.0 : (1.0 / R) #Compute auxiliary parameters diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index e9068706b..25dbfb90d 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -273,7 +273,7 @@ get_params_metadata(::PSY.RECurrentControlB) = [ #DC SOURCE get_params(x::PSY.FixedDCSource) = (voltage = PSY.get_voltage(x),) get_params_metadata(::PSY.FixedDCSource) = - (voltage = ParamMetadata(DEVICE_PARAM, false, false),) + (voltage = ParamsMetadata(DEVICE_PARAM, false, false),) #FREQ ESTIMATOR get_params(x::PSY.KauraPLL) = ( @@ -371,13 +371,13 @@ get_params(x::PSY.OneDOneQMachine) = ( Tq0_p = PSY.get_Tq0_p(x), ) get_params_metadata(::PSY.OneDOneQMachine) = ( - R = PartamsMetadata(DEVICE_PARAM, false, true), - Xd = PartamsMetadata(DEVICE_PARAM, false, true), - Xq = PartamsMetadata(DEVICE_PARAM, false, true), - Xd_p = PartamsMetadata(DEVICE_PARAM, false, true), - Xq_p = PartamsMetadata(DEVICE_PARAM, false, true), - Td0_p = PartamsMetadata(DEVICE_PARAM, false, false), - Tq0_p = PartamsMetadata(DEVICE_PARAM, false, false), + R = ParamsMetadata(DEVICE_PARAM, false, true), + Xd = ParamsMetadata(DEVICE_PARAM, false, true), + Xq = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_p = ParamsMetadata(DEVICE_PARAM, false, true), + Xq_p = ParamsMetadata(DEVICE_PARAM, false, true), + Td0_p = ParamsMetadata(DEVICE_PARAM, false, false), + Tq0_p = ParamsMetadata(DEVICE_PARAM, false, false), ) #= #TODO - SimpleMarconatoMachine @@ -749,35 +749,38 @@ get_params_metadata(::PSY.DEGOV) = ( T6 = ParamsMetadata(DEVICE_PARAM, true, false), Td = ParamsMetadata(DEVICE_PARAM, false, false), ) -#= -get_params(x::PSY.TGTypeII) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_T2(x)] + +#= get_params(x::PSY.TGTypeII) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_T2(x)] get_params_metadata(::PSY.TGTypeII) = [ ParamsMetadata(:R_tg_TurbineGovR, false, false, true, false), ParamsMetadata(:T1_TurbineGov, false, false, true, false), ParamsMetadata(:T2_TurbineGov, false, false, true, false), -] -get_params(x::PSY.GasTG) = [ - PSY.get_R(x), - PSY.get_T1(x), - PSY.get_T2(x), - PSY.get_T3(x), - PSY.get_AT(x), - PSY.get_Kt(x), - PSY.get_V_lim(x)[1], - PSY.get_V_lim(x)[2], - PSY.get_D_turb(x), -] -get_params_metadata(::PSY.GasTG) = [ - ParamsMetadata(:R_TurbineGov, false, false, true, false), - ParamsMetadata(:T1_TurbineGov, false, false, false, false), - ParamsMetadata(:T2_TurbineGov, false, false, false, false), - ParamsMetadata(:T3_TurbineGov, false, false, false, false), - ParamsMetadata(:AT_TurbineGov, false, false, true, false), - ParamsMetadata(:Kt_TurbineGov, false, false, true, false), - ParamsMetadata(:V_min_TurbineGov, false, false, true, false), - ParamsMetadata(:V_max_TurbineGov, false, false, true, false), - ParamsMetadata(:D_turb_TurbineGov, false, false, true, false), -] +] =# +get_params(x::PSY.GasTG) = ( + R = PSY.get_R(x), + T1 = PSY.get_T1(x), + T2 = PSY.get_T2(x), + T3 = PSY.get_T3(x), + AT = PSY.get_AT(x), + Kt = PSY.get_Kt(x), + V_lim = (min = PSY.get_V_lim(x)[1], max = PSY.get_V_lim(x)[2]), + D_turb = PSY.get_D_turb(x), +) +get_params_metadata(::PSY.GasTG) = ( + R = ParamsMetadata(DEVICE_PARAM, false, true), + T1 = ParamsMetadata(DEVICE_PARAM, false, false), + T2 = ParamsMetadata(DEVICE_PARAM, false, false), + T3 = ParamsMetadata(DEVICE_PARAM, false, false), + AT = ParamsMetadata(DEVICE_PARAM, false, true), + Kt = ParamsMetadata(DEVICE_PARAM, false, true), + V_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, true), + max = ParamsMetadata(DEVICE_PARAM, false, true), + ), + D_turb = ParamsMetadata(DEVICE_PARAM, false, true), +) + +#= get_params(x::PSY.TGTypeI) = [ PSY.get_R(x), PSY.get_Ts(x), diff --git a/test/test_base.jl b/test/test_base.jl index 3b209c991..efae885d9 100644 --- a/test/test_base.jl +++ b/test/test_base.jl @@ -472,11 +472,8 @@ end ωref_affect_f = PSID.get_affect(inputs, threebus_sys, ωref) cref_affect_f(integrator_for_test) ωref_affect_f(integrator_for_test) - p_ix1 = PSID.get_p_range(PSID.get_dynamic_injectors(inputs)[1]) - p_ix2 = PSID.get_p_range(PSID.get_dynamic_injectors(inputs)[2]) - - @test PSID.get_P_ref(inputs.dynamic_injectors[1]) == 10.0 - @test PSID.get_ω_ref(inputs.dynamic_injectors[2]) == 0.9 + @test inputs.parameters["generator-102-1"][:refs][:P_ref] == 10.0 + @test inputs.parameters["generator-103-1"][:refs][:ω_ref] == 0.9 inputs = PSID.SimulationInputs( ResidualModel, threebus_sys, @@ -531,14 +528,10 @@ end ltrip_affect_f = PSID.get_affect(inputs, threebus_sys, load_trip) lref_affect_f(integrator_for_test) - zip_load1 = - first(filter(x -> PSY.get_name(x) == "BUS 1", PSID.get_static_loads(inputs))) - @test PSID.get_P_impedance(zip_load1) == 10.0 + @test inputs.parameters["BUS 1"][:refs][:P_impedance] == 10.0 ltrip_affect_f(integrator_for_test) - zip_load2 = - first(filter(x -> PSY.get_name(x) == "BUS 2", PSID.get_static_loads(inputs))) - @test PSID.get_P_impedance(zip_load2) == 0.0 - @test PSID.get_Q_impedance(zip_load2) == 0.0 + @test inputs.parameters["BUS 2"][:refs][:P_impedance] == 0.0 + @test inputs.parameters["BUS 2"][:refs][:Q_impedance] == 0.0 end @testset "Global Index" begin @@ -803,7 +796,6 @@ end 1, 1:6, 1:6, - 1:6, 1:9, 100.0, 60.0, From 57dca4b87b8870348d327ef5ffdfad158bb54c52 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 25 Jun 2024 08:31:58 -0400 Subject: [PATCH 32/76] update rev --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c656355a5..6501ddcb8 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PowerSimulationsDynamics" uuid = "398b2ede-47ed-4edc-b52e-69e4a48b4336" authors = ["Jose Daniel Lara, Rodrigo Henriquez"] -version = "0.14.1" +version = "0.14.2" [deps] ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" From d9878ffd5625f7b2f1902ed4a22af4c3fda0d684 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 25 Jun 2024 18:25:39 -0400 Subject: [PATCH 33/76] changes and convert models to pass surrogate tests --- src/base/nlsolve_wrapper.jl | 8 +- src/base/sensitivity_analysis.jl | 16 ++- src/base/simulation_inputs.jl | 2 +- .../generator_components/init_machine.jl | 48 +++++--- src/initialization/init_device.jl | 14 ++- .../init_frequency_estimator.jl | 30 +++-- .../inverter_components/init_inner.jl | 36 +++--- .../inverter_components/init_outer.jl | 24 ++-- src/models/generator_models/machine_models.jl | 37 +++--- .../frequency_estimator_models.jl | 17 ++- .../inverter_models/inner_control_models.jl | 12 +- .../inverter_models/outer_control_models.jl | 44 +++---- src/utils/parameters.jl | 116 ++++++++++++++++-- 13 files changed, 265 insertions(+), 139 deletions(-) diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index 03716f400..dbcc12ee2 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -128,8 +128,14 @@ function _check_residual( end function _refine_initial_condition!(x0, p, prob) + h(p, t; idxs = nothing) = typeof(idxs) <: Number ? x0[idxs] : x0 function ff(u, x0, p) - prob.f.f(u, x0, p, 0.0) + if typeof(prob) <: SciMLBase.ODEProblem + prob.f.f(u, x0, p, 0.0) + elseif typeof(prob) <: SciMLBase.DDEProblem + prob.f.f(u, x0, h, p, 0.0) + end + return end #residual = similar(x0) #ff(residual, x0, p) #Error: ERROR: AssertionError: length(getcolptr(S)) == size(S, 2) + 1 && (getcolptr(S))[end] - 1 == length(rowvals(S)) == length(nonzeros(S)) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index e5c4c7a68..02fc8c365 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -2,12 +2,16 @@ function get_indices_in_parameter_vector(p, device_param_pairs) indices = Int[] for tuple in device_param_pairs label = join((tuple[1], "params", tuple[2:end]...), ".") - ix = ComponentArrays.label2index(p, label)[1] + ix = ComponentArrays.label2index(p, label) if ix === nothing @error "Index not found for entry $tuple" return nothing end - push!(indices, ix) + if isa(ix, AbstractArray) + indices = vcat(indices, ix) + else + push!(indices, ix) + end end return indices end @@ -68,7 +72,8 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; p_metadata = sim.inputs.parameters_metadata p = sim.inputs.parameters param_ixs = get_indices_in_parameter_vector(p, param_data) - init_level = get_required_initialization_level(p_metadata, param_ixs) + metadata_ixs = get_indices_in_parameter_vector(p_metadata, param_data) + init_level = get_required_initialization_level(p_metadata, metadata_ixs) if init_level === nothing return nothing end @@ -116,6 +121,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; else x0 = deepcopy(sim.x0_init) sys = deepcopy(sim.sys) + sim_inputs = deepcopy(sim.inputs_init) function f_enzyme(p, x0, sys, sim_inputs, prob, data, init_level) #Make separate f_enzymes depending on init_level? p_new = sim_inputs.parameters p_new[param_ixs] .= p @@ -144,7 +150,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; p, x0, sys, - deepcopy(sim.inputs_init), + sim_inputs, prob_new, data, init_level, @@ -154,7 +160,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; dp = Enzyme.make_zero(p) dx0 = Enzyme.make_zero(x0) dsys = Enzyme.make_zero(sys) - sim_inputs = deepcopy(sim.inputs_init) + #sim_inputs = deepcopy(sim.inputs_init) dsim_inputs = Enzyme.make_zero(sim_inputs) dprob_new = Enzyme.make_zero(prob_new) ddata = Enzyme.make_zero(data) diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index 1bd2b3dc2..3182d0258 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -75,7 +75,7 @@ function SimulationInputs( parameter_metadata = _add_parameters_metadata(parameter_metadata, wrapped_static_injectors) end - @assert length(initial_parameters) == length(parameter_metadata) + #@assert length(initial_parameters) == length(parameter_metadata) Can be different with parameters that are vectors (e.g. NN) mass_matrix = _make_mass_matrix(wrapped_injectors, n_vars, n_buses) DAE_vector = _make_DAE_vector(mass_matrix, n_vars, n_buses) _adjust_states!( diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index 94669cf80..540977d71 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -178,7 +178,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{PSY.SauerPaiMachine, S, A, TG, P}}, inner_vars::AbstractVector, @@ -196,20 +196,9 @@ function initialize_mach_shaft!( I = conj(S0 / V) #Machine Data - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) - Xq_pp = PSY.get_Xq_pp(machine) - Xl = PSY.get_Xl(machine) - Td0_p = PSY.get_Td0_p(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) - γ_q2 = PSY.get_γ_q2(machine) + params = p[:params][:Machine] + R = params[:R] + Xq = params[:Xq] #States of SauerPaiMachine are [1] ψq, [2] ψd, [3] eq_p, [4] ed_p, [5] ψd_pp and [6] ψq_pp δ0 = angle(V + (R + Xq * 1im) * I) @@ -217,7 +206,7 @@ function initialize_mach_shaft!( τm0 = real(V * conj(I)) @assert isapprox(τm0, P0; atol = STRICT_NLSOLVE_F_TOLERANCE) #To solve: δ, τm, Vf0, eq_p, ed_p - function f!(out, x) + function f!(out, x, params) δ = x[1] τm = x[2] Vf0 = x[3] @@ -228,6 +217,19 @@ function initialize_mach_shaft!( ψd_pp = x[8] ψq_pp = x[9] + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xq_pp = params[:Xq_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] + γ_q2 = params[:γ_q2] + V_dq = ri_dq(δ) * [V_R; V_I] i_d = (1.0 / Xd_pp) * (γ_d1 * eq_p - ψd + (1 - γ_d1) * ψd_pp) #15.15 i_q = (1.0 / Xq_pp) * (-γ_q1 * ed_p - ψq + (1 - γ_q1) * ψq_pp) #15.15 @@ -247,13 +249,19 @@ function initialize_mach_shaft!( V_dq0 = ri_dq(δ0) * [V_R; V_I] x0 = [δ0, τm0, 1.0, V_dq0[1], V_dq0[2], V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( - "Initialization in Machine $(PSY.get_name(static)) failed" + "Initialization of Machine in $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages inner_vars[VR_gen_var] = V_R inner_vars[VI_gen_var] = V_I diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index a59f10722..b24fbcf28 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -130,7 +130,7 @@ function initialize_dynamic_device!( R_th = PSY.get_R_th(source) X_th = PSY.get_X_th(source) Zmag = R_th^2 + X_th^2 - function f!(out, x) + function f!(out, x, p) V_R_internal = x[1] V_I_internal = x[2] @@ -140,11 +140,17 @@ function initialize_dynamic_device!( R_th * (V_I_internal - V_I) / Zmag - X_th * (V_R_internal - V_R) / Zmag - I_I end x0 = [V_R, V_I] - sol = NLsolve.nlsolve(f!, x0) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, nothing) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn("Initialization in Periodic Variable Source failed") else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages V_internal = sqrt(sol_x0[1]^2 + sol_x0[2]^2) θ_internal = atan(sol_x0[2], sol_x0[1]) diff --git a/src/initialization/inverter_components/init_frequency_estimator.jl b/src/initialization/inverter_components/init_frequency_estimator.jl index 8a2e02d79..ffc712f42 100644 --- a/src/initialization/inverter_components/init_frequency_estimator.jl +++ b/src/initialization/inverter_components/init_frequency_estimator.jl @@ -73,7 +73,7 @@ end function initialize_frequency_estimator!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, IC, DC, PSY.ReducedOrderPLL, F, L}, @@ -91,20 +91,20 @@ function initialize_frequency_estimator!( Vi_filter = inner_vars[Vi_filter_var] #Get parameters - pll_control = PSY.get_freq_estimator(dynamic_device) - kp_pll = PSY.get_kp_pll(pll_control) - ki_pll = PSY.get_ki_pll(pll_control) + params = p[:params][:FrequencyEstimator] #Get initial guess θ0_pll = atan(Vi_filter, Vr_filter) Vpll_q0 = 0.0 ϵ_pll0 = 0.0 - function f!(out, x) + function f!(out, x, params) vpll_q = x[1] ϵ_pll = x[2] θ_pll = x[3] + kp_pll = params[:kp_pll] + ki_pll = params[:ki_pll] V_dq_pll = ri_dq(θ_pll + pi / 2) * [Vr_filter; Vi_filter] out[1] = V_dq_pll[q] - vpll_q @@ -113,11 +113,17 @@ function initialize_frequency_estimator!( end x0 = [Vpll_q0, ϵ_pll0, θ0_pll] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn("Initialization in PLL failed") else - sol_x0 = sol.zero + sol_x0 = sol.u #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.ReducedOrderPLL) @@ -129,7 +135,7 @@ function initialize_frequency_estimator!( pll_states[3] = sol_x0[3] #Update guess of frequency estimator - inner_vars[ω_freq_estimator_var] = get_ω_ref(dynamic_device) + inner_vars[ω_freq_estimator_var] = p[:refs][:ω_ref] inner_vars[θ_freq_estimator_var] = sol_x0[3] end return @@ -137,7 +143,7 @@ end function initialize_frequency_estimator!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, IC, DC, PSY.FixedFrequency, F, L}, @@ -152,9 +158,7 @@ function initialize_frequency_estimator!( L <: Union{Nothing, PSY.InverterLimiter}, } #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.FixedFrequency) - internal_params = @view device_parameters[local_ix_params] - frequency = internal_params[1] + frequency = p[:params][:FrequencyEstimator][:frequency] #Update guess of frequency estimator inner_vars[ω_freq_estimator_var] = frequency diff --git a/src/initialization/inverter_components/init_inner.jl b/src/initialization/inverter_components/init_inner.jl index 98aa36aba..463c02de2 100644 --- a/src/initialization/inverter_components/init_inner.jl +++ b/src/initialization/inverter_components/init_inner.jl @@ -147,7 +147,7 @@ end function initialize_inner!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, PSY.CurrentModeControl, DC, P, F, L}, @@ -171,7 +171,7 @@ function initialize_inner!( Vi_filter = device_states[external_ix[6]] #Obtain inner variables for component - ω_oc = get_ω_ref(dynamic_device) + ω_oc = p[:refs][:ω_ref] θ0_oc = inner_vars[θ_freq_estimator_var] Vdc = inner_vars[Vdc_var] Id_cnv_ref = inner_vars[Id_oc_var] @@ -182,17 +182,15 @@ function initialize_inner!( Vi_cnv0 = inner_vars[Vi_cnv_var] #Get Current Controller parameters - inner_control = PSY.get_inner_control(dynamic_device) - filter = PSY.get_filter(dynamic_device) - kpc = PSY.get_kpc(inner_control) - kic = PSY.get_kic(inner_control) - kffv = PSY.get_kffv(inner_control) - lf = PSY.get_lf(filter) - - function f!(out, x) + kpc = p[:params][:InnerControl][:kpc] + kic = p[:params][:InnerControl][:kic] + kffv = p[:params][:InnerControl][:kffv] + lf = p[:params][:Filter][:lf] + params = [kpc, kic, kffv, lf] + function f!(out, x, params) γ_d = x[1] γ_q = x[2] - + kpc, kic, kffv, lf = params #Reference Frame Transformations I_dq_cnv = ri_dq(θ0_oc + pi / 2) * [Ir_cnv; Ii_cnv] V_dq_filter = ri_dq(θ0_oc + pi / 2) * [Vr_filter; Vi_filter] @@ -214,11 +212,19 @@ function initialize_inner!( out[2] = Vq_cnv_ref - V_dq_cnv0[q] end x0 = [0.0, 0.0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) - @warn("Initialization in Inner Control failed") + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) + @warn( + "Initialization of AVR in $(PSY.get_name(static)) failed" + ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update Converter modulation m0_dq = (ri_dq(θ0_oc + pi / 2) * [Vr_cnv0; Vi_cnv0]) ./ Vdc inner_vars[md_var] = m0_dq[d] diff --git a/src/initialization/inverter_components/init_outer.jl b/src/initialization/inverter_components/init_outer.jl index db4a06806..1c5d47011 100644 --- a/src/initialization/inverter_components/init_outer.jl +++ b/src/initialization/inverter_components/init_outer.jl @@ -69,7 +69,7 @@ end function initialize_outer!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -124,14 +124,14 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc - inner_vars[ω_oc_var] = get_ω_ref(dynamic_device) + inner_vars[ω_oc_var] = p[:refs][:ω_ref] #Update Q_ref. Initialization assumes q_ref = q_elec_out of PF solution - set_P_ref(dynamic_device, p_elec_out) + set_P_ref!(p, p_elec_out) PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - set_Q_ref(dynamic_device, q_elec_out) + set_Q_ref!(p, q_elec_out) end function initialize_outer!( @@ -202,7 +202,7 @@ end function initialize_outer!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -244,12 +244,8 @@ function initialize_outer!( q_elec_out = -Ii_filter * Vr_filter + Ir_filter * Vi_filter #Get Outer Controller parameters - outer_control = PSY.get_outer_control(dynamic_device) - active_power_control = PSY.get_active_power_control(outer_control) - Ki_p = PSY.get_Ki_p(active_power_control) #Integral Gain - reactive_power_control = PSY.get_reactive_power_control(outer_control) - Ki_q = PSY.get_Ki_q(reactive_power_control) #Integral Gain - + Ki_p = p[:params][:OuterControl][:ActivePowerControl][:Ki_p] + Ki_q = p[:params][:OuterControl][:ReactivePowerControl][:Ki_q] #Update inner_vars inner_vars[P_ES_var] = p_elec_out #Update states @@ -265,16 +261,16 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc - inner_vars[ω_oc_var] = get_ω_ref(dynamic_device) + inner_vars[ω_oc_var] = p[:refs][:ω_ref] inner_vars[Id_oc_var] = I_dq_cnv[d] inner_vars[Iq_oc_var] = I_dq_cnv[q] #Update Q_ref. Initialization assumes q_ref = q_elec_out from PF solution - set_P_ref(dynamic_device, p_elec_out) + set_P_ref!(p, p_elec_out) PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - set_Q_ref(dynamic_device, q_elec_out) + set_Q_ref!(p, q_elec_out) PSY.set_Q_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), q_elec_out, diff --git a/src/models/generator_models/machine_models.jl b/src/models/generator_models/machine_models.jl index fb9708e89..da3405ca9 100644 --- a/src/models/generator_models/machine_models.jl +++ b/src/models/generator_models/machine_models.jl @@ -136,7 +136,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -170,23 +170,24 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #Get parameters - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) - Xq_pp = PSY.get_Xq_pp(machine) - Xl = PSY.get_Xl(machine) - Td0_p = PSY.get_Td0_p(machine) - Tq0_p = PSY.get_Tq0_p(machine) - Td0_pp = PSY.get_Td0_pp(machine) - Tq0_pp = PSY.get_Tq0_pp(machine) - γ_d1 = PSY.get_γ_d1(machine) - γ_q1 = PSY.get_γ_q1(machine) - γ_d2 = PSY.get_γ_d2(machine) - γ_q2 = PSY.get_γ_q2(machine) + params = p[:params][:Machine] + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xq_pp = params[:Xq_pp] + Xl = params[:Xl] + Td0_p = params[:Td0_p] + Tq0_p = params[:Tq0_p] + Td0_pp = params[:Td0_pp] + Tq0_pp = params[:Tq0_pp] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] + γ_q2 = params[:γ_q2] + basepower = PSY.get_base_power(dynamic_device) `` #RI to dq transformation diff --git a/src/models/inverter_models/frequency_estimator_models.jl b/src/models/inverter_models/frequency_estimator_models.jl index 455aa1d33..2f2638a96 100644 --- a/src/models/inverter_models/frequency_estimator_models.jl +++ b/src/models/inverter_models/frequency_estimator_models.jl @@ -77,7 +77,7 @@ end function mdl_freq_estimator_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -100,10 +100,10 @@ function mdl_freq_estimator_ode!( Vi_filter = device_states[external_ix[2]] #Get parameters - pll_control = PSY.get_freq_estimator(dynamic_device) - ω_lp = PSY.get_ω_lp(pll_control) - kp_pll = PSY.get_kp_pll(pll_control) - ki_pll = PSY.get_ki_pll(pll_control) + params = p[:params][:FrequencyEstimator] + ω_lp = params[:ω_lp] + kp_pll = params[:kp_pll] + ki_pll = params[:ki_pll] f0 = get_system_base_frequency(dynamic_device) ωb = 2.0 * pi * f0 @@ -141,7 +141,7 @@ end function mdl_freq_estimator_ode!( ::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -158,10 +158,7 @@ function mdl_freq_estimator_ode!( L <: Union{Nothing, PSY.InverterLimiter}, } #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.FixedFrequency) - internal_params = @view device_parameters[local_ix_params] - frequency = internal_params[1] - + frequency = p[:params][:FrequencyEstimator][:frequency] #Update inner_vars #PLL frequency inner_vars[ω_freq_estimator_var] = frequency diff --git a/src/models/inverter_models/inner_control_models.jl b/src/models/inverter_models/inner_control_models.jl index fed883266..fbba6a728 100644 --- a/src/models/inverter_models/inner_control_models.jl +++ b/src/models/inverter_models/inner_control_models.jl @@ -278,7 +278,7 @@ end function mdl_inner_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, PSY.CurrentModeControl, DC, P, F, L}, @@ -309,12 +309,10 @@ function mdl_inner_ode!( Vdc = inner_vars[Vdc_var] #Get Current Controller parameters - inner_control = PSY.get_inner_control(dynamic_device) - filter = PSY.get_filter(dynamic_device) - kpc = PSY.get_kpc(inner_control) - kic = PSY.get_kic(inner_control) - kffv = PSY.get_kffv(inner_control) - lf = PSY.get_lf(filter) + kpc = p[:params][:InnerControl][:kpc] + kic = p[:params][:InnerControl][:kic] + kffv = p[:params][:InnerControl][:kffv] + lf = p[:params][:Filter][:lf] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.CurrentModeControl) diff --git a/src/models/inverter_models/outer_control_models.jl b/src/models/inverter_models/outer_control_models.jl index 968af222a..78e6c58d0 100644 --- a/src/models/inverter_models/outer_control_models.jl +++ b/src/models/inverter_models/outer_control_models.jl @@ -723,7 +723,7 @@ end function mdl_outer_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -759,23 +759,21 @@ function mdl_outer_ode!( Ii_filter = device_states[external_ix[4]] #Get Active Power Controller parameters - outer_control = PSY.get_outer_control(dynamic_device) - active_power_control = PSY.get_active_power_control(outer_control) - Rp = PSY.get_Rp(active_power_control) #Droop Gain - ωz = PSY.get_ωz(active_power_control) #Frequency cutoff frequency + Rp = p[:params][:OuterControl][:ActivePowerControl][:Rp] #Droop Gain + ωz = p[:params][:OuterControl][:ActivePowerControl][:ωz] #Frequency cutoff frequency + f0 = get_system_base_frequency(dynamic_device) ωb = 2 * pi * f0 #Rated angular frequency #Get Reactive Power Controller parameters - reactive_power_control = PSY.get_reactive_power_control(outer_control) - kq = PSY.get_kq(reactive_power_control) #Reactive power droop gain - ωf = PSY.get_ωf(reactive_power_control) #Reactive power filter cutoff frequency + kq = p[:params][:OuterControl][:ReactivePowerControl][:kq] + ωf = p[:params][:OuterControl][:ReactivePowerControl][:ωf] #Obtain external parameters - p_ref = get_P_ref(dynamic_device) - ω_ref = get_ω_ref(dynamic_device) - V_ref = get_V_ref(dynamic_device) - q_ref = get_Q_ref(dynamic_device) + p_ref = p[:refs][:P_ref] + ω_ref = p[:refs][:ω_ref] + V_ref = p[:refs][:V_ref] + q_ref = p[:refs][:Q_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix( @@ -800,6 +798,7 @@ function mdl_outer_ode!( _, dpm_dt = low_pass(p_elec_out, pm, 1.0, 1.0 / ωz) _, dqm_dt = low_pass(q_elec_out, qm, 1.0, 1.0 / ωf) + outer_control = PSY.get_outer_control(dynamic_device) ext = PSY.get_ext(outer_control) bool_val = get(ext, "is_not_reference", 1.0) @@ -915,7 +914,7 @@ end function mdl_outer_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -955,21 +954,18 @@ function mdl_outer_ode!( ω_pll = inner_vars[ω_freq_estimator_var] #Get Active Power Controller parameters - outer_control = PSY.get_outer_control(dynamic_device) - active_power_control = PSY.get_active_power_control(outer_control) - Kp_p = PSY.get_Kp_p(active_power_control) #Proportional Gain - Ki_p = PSY.get_Ki_p(active_power_control) #Integral Gain - ωz = PSY.get_ωz(active_power_control) #Frequency cutoff frequency + Kp_p = p[:params][:OuterControl][:ActivePowerControl][:Kp_p] + Ki_p = p[:params][:OuterControl][:ActivePowerControl][:Ki_p] + ωz = p[:params][:OuterControl][:ActivePowerControl][:ωz] #Get Reactive Power Controller parameters - reactive_power_control = PSY.get_reactive_power_control(outer_control) - Kp_q = PSY.get_Kp_q(reactive_power_control) #Proportional Gain - Ki_q = PSY.get_Ki_q(reactive_power_control) #Integral Gain - ωf = PSY.get_ωf(reactive_power_control) #Reactive power filter cutoff frequency + Kp_q = p[:params][:OuterControl][:ReactivePowerControl][:Kp_q] + Ki_q = p[:params][:OuterControl][:ReactivePowerControl][:Ki_q] + ωf = p[:params][:OuterControl][:ReactivePowerControl][:ωf] #Obtain external parameters - p_ref = get_P_ref(dynamic_device) - q_ref = get_Q_ref(dynamic_device) + p_ref = p[:refs][:P_ref] + q_ref = p[:refs][:Q_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix( diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index 25dbfb90d..d1f0f4897 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -17,12 +17,33 @@ function get_params(x) @error "Parameters not yet defined for component: $(typeof(x))" (;) end +function get_params_metadata(x) + @error "Parameters metadata not yet defined for component: $(typeof(x))" + (;) +end +#Overloads for refs +PSY.get_V_ref(x) = 0.0 +PSY.get_ω_ref(x) = 0.0 +PSY.get_P_ref(x) = 0.0 get_params_metadata(::T) where {T <: PSY.DynamicComponent} = (;) -get_params(::PSY.ActivePowerControl) = (;) -get_params_metadata(::PSY.ActivePowerControl) = (;) -get_params(::PSY.ReactivePowerControl) = (;) -get_params_metadata(::PSY.ReactivePowerControl) = (;) + +function get_params(x::PSY.ActivePowerControl) + @error "Parameters not yet defined for component: $(typeof(x))" + (;) +end +function get_params_metadata(x::PSY.ActivePowerControl) + @error "Parameters metadata not yet defined for component: $(typeof(x))" + (;) +end +function get_params(x::PSY.ReactivePowerControl) + @error "Parameters not yet defined for component: $(typeof(x))" + (;) +end +function get_params_metadata(x::PSY.ReactivePowerControl) + @error "Parameters metadata not yet defined for component: $(typeof(x))" + (;) +end get_params( d::DynamicWrapper{T}, @@ -105,6 +126,21 @@ get_params_metadata(x::PSY.OuterControl) = ( ReactivePowerControl = get_params_metadata(PSY.get_reactive_power_control(x)), ) #ACTIVE POWER CONTROL +get_params(x::PSY.ActivePowerPI) = ( + Kp_p = PSY.get_Kp_p(x), + Ki_p = PSY.get_Ki_p(x), + ωz = PSY.get_ωz(x), +) +get_params_metadata(::PSY.ActivePowerPI) = ( + Kp_p = ParamsMetadata(DEVICE_PARAM, false, false), + Ki_p = ParamsMetadata(DEVICE_PARAM, false, true), + ωz = ParamsMetadata(DEVICE_PARAM, false, false), +) +get_params(x::PSY.ActivePowerDroop) = (Rp = PSY.get_Rp(x), ωz = PSY.get_ωz(x)) +get_params_metadata(::PSY.ActivePowerDroop) = ( + Rp = ParamsMetadata(DEVICE_PARAM, false, false), + ωz = ParamsMetadata(DEVICE_PARAM, false, false), +) get_params(x::PSY.VirtualInertia) = (Ta = PSY.get_Ta(x), kd = PSY.get_kd(x), kω = PSY.get_kω(x)) get_params_metadata(::PSY.VirtualInertia) = ( @@ -152,6 +188,16 @@ get_params_metadata(::PSY.ActiveRenewableControllerAB) = ( T_pord = ParamsMetadata(DEVICE_PARAM, false, false), ) #REACTIVE POWER CONTROL +get_params(x::PSY.ReactivePowerPI) = ( + Kp_q = PSY.get_Kp_q(x), + Ki_q = PSY.get_Ki_q(x), + ωf = PSY.get_ωf(x), +) +get_params_metadata(::PSY.ReactivePowerPI) = ( + Kp_q = ParamsMetadata(DEVICE_PARAM, false, false), + Ki_q = ParamsMetadata(DEVICE_PARAM, false, true), + ωf = ParamsMetadata(DEVICE_PARAM, false, false), +) get_params(x::PSY.ReactivePowerDroop) = (kq = PSY.get_kq(x), ωf = PSY.get_ωf(x)) get_params_metadata(::PSY.ReactivePowerDroop) = ( kq = ParamsMetadata(DEVICE_PARAM, false, false), @@ -238,6 +284,16 @@ get_params_metadata(::PSY.VoltageModeControl) = ( ωad = ParamsMetadata(DEVICE_PARAM, false, false), kad = ParamsMetadata(DEVICE_PARAM, false, true), ) +get_params(x::PSY.CurrentModeControl) = ( + kpc = PSY.get_kpc(x), + kic = PSY.get_kic(x), + kffv = PSY.get_kffv(x), +) +get_params_metadata(::PSY.CurrentModeControl) = ( + kpc = ParamsMetadata(DEVICE_PARAM, false, true), + kic = ParamsMetadata(DEVICE_PARAM, false, true), + kffv = ParamsMetadata(DEVICE_PARAM, false, true), +) #= get_params(x::PSY.RECurrentControlB) = [ PSY.get_Vdip_lim(x)[1], @@ -286,10 +342,20 @@ get_params_metadata(::PSY.KauraPLL) = ( kp_pll = ParamsMetadata(DEVICE_PARAM, false, true), ki_pll = ParamsMetadata(DEVICE_PARAM, false, true), ) -#= get_params(x::PSY.FixedFrequency) = [PSY.get_frequency(x)] +get_params(x::PSY.ReducedOrderPLL) = ( + ω_lp = PSY.get_ω_lp(x), + kp_pll = PSY.get_kp_pll(x), + ki_pll = PSY.get_ki_pll(x), +) +get_params_metadata(::PSY.ReducedOrderPLL) = ( + ω_lp = ParamsMetadata(DEVICE_PARAM, false, false), + kp_pll = ParamsMetadata(DEVICE_PARAM, false, true), + ki_pll = ParamsMetadata(DEVICE_PARAM, false, true), +) +get_params(x::PSY.FixedFrequency) = (; frequency = PSY.get_frequency(x)) get_params_metadata(::PSY.FixedFrequency) = - [ParamsMetadata(:frequency_FrequencyEstimator, false, false, false, false)] - =# + (; frequency = ParamsMetadata(DEVICE_PARAM, false, true)) + #CONVERTER get_params(::PSY.AverageConverter) = (;) get_params_metadata(::PSY.AverageConverter) = (;) @@ -379,6 +445,42 @@ get_params_metadata(::PSY.OneDOneQMachine) = ( Td0_p = ParamsMetadata(DEVICE_PARAM, false, false), Tq0_p = ParamsMetadata(DEVICE_PARAM, false, false), ) +get_params(x::PSY.SauerPaiMachine) = ( + R = PSY.get_R(x), + Xd = PSY.get_Xd(x), + Xq = PSY.get_Xq(x), + Xd_p = PSY.get_Xd_p(x), + Xq_p = PSY.get_Xq_p(x), + Xd_pp = PSY.get_Xd_pp(x), + Xq_pp = PSY.get_Xq_pp(x), + Xl = PSY.get_Xl(x), + Td0_p = PSY.get_Td0_p(x), + Tq0_p = PSY.get_Tq0_p(x), + Td0_pp = PSY.get_Td0_pp(x), + Tq0_pp = PSY.get_Tq0_pp(x), + γ_d1 = PSY.get_γ_d1(x), + γ_q1 = PSY.get_γ_q1(x), + γ_d2 = PSY.get_γ_d2(x), + γ_q2 = PSY.get_γ_q2(x), +) +get_params_metadata(::PSY.SauerPaiMachine) = ( + R = ParamsMetadata(DEVICE_PARAM, false, true), + Xd = ParamsMetadata(DEVICE_PARAM, false, true), + Xq = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_p = ParamsMetadata(DEVICE_PARAM, false, true), + Xq_p = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Xq_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Xl = ParamsMetadata(DEVICE_PARAM, false, true), + Td0_p = ParamsMetadata(DEVICE_PARAM, false, false), + Tq0_p = ParamsMetadata(DEVICE_PARAM, false, false), + Td0_pp = ParamsMetadata(DEVICE_PARAM, false, false), + Tq0_pp = ParamsMetadata(DEVICE_PARAM, false, false), + γ_d1 = ParamsMetadata(DEVICE_PARAM, false, true), + γ_q1 = ParamsMetadata(DEVICE_PARAM, false, true), + γ_d2 = ParamsMetadata(DEVICE_PARAM, false, true), + γ_q2 = ParamsMetadata(DEVICE_PARAM, false, true), +) #= #TODO - SimpleMarconatoMachine get_params(x::PSY.MarconatoMachine) = [ From 068051e7439152bb58349c9822d386af0a231943 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 27 Jun 2024 08:54:46 -0400 Subject: [PATCH 34/76] revert change --- src/base/sensitivity_analysis.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 02fc8c365..0db195964 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -121,7 +121,6 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; else x0 = deepcopy(sim.x0_init) sys = deepcopy(sim.sys) - sim_inputs = deepcopy(sim.inputs_init) function f_enzyme(p, x0, sys, sim_inputs, prob, data, init_level) #Make separate f_enzymes depending on init_level? p_new = sim_inputs.parameters p_new[param_ixs] .= p @@ -150,7 +149,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; p, x0, sys, - sim_inputs, + deepcopy(sim.inputs_init), prob_new, data, init_level, @@ -160,7 +159,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; dp = Enzyme.make_zero(p) dx0 = Enzyme.make_zero(x0) dsys = Enzyme.make_zero(sys) - #sim_inputs = deepcopy(sim.inputs_init) + sim_inputs = deepcopy(sim.inputs_init) dsim_inputs = Enzyme.make_zero(sim_inputs) dprob_new = Enzyme.make_zero(prob_new) ddata = Enzyme.make_zero(data) From e2fe76ff40d7f7a7580fa592427a4eb1da772876 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sun, 30 Jun 2024 16:00:33 -0400 Subject: [PATCH 35/76] remove td as parameter for degov --- src/models/generator_models/tg_models.jl | 3 ++- src/utils/parameters.jl | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index 8e4241441..4837b1aa5 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -370,7 +370,8 @@ function mdl_tg_ode!( T4 = params[:T4] T5 = params[:T5] T6 = params[:T6] - Td = params[:Td] + tg = PSY.get_prime_mover(device) + Td = PSY.get_Td(tg) #Compute block derivatives Δω = ω[1] - 1.0 diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index d1f0f4897..3183be763 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -839,7 +839,6 @@ get_params(x::PSY.DEGOV) = ( T4 = PSY.get_T4(x), T5 = PSY.get_T5(x), T6 = PSY.get_T6(x), - Td = PSY.get_Td(x), ) get_params_metadata(::PSY.DEGOV) = ( T1 = ParamsMetadata(DEVICE_PARAM, true, false), @@ -849,7 +848,6 @@ get_params_metadata(::PSY.DEGOV) = ( T4 = ParamsMetadata(DEVICE_PARAM, false, false), T5 = ParamsMetadata(DEVICE_PARAM, true, false), T6 = ParamsMetadata(DEVICE_PARAM, true, false), - Td = ParamsMetadata(DEVICE_PARAM, false, false), ) #= get_params(x::PSY.TGTypeII) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_T2(x)] From 96f64f38d9c592775aa41ad91393556eb406dc71 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sun, 30 Jun 2024 16:02:22 -0400 Subject: [PATCH 36/76] loosen dispatch for common controls (for sensitivity compatibility) --- src/models/common_controls.jl | 45 +++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/models/common_controls.jl b/src/models/common_controls.jl index c320f843b..ff7525ea7 100644 --- a/src/models/common_controls.jl +++ b/src/models/common_controls.jl @@ -13,9 +13,9 @@ u -> │ ────────────│ -> y function low_pass_modified_mass_matrix( u::Z, y::V, - K::Float64, + K::ACCEPTED_REAL_TYPES, K_den::W, - ::Float64, + ::ACCEPTED_REAL_TYPES, ) where {V <: ACCEPTED_REAL_TYPES, W <: ACCEPTED_REAL_TYPES, Z <: ACCEPTED_REAL_TYPES} return y, K * u - K_den * y end @@ -23,9 +23,9 @@ end function low_pass_modified( u::Z, y::V, - K::Float64, + K::ACCEPTED_REAL_TYPES, K_den::W, - T::Float64, + T::ACCEPTED_REAL_TYPES, ) where {V <: ACCEPTED_REAL_TYPES, W <: ACCEPTED_REAL_TYPES, Z <: ACCEPTED_REAL_TYPES} return y, (1.0 / T) * low_pass_modified_mass_matrix(u, y, K, K_den, T)[2] end @@ -52,8 +52,8 @@ end function low_pass( u::Z, y::V, - K::Float64, - T::Float64, + K::ACCEPTED_REAL_TYPES, + T::ACCEPTED_REAL_TYPES, ) where {V <: ACCEPTED_REAL_TYPES, Z <: ACCEPTED_REAL_TYPES} return low_pass_modified(u, y, K, 1.0, T) end @@ -133,14 +133,19 @@ Internal State: x function high_pass_mass_matrix( u::Z, x::Z, - K::Float64, - T::Float64, + K::ACCEPTED_REAL_TYPES, + T::ACCEPTED_REAL_TYPES, ) where {Z <: ACCEPTED_REAL_TYPES} K_T = T < eps() ? 0.0 : (K / T) return x + K_T * u, -(K_T * u + x) end -function high_pass(u::Z, x::Z, K::Float64, T::Float64) where {Z <: ACCEPTED_REAL_TYPES} +function high_pass( + u::Z, + x::Z, + K::ACCEPTED_REAL_TYPES, + T::ACCEPTED_REAL_TYPES, +) where {Z <: ACCEPTED_REAL_TYPES} y, dxdt_scaled = high_pass_mass_matrix(u, x, K, T) return y, (1.0 / T) * dxdt_scaled end @@ -230,10 +235,10 @@ function lead_lag_2nd_mass_matrix( u::Z, x1::Z, x2::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, ) where {Z <: ACCEPTED_REAL_TYPES} dx1dt = u - T1 * x1 - x2 dx2dt = x1 @@ -1527,10 +1532,10 @@ Integrator with windup limits function integrator_windup_mass_matrix( u::Z, y::Z, - K::Float64, + K::ACCEPTED_REAL_TYPES, ::Float64, - y_min::Float64, - y_max::Float64, + y_min::ACCEPTED_REAL_TYPES, + y_max::ACCEPTED_REAL_TYPES, ) where {Z <: ACCEPTED_REAL_TYPES} dydt_scaled = K * u y_sat = clamp(y, y_min, y_max) @@ -1541,10 +1546,10 @@ end function integrator_windup( u::Z, y::Z, - K::Float64, - T::Float64, - y_min::Float64, - y_max::Float64, + K::ACCEPTED_REAL_TYPES, + T::ACCEPTED_REAL_TYPES, + y_min::ACCEPTED_REAL_TYPES, + y_max::ACCEPTED_REAL_TYPES, ) where {Z <: ACCEPTED_REAL_TYPES} y_sat = clamp(y, y_min, y_max) return y_sat, (1.0 / T) * integrator_windup_mass_matrix(u, y, K, T, y_min, y_max)[2] From 57cd61ad6b2c85b34e1dc2df4f6b2aab5900c62d Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sun, 30 Jun 2024 18:15:22 -0400 Subject: [PATCH 37/76] add avrs and tgs --- .../generator_components/init_avr.jl | 56 ++++---- .../generator_components/init_tg.jl | 81 +++++++----- src/initialization/init_device.jl | 1 - src/models/generator_models/avr_models.jl | 37 +++--- src/models/generator_models/tg_models.jl | 31 +++-- src/utils/parameters.jl | 120 +++++++++--------- 6 files changed, 181 insertions(+), 145 deletions(-) diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index bc7da15f3..a24117dcb 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -17,7 +17,7 @@ end function initialize_avr!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRSimple, TG, P}}, inner_vars::AbstractVector, @@ -34,7 +34,7 @@ function initialize_avr!( #Set V_ref PSY.set_V_ref!(PSY.get_avr(dynamic_device), Vm) #Update Control Refs - set_V_ref(dynamic_device, Vm) + set_V_ref!(p, Vm) return end @@ -104,7 +104,7 @@ end function initialize_avr!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRTypeII, TG, P}}, inner_vars::AbstractVector, @@ -115,29 +115,33 @@ function initialize_avr!( Vm = sqrt(inner_vars[VR_gen_var]^2 + inner_vars[VI_gen_var]^2) #Get parameters + params = p[:params][:AVR] + K0 = params[:K0] + T1 = params[:T1] + T2 = params[:T2] + T3 = params[:T3] + T4 = params[:T4] + Va_min = params[:Va_lim][:min] + Va_max = params[:Va_lim][:max] + Ae = params[:Ae] + Be = params[:Be] avr = PSY.get_avr(dynamic_device) - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AVRTypeII) - internal_params = @view device_parameters[local_ix_params] - K0, - T1, - T2, - T3, - T4, - Te, - _, - Va_min, - Va_max, - Ae, - Be = internal_params - #Obtain saturated Vf - Se_Vf = Ae * (exp(Be * abs(Vf0))) #States of AVRTypeII are Vf, Vr1, Vr2, Vm #To solve V_ref, Vr1, Vr2 - function f!(out, x) + function f!(out, x, params) V_ref = x[1] Vr1 = x[2] Vr2 = x[3] + K0 = params[:K0] + T1 = params[:T1] + T2 = params[:T2] + T3 = params[:T3] + T4 = params[:T4] + Te = params[:Te] + + #Obtain saturated Vf + Se_Vf = Ae * (exp(Be * abs(Vf0))) y_ll1, dVr1_dt = lead_lag(V_ref - Vm, Vr1, K0, T2, T1) y_ll2, dVr2_dt = lead_lag(y_ll1, K0 * Vr2, 1.0, K0 * T4, K0 * T3) @@ -149,16 +153,22 @@ function initialize_avr!( out[3] = dVr2_dt #16.20 end x0 = [1.0, Vf0, Vf0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - set_V_ref(dynamic_device, sol_x0[1]) + set_V_ref!(p, sol_x0[1]) #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeII) avr_states = @view device_states[avr_ix] diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index b3b64fe2f..d472fcdb3 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -18,7 +18,7 @@ end function initialize_tg!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGTypeI, P}}, inner_vars::AbstractVector, @@ -29,21 +29,31 @@ function initialize_tg!( tg = PSY.get_prime_mover(dynamic_device) #Get Parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.TGTypeI) - internal_params = @view device_parameters[local_ix_params] - R, _, Tc, T3, T4, T5, V_min, V_max = internal_params - inv_R = R < eps() ? 0.0 : (1.0 / R) + params = p[:params][:TurbineGov] + R = params[:R] + Tc = params[:Tc] + T3 = params[:T3] + T4 = params[:T4] + T5 = params[:T5] + V_min = params[:valve_position_limits][:min] + V_max = params[:valve_position_limits][:max] #Get References - ω_ref = get_ω_ref(dynamic_device) + ω_ref = p[:refs][:ω_ref] ω0 = 1.0 - function f!(out, x) + function f!(out, x, params) P_ref = x[1] x_g1 = x[2] x_g2 = x[3] x_g3 = x[4] + R = params[:R] + Tc = params[:Tc] + T3 = params[:T3] + T4 = params[:T4] + T5 = params[:T5] #Compute auxiliary parameters + inv_R = R < eps() ? 0.0 : (1.0 / R) P_in = P_ref + inv_R * (ω_ref - ω0) out[1] = P_in - x_g1 @@ -57,16 +67,20 @@ function initialize_tg!( (1.0 - T3 / Tc) * τm0, (1.0 - T4 / T5) * ((1.0 - T3 / Tc) * τm0 + (T3 / Tc) * τm0), ] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) - @warn( - "Initialization of Turbine Governor $(PSY.get_name(static)) failed" - ) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) + @warn("Initialization of Turbine Governor $(PSY.get_name(static)) failed") else - sol_x0 = sol.zero + sol_x0 = sol.u #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - set_P_ref(dynamic_device, sol_x0[1]) + set_P_ref!(p, sol_x0[1]) #Update states tg_ix = get_local_state_ix(dynamic_device, PSY.TGTypeI) tg_states = @view device_states[tg_ix] @@ -84,7 +98,7 @@ end function initialize_tg!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGTypeII, P}}, inner_vars::AbstractVector, @@ -92,32 +106,39 @@ function initialize_tg!( #Get mechanical torque to SyncMach τm0 = inner_vars[τm_var] - #Get parameters tg = PSY.get_prime_mover(dynamic_device) - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.TGTypeII) - internal_params = @view device_parameters[local_ix_params] - R, T1, T2 = internal_params - inv_R = R < eps() ? 0.0 : (1.0 / R) - ω_ref = get_ω_ref(dynamic_device) - ω0 = ω_ref - function f!(out, x) + params = [ + p[:params][:TurbineGov][:R], + p[:params][:TurbineGov][:T1], + p[:params][:TurbineGov][:T2], + p[:refs][:ω_ref], + ] + + function f!(out, x, params) P_ref = x[1] xg = x[2] + R, T1, T2, ω_ref = params + ω0 = ω_ref + inv_R = R < eps() ? 0.0 : (1.0 / R) out[1] = inv_R * (T1 / T2) * (ω_ref - ω0) + P_ref / 1.0 + xg - τm0 out[2] = (1.0 / T2) * (inv_R * (1 - T2 / T1) * (ω_ref - ω0) - xg) end x0 = [τm0, 0.0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) - @warn( - "Initialization of Turbine Governor $(PSY.get_name(static)) failed" - ) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) + @warn("Initialization of Turbine Governor $(PSY.get_name(static)) failed") else - sol_x0 = sol.zero + sol_x0 = sol.u #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - set_P_ref(dynamic_device, sol_x0[1]) + set_P_ref!(p, sol_x0[1]) #Update states tg_ix = get_local_state_ix(dynamic_device, PSY.TGTypeII) tg_states = @view device_states[tg_ix] diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index b24fbcf28..9d81e8024 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -92,7 +92,6 @@ function initialize_static_device!( reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) - if !SciMLBase.successful_retcode(sol) @warn("Initialization in Source failed") else diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index 8141f9d51..d41722ce9 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -79,7 +79,7 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRSimple, TG, P}}, h, @@ -87,7 +87,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V_ref = get_V_ref(dynamic_device) + V_ref = p[:refs][:V_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.AVRSimple) @@ -100,9 +100,7 @@ function mdl_avr_ode!( V_th = sqrt(inner_vars[VR_gen_var]^2 + inner_vars[VI_gen_var]^2) #Get Parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AVRSimple) - internal_params = @view device_parameters[local_ix_params] - Kv = internal_params[1] + Kv = p[:params][:AVR][:Kv] #Compute ODEs output_ode[local_ix[1]] = Kv * (V_ref - V_th) @@ -176,7 +174,7 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.AVRTypeII, TG, P}}, h, @@ -184,7 +182,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = p[:refs][:V_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.AVRTypeII) @@ -201,19 +199,18 @@ function mdl_avr_ode!( Vs = inner_vars[V_pss_var] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AVRTypeII) - internal_params = @view device_parameters[local_ix_params] - K0, - T1, - T2, - T3, - T4, - Te, - Tr, - Va_min, - Va_max, - Ae, - Be = internal_params + params = p[:params][:AVR] + K0 = params[:K0] + T1 = params[:T1] + T2 = params[:T2] + T3 = params[:T3] + T4 = params[:T4] + Te = params[:Te] + Tr = params[:Tr] + Va_min = params[:Va_lim][:min] + Va_max = params[:Va_lim][:max] + Ae = params[:Ae] + Be = params[:Be] #Compute auxiliary parameters Se_Vf = Ae * exp(Be * abs(Vf)) #16.13 diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index 4837b1aa5..d818cd94d 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -46,7 +46,7 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGTypeI, P}}, @@ -55,8 +55,8 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - ω_ref = get_ω_ref(device) - P_ref = get_P_ref(device) + ω_ref = p[:refs][:ω_ref] + P_ref = p[:refs][:P_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.TGTypeI) @@ -72,9 +72,15 @@ function mdl_tg_ode!( ω = @view device_states[external_ix] #Get Parameters - local_ix_params = get_local_parameter_ix(device, PSY.TGTypeI) - internal_params = @view device_parameters[local_ix_params] - R, Ts, Tc, T3, T4, T5, V_min, V_max = internal_params + params = p[:params][:TurbineGov] + R = params[:R] + Ts = params[:Ts] + Tc = params[:Tc] + T3 = params[:T3] + T4 = params[:T4] + T5 = params[:T5] + V_min = params[:valve_position_limits][:min] + V_max = params[:valve_position_limits][:max] inv_R = R < eps() ? 0.0 : (1.0 / R) #Compute auxiliary parameters @@ -99,7 +105,7 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.TGTypeII, P}}, @@ -108,8 +114,8 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - ω_ref = get_ω_ref(device) - P_ref = get_P_ref(device) + ω_ref = p[:refs][:ω_ref] + P_ref = p[:refs][:P_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.TGTypeII) @@ -123,9 +129,10 @@ function mdl_tg_ode!( ω = @view device_states[external_ix] #Get parameters - local_ix_params = get_local_parameter_ix(device, PSY.TGTypeII) - internal_params = @view device_parameters[local_ix_params] - R, T1, T2 = internal_params + params = p[:params][:TurbineGov] + R = params[:R] + T1 = params[:T1] + T2 = params[:T2] inv_R = R < eps() ? 0.0 : (1.0 / R) #Compute block derivatives diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index 3183be763..6df5f08ad 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -666,10 +666,8 @@ get_params_metadata(::PSY.FiveMassShaft) = [ #AVRS get_params(::PSY.AVRFixed) = (;) get_params_metadata(::PSY.AVRFixed) = (;) - -#= get_params(x::PSY.AVRSimple) = [PSY.get_Kv(x)] -get_params_metadata(::PSY.AVRSimple) = [ParamsMetadata(:Kv_AVR, false, false, false, false)] - =# +get_params(x::PSY.AVRSimple) = (Kv = PSY.get_Kv(x),) +get_params_metadata(::PSY.AVRSimple) = (Kv = ParamsMetadata(DEVICE_PARAM, false, false),) get_params(x::PSY.AVRTypeI) = ( Ka = PSY.get_Ka(x), Ke = PSY.get_Ke(x), @@ -709,32 +707,34 @@ get_params_metadata(::PSY.SEXS) = ( max = ParamsMetadata(DEVICE_PARAM, false, true), ), ) -#= get_params(x::PSY.AVRTypeII) = [ - PSY.get_K0(x), - PSY.get_T1(x), - PSY.get_T2(x), - PSY.get_T3(x), - PSY.get_T4(x), - PSY.get_Te(x), - PSY.get_Tr(x), - PSY.get_Va_lim(x)[1], - PSY.get_Va_lim(x)[2], - PSY.get_Ae(x), - PSY.get_Be(x), -] -get_params_metadata(::PSY.AVRTypeII) = [ - ParamsMetadata(:K0_AVR, false, false, true, false), - ParamsMetadata(:T1_AVR, false, false, true, false), - ParamsMetadata(:T2_AVR, false, false, true, false), - ParamsMetadata(:T3_AVR, false, false, true, false), - ParamsMetadata(:T4_AVR, false, false, true, false), - ParamsMetadata(:Te_AVR, false, false, true, false), - ParamsMetadata(:Tr_AVR, false, false, false, false), - ParamsMetadata(:Va_min_AVR, false, false, true, false), - ParamsMetadata(:Va_max_AVR, false, false, true, false), - ParamsMetadata(:Ae_AVR, false, false, true, false), - ParamsMetadata(:Be_AVR, false, false, true, false), -] +get_params(x::PSY.AVRTypeII) = ( + K0 = PSY.get_K0(x), + T1 = PSY.get_T1(x), + T2 = PSY.get_T2(x), + T3 = PSY.get_T3(x), + T4 = PSY.get_T4(x), + Te = PSY.get_Te(x), + Tr = PSY.get_Tr(x), + Va_lim = PSY.get_Va_lim(x), + Ae = PSY.get_Ae(x), + Be = PSY.get_Be(x), +) +get_params_metadata(::PSY.AVRTypeII) = ( + K0 = ParamsMetadata(DEVICE_PARAM, false, true), + T1 = ParamsMetadata(DEVICE_PARAM, false, true), + T2 = ParamsMetadata(DEVICE_PARAM, false, true), + T3 = ParamsMetadata(DEVICE_PARAM, false, true), + T4 = ParamsMetadata(DEVICE_PARAM, false, true), + Te = ParamsMetadata(DEVICE_PARAM, false, true), + Tr = ParamsMetadata(DEVICE_PARAM, false, false), + Va_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, true), + max = ParamsMetadata(DEVICE_PARAM, false, true), + ), + Ae = ParamsMetadata(DEVICE_PARAM, false, true), + Be = ParamsMetadata(DEVICE_PARAM, false, true), +) +#= get_params(x::PSY.ESAC1A) = [ PSY.get_Tr(x), PSY.get_Tb(x), @@ -849,13 +849,16 @@ get_params_metadata(::PSY.DEGOV) = ( T5 = ParamsMetadata(DEVICE_PARAM, true, false), T6 = ParamsMetadata(DEVICE_PARAM, true, false), ) - -#= get_params(x::PSY.TGTypeII) = [PSY.get_R(x), PSY.get_T1(x), PSY.get_T2(x)] -get_params_metadata(::PSY.TGTypeII) = [ - ParamsMetadata(:R_tg_TurbineGovR, false, false, true, false), - ParamsMetadata(:T1_TurbineGov, false, false, true, false), - ParamsMetadata(:T2_TurbineGov, false, false, true, false), -] =# +get_params(x::PSY.TGTypeII) = ( + R = PSY.get_R(x), + T1 = PSY.get_T1(x), + T2 = PSY.get_T2(x), +) +get_params_metadata(::PSY.TGTypeII) = ( + R = ParamsMetadata(DEVICE_PARAM, false, true), + T1 = ParamsMetadata(DEVICE_PARAM, false, true), + T2 = ParamsMetadata(DEVICE_PARAM, false, true), +) get_params(x::PSY.GasTG) = ( R = PSY.get_R(x), T1 = PSY.get_T1(x), @@ -880,29 +883,28 @@ get_params_metadata(::PSY.GasTG) = ( D_turb = ParamsMetadata(DEVICE_PARAM, false, true), ) -#= -get_params(x::PSY.TGTypeI) = [ - PSY.get_R(x), - PSY.get_Ts(x), - PSY.get_Tc(x), - PSY.get_T3(x), - PSY.get_T4(x), - PSY.get_T5(x), - PSY.get_valve_position_limits(x)[1], - PSY.get_valve_position_limits(x)[2], -] -get_params_metadata(::PSY.TGTypeI) = [ - ParamsMetadata(:R_tg_TurbineGov, false, false, true, false), - ParamsMetadata(:Ts_TurbineGov, false, false, false, false), - ParamsMetadata(:Tc_TurbineGov, false, false, true, false), - ParamsMetadata(:T3_TurbineGov, false, false, true, false), - ParamsMetadata(:T4_TurbineGov, false, false, true, false), - ParamsMetadata(:T5_TurbineGov, false, false, true, false), - ParamsMetadata(:valve_position_min_TurbineGov, false, false, true, false), - ParamsMetadata(:valve_position_max_TurbineGov, false, false, true, false), -] - =# +get_params(x::PSY.TGTypeI) = ( + R = PSY.get_R(x), + Ts = PSY.get_Ts(x), + Tc = PSY.get_Tc(x), + T3 = PSY.get_T3(x), + T4 = PSY.get_T4(x), + T5 = PSY.get_T5(x), + valve_position_limits = PSY.get_valve_position_limits(x), +) +get_params_metadata(::PSY.TGTypeI) = ( + R = ParamsMetadata(DEVICE_PARAM, false, true), + Ts = ParamsMetadata(DEVICE_PARAM, false, false), + Tc = ParamsMetadata(DEVICE_PARAM, false, true), + T3 = ParamsMetadata(DEVICE_PARAM, false, true), + T4 = ParamsMetadata(DEVICE_PARAM, false, true), + T5 = ParamsMetadata(DEVICE_PARAM, false, true), + valve_position_limits = ( + min = ParamsMetadata(DEVICE_PARAM, false, true), + max = ParamsMetadata(DEVICE_PARAM, false, true), + ), +) get_params(x::PSY.SteamTurbineGov1) = ( R = PSY.get_R(x), T1 = PSY.get_T1(x), From f4f9e73be64809a43c7dc9ed212ba22c24f2e820 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sun, 30 Jun 2024 18:39:46 -0400 Subject: [PATCH 38/76] add gensal gensae --- .../generator_components/init_machine.jl | 111 ++++++++++++------ src/models/device.jl | 50 ++++---- src/models/generator_models/machine_models.jl | 58 +++++---- src/utils/parameters.jl | 59 +++++----- 4 files changed, 151 insertions(+), 127 deletions(-) diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index 540977d71..c37ca6448 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -877,7 +877,7 @@ end function initialize_mach_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicGenerator{PSY.SalientPoleQuadratic, S, A, TG, P}, @@ -899,20 +899,20 @@ function initialize_mach_shaft!( machine = PSY.get_machine(dynamic_device) #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SalientPoleQuadratic) - internal_params = @view device_parameters[local_ix_params] - R, - Td0_p, - Td0_pp, - Tq0_pp, - Xd, - Xq, - Xd_p, - Xd_pp, - Xl, - γ_d1, - γ_q1, - γ_d2 = internal_params + params = @view(p[:params][:Machine]) + R = params[:R] + # Td0_p = params[:Td0_p] + # Td0_pp = params[:Td0_pp] + # Tq0_pp = params[:Tq0_pp] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] + Xq_pp = Xd_pp ## Initialization ## @@ -938,7 +938,7 @@ function initialize_mach_shaft!( Se0 * eq_p0 + (Xd - Xd_p) * (I_d0 + γ_d2 * (eq_p0 - ψ_kd0 - (Xd_p - Xl) * I_d0)) - function f!(out, x) + function f!(out, x, params) δ = x[1] τm = x[2] Vf = x[3] @@ -947,6 +947,20 @@ function initialize_mach_shaft!( ψq_pp = x[6] Xad_Ifd_aux = x[7] + R = params[:R] + Td0_p = params[:Td0_p] + Td0_pp = params[:Td0_pp] + Tq0_pp = params[:Tq0_pp] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] + Xq_pp = Xd_pp + V_d, V_q = ri_dq(δ) * [V_R; V_I] #Additional Fluxes ψd_pp = γ_d1 * eq_p + γ_q1 * ψ_kd @@ -970,13 +984,19 @@ function initialize_mach_shaft!( out[7] = Xad_Ifd_aux - Xad_Ifd end x0 = [δ0, τm0, Vf0, eq_p0, ψ_kd0, ψq_pp0, Xad_Ifd0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages inner_vars[VR_gen_var] = V_R inner_vars[VI_gen_var] = V_I @@ -1004,7 +1024,7 @@ end function initialize_mach_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicGenerator{PSY.SalientPoleExponential, S, A, TG, P}, @@ -1026,20 +1046,16 @@ function initialize_mach_shaft!( machine = PSY.get_machine(dynamic_device) #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SalientPoleExponential) - internal_params = @view device_parameters[local_ix_params] - R, - Td0_p, - Td0_pp, - Tq0_pp, - Xd, - Xq, - Xd_p, - Xd_pp, - Xl, - γ_d1, - γ_q1, - γ_d2 = internal_params + params = @view(p[:params][:Machine]) + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] Xq_pp = Xd_pp γ_qd = (Xq - Xl) / (Xd - Xl) @@ -1077,7 +1093,7 @@ function initialize_mach_shaft!( Se0 * ψd_pp0 + (Xd - Xd_p) * (I_d0 + γ_d2 * (eq_p0 - ψ_kd0 - (Xd_p - Xl) * I_d0)) - function f!(out, x) + function f!(out, x, params) δ = x[1] τm = x[2] Vf = x[3] @@ -1086,6 +1102,19 @@ function initialize_mach_shaft!( ψq_pp = x[6] Xad_Ifd_aux = x[7] + R = params[:R] + Td0_p = params[:Td0_p] + Td0_pp = params[:Td0_pp] + Tq0_pp = params[:Tq0_pp] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] + V_d, V_q = ri_dq(δ) * [V_R; V_I] #Additional Fluxes ψd_pp = γ_d1 * eq_p + γ_q1 * ψ_kd @@ -1109,13 +1138,19 @@ function initialize_mach_shaft!( out[7] = Xad_Ifd_aux - Xad_Ifd end x0 = [δ0, τm0, Vf0, eq_p0, ψ_kd0, ψq_pp0, Xad_Ifd0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages inner_vars[VR_gen_var] = V_R inner_vars[VI_gen_var] = V_I diff --git a/src/models/device.jl b/src/models/device.jl index 7428cdc4f..b2e17dad5 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -437,7 +437,7 @@ end function _update_inner_vars!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ @@ -463,20 +463,15 @@ function _update_inner_vars!( V_tI = inner_vars[VI_gen_var] #Get parameters - machine_ix_params = get_local_parameter_ix(dynamic_device, typeof(machine)) - machine_params = @view device_parameters[machine_ix_params] - R, - Td0_p, - Td0_pp, - Tq0_pp, - Xd, - Xq, - Xd_p, - Xd_pp, - Xl, - γ_d1, - γ_q1, - γ_d2 = machine_params + params = p[:params][:Machine] + R = params[:R] + Xd = params[:Xd] + Xd_p = params[:Xd_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] #RI to dq transformation V_d, V_q = ri_dq(δ) * [V_tR; V_tI] @@ -498,7 +493,7 @@ end function _update_inner_vars!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ @@ -524,20 +519,15 @@ function _update_inner_vars!( V_tI = inner_vars[VI_gen_var] #Get parameters - machine_ix_params = get_local_parameter_ix(dynamic_device, typeof(machine)) - machine_params = @view device_parameters[machine_ix_params] - R, - Td0_p, - Td0_pp, - Tq0_pp, - Xd, - Xq, - Xd_p, - Xd_pp, - Xl, - γ_d1, - γ_q1, - γ_d2 = machine_params + params = p[:params][:Machine] + R = params[:R] + Xd = params[:Xd] + Xd_p = params[:Xd_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] Xq_pp = Xd_pp #RI to dq transformation diff --git a/src/models/generator_models/machine_models.jl b/src/models/generator_models/machine_models.jl index da3405ca9..15dcb8c03 100644 --- a/src/models/generator_models/machine_models.jl +++ b/src/models/generator_models/machine_models.jl @@ -661,7 +661,7 @@ end function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -694,20 +694,19 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #E_fd: Field voltage #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SalientPoleQuadratic) - internal_params = @view device_parameters[local_ix_params] - R, - Td0_p, - Td0_pp, - Tq0_pp, - Xd, - Xq, - Xd_p, - Xd_pp, - Xl, - γ_d1, - γ_q1, - γ_d2 = internal_params + params = p[:params][:Machine] + R = params[:R] + Td0_p = params[:Td0_p] + Td0_pp = params[:Td0_pp] + Tq0_pp = params[:Tq0_pp] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] Xq_pp = Xd_pp basepower = PSY.get_base_power(dynamic_device) @@ -747,7 +746,7 @@ end function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -780,20 +779,19 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #E_fd: Field voltage #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SalientPoleExponential) - internal_params = @view device_parameters[local_ix_params] - R, - Td0_p, - Td0_pp, - Tq0_pp, - Xd, - Xq, - Xd_p, - Xd_pp, - Xl, - γ_d1, - γ_q1, - γ_d2 = internal_params + params = p[:params][:Machine] + R = params[:R] + Td0_p = params[:Td0_p] + Td0_pp = params[:Td0_pp] + Tq0_pp = params[:Tq0_pp] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xd_pp = params[:Xd_pp] + Xl = params[:Xl] + γ_d1 = params[:γ_d1] + γ_q1 = params[:γ_q1] + γ_d2 = params[:γ_d2] Xq_pp = Xd_pp γ_qd = (Xq - Xl) / (Xd - Xl) basepower = PSY.get_base_power(dynamic_device) diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index 6df5f08ad..30aa0787b 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -582,38 +582,39 @@ get_params_metadata( γ_q2 = ParamsMetadata(DEVICE_PARAM, false, true), γ_qd = ParamsMetadata(DEVICE_PARAM, false, true), ) -#= get_params( + +get_params( x::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, -) = [ - PSY.get_R(x), - PSY.get_Td0_p(x), - PSY.get_Td0_pp(x), - PSY.get_Tq0_pp(x), - PSY.get_Xd(x), - PSY.get_Xq(x), - PSY.get_Xd_p(x), - PSY.get_Xd_pp(x), - PSY.get_Xl(x), - PSY.get_γ_d1(x), - PSY.get_γ_q1(x), - PSY.get_γ_d2(x), -] +) = ( + R = PSY.get_R(x), + Td0_p = PSY.get_Td0_p(x), + Td0_pp = PSY.get_Td0_pp(x), + Tq0_pp = PSY.get_Tq0_pp(x), + Xd = PSY.get_Xd(x), + Xq = PSY.get_Xq(x), + Xd_p = PSY.get_Xd_p(x), + Xd_pp = PSY.get_Xd_pp(x), + Xl = PSY.get_Xl(x), + γ_d1 = PSY.get_γ_d1(x), + γ_q1 = PSY.get_γ_q1(x), + γ_d2 = PSY.get_γ_d2(x), +) get_params_metadata( ::Union{PSY.SalientPoleMachine, PSY.SalientPoleExponential, PSY.SalientPoleQuadratic}, -) = [ - ParamsMetadata(:R_Machine, false, false, true, false), - ParamsMetadata(:Td0_p_Machine, false, false, true, false), - ParamsMetadata(:Td0_pp_Machine, false, false, true, false), - ParamsMetadata(:Tq0_pp_Machine, false, false, true, false), - ParamsMetadata(:Xd_Machine, false, false, true, false), - ParamsMetadata(:Xq_Machine, false, false, true, false), - ParamsMetadata(:Xd_p_Machine, false, false, true, false), - ParamsMetadata(:Xd_pp_Machine, false, false, true, false), - ParamsMetadata(:Xl_Machine, false, false, true, false), - ParamsMetadata(:γ_d1_Machine, false, false, true, false), - ParamsMetadata(:γ_q1_Machine, false, false, true, false), - ParamsMetadata(:γ_d2_Machine, false, false, true, false), -] =# +) = ( + R = ParamsMetadata(DEVICE_PARAM, false, true), + Td0_p = ParamsMetadata(DEVICE_PARAM, false, true), + Td0_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Tq0_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Xd = ParamsMetadata(DEVICE_PARAM, false, true), + Xq = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_p = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Xl = ParamsMetadata(DEVICE_PARAM, false, true), + γ_d1 = ParamsMetadata(DEVICE_PARAM, false, true), + γ_q1 = ParamsMetadata(DEVICE_PARAM, false, true), + γ_d2 = ParamsMetadata(DEVICE_PARAM, false, true), +) #SHAFTS get_params(x::PSY.SingleMass) = (H = PSY.get_H(x), D = PSY.get_D(x)) From 24ea509c8249c42f193b9c0ea93453b84506e404 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 1 Jul 2024 17:16:18 -0400 Subject: [PATCH 39/76] more models (still debugging tests) --- .../generator_components/init_avr.jl | 68 +-- .../generator_components/init_machine.jl | 35 +- .../generator_components/init_tg.jl | 50 ++- src/initialization/init_device.jl | 62 +-- .../inverter_components/init_converter.jl | 30 +- .../inverter_components/init_filter.jl | 6 +- .../inverter_components/init_inner.jl | 23 +- .../inverter_components/init_outer.jl | 30 +- src/models/device.jl | 68 ++- src/models/generator_models/avr_models.jl | 37 +- src/models/generator_models/machine_models.jl | 22 +- src/models/generator_models/tg_models.jl | 33 +- .../inverter_models/converter_models.jl | 38 +- src/models/inverter_models/filter_models.jl | 6 +- .../inverter_models/inner_control_models.jl | 48 +- .../inverter_models/outer_control_models.jl | 293 +++++------- src/models/load_models.jl | 4 +- src/utils/parameters.jl | 417 +++++++++--------- 18 files changed, 594 insertions(+), 676 deletions(-) diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index a24117dcb..008c19c6b 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -189,7 +189,7 @@ end function initialize_avr!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.ESAC1A, TG, P}}, inner_vars::AbstractVector, @@ -204,42 +204,41 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.ESAC1A) - internal_params = @view device_parameters[local_ix_params] - Tr, - Tb, - Tc, - Ka, - Ta, - Va_min, - Va_max, - Te, - Kf, - Tf, - Kc, - Kd, - Ke, - Vr_min, - Vr_max = internal_params - inv_Tr = Tr < eps() ? 1.0 : 1.0 / Tr + params = p[:params][:AVR] + Tb = params[:Tb] + Tc = params[:Tc] + Ka = params[:Ka] + Kf = params[:Kf] + Tf = params[:Tf] + Kc = params[:Kc] + Kd = params[:Kd] + Ke = params[:Ke] + Vr_min = params[:Vr_lim][:min] + Vr_max = params[:Vr_lim][:max] #Obtain saturation #Se_Vf = saturation_function(Vm) #Solve Ve from rectifier function - function f_Ve!(out, x) + function f_Ve!(out, x, params) V_e0 = x[1] I_N0 = Kc * Xad_Ifd0 / V_e0 out[1] = Vf0 - V_e0 * rectifier_function(I_N0) end x0 = [1.0] - sol = NLsolve.nlsolve(f_Ve!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f_Ve!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u V_e0 = sol_x0[1] I_N0 = Kc * Xad_Ifd0 / V_e0 end @@ -258,13 +257,18 @@ function initialize_avr!( #States of ESAC1A are Vm, Vr1, Vr2, Ve, Vr3 #To solve V_ref, Vr1, Vr2, Ve, Vr3 - function f!(out, x) + function f!(out, x, params) V_ref = x[1] Vr1 = x[2] Vr2 = x[3] Ve = x[4] Vr3 = x[5] - + Ka = params[:Ka] + Kf = params[:Kf] + Tf = params[:Tf] + Kc = params[:Kc] + Kd = params[:Kd] + Ke = params[:Ke] #Compute auxiliary variables I_N = Kc * Xad_Ifd0 / Ve @@ -282,16 +286,22 @@ function initialize_avr!( out[5] = Vf0 - Ve * rectifier_function(I_N) end x0 = [V_ref0, V_r10, V_r20, V_e0, V_r30] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - set_V_ref(dynamic_device, sol_x0[1]) + set_V_ref!(p, sol_x0[1]) #Update AVR states avr_ix = get_local_state_ix(dynamic_device, typeof(avr)) avr_states = @view device_states[avr_ix] diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index c37ca6448..748aec485 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -297,7 +297,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{PSY.MarconatoMachine, S, A, TG, P}}, inner_vars::AbstractVector, @@ -315,9 +315,9 @@ function initialize_mach_shaft!( I = conj(S0 / V) #Machine Data - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.MarconatoMachine) - internal_params = @view device_parameters[local_ix_params] - R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, _, _, _, T_AA, γd, γq = internal_params + params = p[:params][:Machine] + R = params[:R] + Xq = params[:Xq] #States of MarconatoMachine are [1] ψq, [2] ψd, [3] eq_p, [4] ed_p, [5] eq_pp and [6] ed_pp δ0 = angle(V + (R + Xq * 1im) * I) @@ -325,7 +325,7 @@ function initialize_mach_shaft!( τm0 = real(V * conj(I)) @assert isapprox(τm0, P0; atol = STRICT_NLSOLVE_F_TOLERANCE) #To solve: δ, τm, Vf0, eq_p, ed_p - function f!(out, x) + function f!(out, x, params) δ = x[1] τm = x[2] Vf0 = x[3] @@ -336,6 +336,18 @@ function initialize_mach_shaft!( eq_pp = x[8] ed_pp = x[9] + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xq_pp = params[:Xq_pp] + Td0_p = params[:Td0_p] + T_AA = params[:T_AA] + γd = params[:γd] + γq = params[:γq] + V_dq = ri_dq(δ) * [V_R; V_I] i_d = (1.0 / Xd_pp) * (eq_pp - ψd) #15.18 i_q = (1.0 / Xq_pp) * (-ed_pp - ψq) #15.18 @@ -353,13 +365,19 @@ function initialize_mach_shaft!( V_dq0 = ri_dq(δ0) * [V_R; V_I] x0 = [δ0, τm0, 1.0, V_dq0[1], V_dq0[2], V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages inner_vars[VR_gen_var] = V_R inner_vars[VI_gen_var] = V_I @@ -835,7 +853,6 @@ function initialize_mach_shaft!( out[8] = Xad_Ifd_aux - Xad_Ifd end x0 = [δ0, τm0, Vf0, eq_p0, ed_p0, ψ_kd0, ψ_kq0, Xad_Ifd0] - prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) sol = NonlinearSolve.solve( prob, diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index d472fcdb3..df3140b12 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -306,7 +306,7 @@ end function initialize_tg!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.HydroTurbineGov, P}}, inner_vars::AbstractVector, @@ -318,28 +318,28 @@ function initialize_tg!( tg = PSY.get_prime_mover(dynamic_device) #Get Parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.HydroTurbineGov) - internal_params = @view device_parameters[local_ix_params] - R, - r, - Tr, - Tf, - Tg, - VELM, #Gate velocity limits not implemented - G_min, - G_max, - Tw, - At, - D_T, - q_nl = internal_params + params = p[:params][:TurbineGov] + R = params[:R] + r = params[:r] + Tr = params[:Tr] + G_min = params[:gate_position_limits][:min] + G_max = params[:gate_position_limits][:max] + At = params[:At] + q_nl = params[:q_nl] - function f!(out, x) + function f!(out, x, params) P_ref = x[1] x_g1 = x[2] x_g2 = x[3] x_g3 = x[4] x_g4 = x[5] + R = params[:R] + r = params[:r] + Tr = params[:Tr] + At = params[:At] + D_T = params[:D_T] + q_nl = params[:q_nl] c = (1.0 / r) * x_g1 + (1.0 / (r * Tr)) * x_g2 P_in = P_ref - Δω - R * c h = (x_g4 / x_g3)^2 @@ -352,13 +352,17 @@ function initialize_tg!( end P0 = R * (q_nl + τm0 / At) # mechanical power initial guess. It migth be different than electrical output power x0 = [P0, 0, (r * Tr) * P0 / R, P0 / R, P0 / R] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) - @warn( - "Initialization of Turbine Governor $(PSY.get_name(static)) failed" - ) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) + @warn("Initialization of Turbine Governor $(PSY.get_name(static)) failed") else - sol_x0 = sol.zero + sol_x0 = sol.u #Error if x_g3 is outside PI limits if sol_x0[4] > G_max || sol_x0[4] < G_min error( @@ -367,7 +371,7 @@ function initialize_tg!( end #Update Control Refs PSY.set_P_ref!(tg, sol_x0[1]) - set_P_ref(dynamic_device, sol_x0[1]) + set_P_ref!(p, sol_x0[1]) #Update states tg_ix = get_local_state_ix(dynamic_device, typeof(tg)) tg_states = @view device_states[tg_ix] diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index 9d81e8024..9b6795af8 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -207,27 +207,21 @@ function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.SingleCageInductionMachine}, device::PSY.StaticInjection, ::AbstractVector, - device_parameters::AbstractVector, + p::AbstractVector, device_states::AbstractVector, ) Sbase = get_system_base_power(dynamic_wrapper) # Get parameters dynamic_device = get_device(dynamic_wrapper) - R_s, - R_r, - X_ls, - X_lr, - X_m, - H, - A, - B, - base_power, - C, - τ_m0, - B_sh, - X_ad, - X_aq = device_parameters + params = p[:params] + R_s = params[:R_s] + X_ls = params[:X_ls] + X_lr = params[:X_lr] + base_power = params[:base_power] + τ_m0 = params[:τ_ref] + X_ad = params[:X_ad] + X_aq = params[:X_aq] #PowerFlow Data if isa(device, PSY.StandardLoad) @@ -265,8 +259,7 @@ function initialize_dynamic_device!( τ_m00 = P0 / ωr0 x0 = [i_qs0, i_ds0, B_sh0, ψ_qs0, ψ_ds0, ψ_qr0, ψ_dr0, ωr0, τ_m00] - # - function f!(out, x) + function f!(out, x, params) i_qs = x[1] i_ds = x[2] B_sh = x[3] @@ -276,6 +269,17 @@ function initialize_dynamic_device!( ψ_dr = x[7] ωr = x[8] τ_m0 = x[9] + + R_s = params[:R_s] + R_r = params[:R_r] + X_ls = params[:X_ls] + X_lr = params[:X_lr] + A = params[:A] + B = params[:B] + C = params[:C] + X_ad = params[:X_ad] + X_aq = params[:X_aq] + ψ_mq = ψ_qs - i_qs * X_ls ψ_md = ψ_ds - i_ds * X_ls out[1] = -I_R + i_ds - V_I * B_sh # network interface @@ -288,24 +292,28 @@ function initialize_dynamic_device!( out[8] = (1.0 - ωr) * ψ_qr + R_r / X_lr * (ψ_md - ψ_dr) # dψ_dr/dt = 0 out[9] = ψ_ds * i_qs - ψ_qs * i_ds - τ_m0 * (A * ωr^2 + B * ωr + C) # dωr/dt = 0 end - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) - @warn( - "Initialization in Ind. Motor $(PSY.get_name(device)) failed" - ) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) + @warn("Initialization in Ind. Motor $(PSY.get_name(device)) failed") else - sol_x0 = sol.zero + sol_x0 = sol.u device_states[1] = sol_x0[4] # ψ_qs device_states[2] = sol_x0[5] # ψ_ds device_states[3] = sol_x0[6] # ψ_qr device_states[4] = sol_x0[7] # ψ_dr device_states[5] = sol_x0[8] # ωr # update τ_ref and B_sh - device_parameters[12] = sol_x0[3] # B_sh + params[:B_shunt] = sol_x0[3] # B_sh PSY.set_B_shunt!(dynamic_device, sol_x0[3]) # B_sh - device_parameters[11] = sol_x0[9] # τ_m0 - PSY.set_τ_ref!(dynamic_device, sol_x0[9]) # τ_m0 - set_P_ref(dynamic_wrapper, sol_x0[9]) # τ_m0 + params[:τ_ref] = sol_x0[9] # τ_ref + PSY.set_τ_ref!(dynamic_device, sol_x0[9]) # τ_ref + set_P_ref!(p, sol_x0[9]) # τ_m0 end return end diff --git a/src/initialization/inverter_components/init_converter.jl b/src/initialization/inverter_components/init_converter.jl index 5f264ee0f..a56f28262 100644 --- a/src/initialization/inverter_components/init_converter.jl +++ b/src/initialization/inverter_components/init_converter.jl @@ -17,7 +17,7 @@ function initialize_converter!( function initialize_converter!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{PSY.RenewableEnergyConverterTypeA, O, IC, DC, P, F, L}, @@ -46,30 +46,10 @@ function initialize_converter!( Iq = Ip_external * sin(-θ) + Iq_external * cos(-θ) #Get Converter parameters - converter = PSY.get_converter(dynamic_device) - local_ix_params = - get_local_parameter_ix(dynamic_device, PSY.RenewableEnergyConverterTypeA) - internal_params = @view device_parameters[local_ix_params] - T_g, - Rrpwr, - Brkpt, - Zerox, - Lvpl1, - Vo_lim, - Lv_pnt0, - Lv_pnt1, - Io_lim, - T_fltr, - K_hv, - Iqr_min, - Iqr_max, - Accel, - Q_ref, - R_source, - X_source = internal_params - - # Lv_pnt0 is unused in the initialization - _, Lv_pnt1 = PSY.get_Lv_pnts(converter) + params = p[:params][:Converter] + Vo_lim = params[:Vo_lim] + Lv_pnt1 = params[:Lv_pnts][:max] + Io_lim = params[:Io_lim] if (Iq < Io_lim) || (V_t > Vo_lim) || (V_t < Lv_pnt1) @error( diff --git a/src/initialization/inverter_components/init_filter.jl b/src/initialization/inverter_components/init_filter.jl index bb23df773..0976ca5eb 100644 --- a/src/initialization/inverter_components/init_filter.jl +++ b/src/initialization/inverter_components/init_filter.jl @@ -141,9 +141,9 @@ function initialize_filter!( params = p[:params][:Filter] rf = params[:rf] lf = params[:lf] - converter = PSY.get_converter(dynamic_device) - R_source = PSY.get_R_source(converter) - X_source = PSY.get_X_source(converter) + + R_source = p[:params][:Converter][:R_source] + X_source = p[:params][:Converter][:X_source] #Update terminal voltages inner_vars[Vr_inv_var] = V_R diff --git a/src/initialization/inverter_components/init_inner.jl b/src/initialization/inverter_components/init_inner.jl index 463c02de2..756dde4b8 100644 --- a/src/initialization/inverter_components/init_inner.jl +++ b/src/initialization/inverter_components/init_inner.jl @@ -240,7 +240,7 @@ end function initialize_inner!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, PSY.RECurrentControlB, DC, P, F, L}, @@ -266,21 +266,10 @@ function initialize_inner!( inner_control = PSY.get_inner_control(dynamic_device) Q_Flag = PSY.get_Q_Flag(inner_control) PQ_Flag = PSY.get_PQ_Flag(inner_control) - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.RECurrentControlB) - internal_params = @view device_parameters[local_ix_params] - Vdip_min, - Vdip_max, - T_rv, - dbd1, - dbd2, - K_qv, - I_ql1, - I_qh1, - V_ref0, - K_vp, - K_vi, - T_iq, - I_max = internal_params + params = p[:params][:InnerControl] + V_ref0 = params[:V_ref0] + K_vi = params[:K_vi] + Ip_min, Ip_max, Iq_min, Iq_max = current_limit_logic(inner_control, Val(PQ_Flag), V_t, Ip_oc, Iq_cmd) @@ -315,7 +304,7 @@ function initialize_inner!( # Based on PSS/E manual, if user does not provide V_ref0, then # V_ref0 is considered to be the output voltage of the PF solution if V_ref0 == 0.0 - internal_params[9] = V_t + params[:V_ref0] = V_t end return end diff --git a/src/initialization/inverter_components/init_outer.jl b/src/initialization/inverter_components/init_outer.jl index 1c5d47011..c38e9fab5 100644 --- a/src/initialization/inverter_components/init_outer.jl +++ b/src/initialization/inverter_components/init_outer.jl @@ -136,7 +136,7 @@ end function initialize_outer!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -280,7 +280,7 @@ end function initialize_outer!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -324,7 +324,7 @@ function initialize_outer!( ## Set references Vm = V_t PSY.set_Q_ref!(PSY.get_converter(dynamic_device), q_elec_out) - set_Q_ref(dynamic_device, q_elec_out) + set_Q_ref!(p, q_elec_out) PSY.set_Q_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), q_elec_out, @@ -333,15 +333,15 @@ function initialize_outer!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - set_P_ref(dynamic_device, p_elec_out) + set_P_ref!(p, p_elec_out) PSY.set_V_ref!( PSY.get_reactive_power_control(PSY.get_outer_control(dynamic_device)), Vm, ) - set_V_ref(dynamic_device, Vm) + set_V_ref!(p, Vm) #Get Outer Controller parameters - q_ref = get_Q_ref(dynamic_device) + q_ref = p[:refs][:Q_ref] outer_control = PSY.get_outer_control(dynamic_device) active_power_control = PSY.get_active_power_control(outer_control) reactive_power_control = PSY.get_reactive_power_control(outer_control) @@ -363,15 +363,15 @@ function initialize_outer!( ) internal_states = @view device_states[local_ix] - #Get parameters - K_ig = device_parameters[:OuterControl][:ActivePowerControl][:K_ig] - T_p = device_parameters[:OuterControl][:ActivePowerControl][:T_p] - K_i = device_parameters[:OuterControl][:ReactivePowerControl][:K_i] - R_c = device_parameters[:OuterControl][:ReactivePowerControl][:R_c] - X_c = device_parameters[:OuterControl][:ReactivePowerControl][:X_c] - K_c = device_parameters[:OuterControl][:ReactivePowerControl][:K_c] - T_p = device_parameters[:OuterControl][:ReactivePowerControl][:T_p] - K_qi = device_parameters[:OuterControl][:ReactivePowerControl][:K_qi] + #Get parameters OuterControl + K_ig = p[:params][:OuterControl][:ActivePowerControl][:K_ig] + T_p = p[:params][:OuterControl][:ActivePowerControl][:T_p] + K_i = p[:params][:OuterControl][:ReactivePowerControl][:K_i] + R_c = p[:params][:OuterControl][:ReactivePowerControl][:R_c] + X_c = p[:params][:OuterControl][:ReactivePowerControl][:X_c] + K_c = p[:params][:OuterControl][:ReactivePowerControl][:K_c] + T_p = p[:params][:OuterControl][:ReactivePowerControl][:T_p] + K_qi = p[:params][:OuterControl][:ReactivePowerControl][:K_qi] if Freq_Flag == 1 #Update States diff --git a/src/models/device.jl b/src/models/device.jl index b2e17dad5..e7feabf29 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -570,7 +570,7 @@ end function _update_inner_vars!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ @@ -598,33 +598,23 @@ function _update_inner_vars!( #Get Converter parameters converter = PSY.get_converter(dynamic_device) - converter_ix_params = get_local_parameter_ix(dynamic_device, typeof(converter)) - converter_params = @view device_parameters[converter_ix_params] - T_g, - Rrpwr, - Brkpt, - Zerox, - Lvpl1, - Vo_lim, - Lv_pnt0, - Lv_pnt1, - Io_lim, - T_fltr, - K_hv, - Iqr_min, - Iqr_max, - Accel, - Q_ref, - R_source, - X_source = converter_params + params = p[:params][:Converter] + Brkpt = params[:Brkpt] + Zerox = params[:Zerox] + Lvpl1 = params[:Lvpl1] + Vo_lim = params[:Vo_lim] + Lv_pnt0 = params[:Lv_pnts][:min] + Lv_pnt1 = params[:Lv_pnts][:max] + K_hv = params[:K_hv] + R_source = params[:R_source] + X_source = params[:X_source] + Lvpl_sw = PSY.get_Lvpl_sw(converter) Z_source_sq = R_source^2 + X_source^2 #Obtain filter parameters - filt = PSY.get_filter(dynamic_device) - filter_ix_params = get_local_parameter_ix(dynamic_device, typeof(filt)) - filter_params = @view device_parameters[filter_ix_params] - rf, lf = filter_params + rf = p[:params][:Filter][:rf] + lf = p[:params][:Filter][:lf] #Define internal states for Converter converter_ix = get_local_state_ix(dynamic_device, PSY.RenewableEnergyConverterTypeA) @@ -775,7 +765,7 @@ Oleg Wasynczuk and Scott Sudhoff for the equations function device!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -804,20 +794,20 @@ function device!( ωr = device_states[5] #Get parameters - R_s, - R_r, - X_ls, - X_lr, - X_m, - H, - A, - B, - base_power, - C, - τ_m0, - B_sh, - X_ad, - X_aq = device_parameters + params = p[:params] + R_s = params[:R_s] + R_r = params[:R_r] + X_ls = params[:X_ls] + X_lr = params[:X_lr] + H = params[:H] + A = params[:A] + B = params[:B] + base_power = params[:base_power] + C = params[:C] + τ_m0 = params[:τ_ref] + B_sh = params[:B_shunt] + X_ad = params[:X_ad] + X_aq = params[:X_aq] # voltages in QD v_qs = voltage_i diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index d41722ce9..a364cfb58 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -238,7 +238,7 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.ESAC1A, TG, P}}, h, @@ -246,7 +246,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V_ref = get_V_ref(dynamic_device) + V_ref = p[:refs][:V_ref] #Obtain avr avr = PSY.get_avr(dynamic_device) @@ -268,23 +268,22 @@ function mdl_avr_ode!( Xad_Ifd = inner_vars[Xad_Ifd_var] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.ESAC1A) - internal_params = @view device_parameters[local_ix_params] - Tr, - Tb, - Tc, - Ka, - Ta, - Va_min, - Va_max, - Te, - Kf, - Tf, - Kc, - Kd, - Ke, - Vr_min, - Vr_max = internal_params + params = p[:params][:AVR] + Tr = params[:Tr] + Tb = params[:Tb] + Tc = params[:Tc] + Ka = params[:Ka] + Ta = params[:Ta] + Va_min = params[:Va_lim][:min] + Va_max = params[:Va_lim][:max] + Te = params[:Te] + Kf = params[:Kf] + Tf = params[:Tf] + Kc = params[:Kc] + Kd = params[:Kd] + Ke = params[:Ke] + Vr_min = params[:Vr_lim][:min] + Vr_max = params[:Vr_lim][:max] inv_Tr = Tr < eps() ? 1.0 : 1.0 / Tr #Obtain saturation Se = saturation_function(avr, Ve) diff --git a/src/models/generator_models/machine_models.jl b/src/models/generator_models/machine_models.jl index 15dcb8c03..99f64a743 100644 --- a/src/models/generator_models/machine_models.jl +++ b/src/models/generator_models/machine_models.jl @@ -230,7 +230,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -264,10 +264,22 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.MarconatoMachine) - internal_params = @view device_parameters[local_ix_params] - R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, T_AA, γd, γq = - internal_params + params = p[:params][:Machine] + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xq_pp = params[:Xq_pp] + Td0_p = params[:Td0_p] + Tq0_p = params[:Tq0_p] + Td0_pp = params[:Td0_pp] + Tq0_pp = params[:Tq0_pp] + T_AA = params[:T_AA] + γd = params[:γd] + γq = params[:γq] + basepower = PSY.get_base_power(dynamic_device) #RI to dq transformation diff --git a/src/models/generator_models/tg_models.jl b/src/models/generator_models/tg_models.jl index d818cd94d..e01c0eb22 100644 --- a/src/models/generator_models/tg_models.jl +++ b/src/models/generator_models/tg_models.jl @@ -270,7 +270,7 @@ end function mdl_tg_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, PSY.HydroTurbineGov, P}}, @@ -279,8 +279,8 @@ function mdl_tg_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, A <: PSY.AVR, P <: PSY.PSS} #Obtain references - P_ref = get_P_ref(device) - ω_ref = get_ω_ref(device) + P_ref = p[:refs][:P_ref] + ω_ref = p[:refs][:ω_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(device, PSY.HydroTurbineGov) @@ -298,20 +298,19 @@ function mdl_tg_ode!( Δω = ω - ω_ref #Get Parameters - local_ix_params = get_local_parameter_ix(device, PSY.HydroTurbineGov) - internal_params = @view device_parameters[local_ix_params] - R, - r, - Tr, - Tf, - Tg, - VELM, - G_min, - G_max, - Tw, - At, - D_T, - q_nl = internal_params + params = p[:params][:TurbineGov] + R = params[:R] + r = params[:r] + Tr = params[:Tr] + Tf = params[:Tf] + Tg = params[:Tg] + VELM = params[:VELM] + G_min = params[:gate_position_limits][:min] + G_max = params[:gate_position_limits][:max] + Tw = params[:Tw] + At = params[:At] + D_T = params[:D_T] + q_nl = params[:q_nl] #Compute block derivatives c, dxg2_dt = pi_block_nonwindup(x_g1, x_g2, 1.0 / r, 1.0 / (r * Tr), G_min, G_max) diff --git a/src/models/inverter_models/converter_models.jl b/src/models/inverter_models/converter_models.jl index f4d4ea5df..c04f5ad8b 100644 --- a/src/models/inverter_models/converter_models.jl +++ b/src/models/inverter_models/converter_models.jl @@ -43,7 +43,7 @@ end function mdl_converter_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{ @@ -74,26 +74,22 @@ function mdl_converter_ode!( Iq_cmd = inner_vars[Iq_ic_var] #Get Converter parameters - local_ix_params = - get_local_parameter_ix(dynamic_device, PSY.RenewableEnergyConverterTypeA) - internal_params = @view device_parameters[local_ix_params] - T_g, - Rrpwr, - Brkpt, - Zerox, - Lvpl1, - Vo_lim, - Lv_pnt0, - Lv_pnt1, - Io_lim, - T_fltr, - K_hv, - Iqr_min, - Iqr_max, - Accel, - Q_ref, - R_source, - X_source = internal_params + params = p[:params][:Converter] + T_g = params[:T_g] + Rrpwr = params[:Rrpwr] + Brkpt = params[:Brkpt] + Zerox = params[:Zerox] + Lvpl1 = params[:Lvpl1] + Vo_lim = params[:Vo_lim] + Lv_pnt0 = params[:Lv_pnts][:min] + Lv_pnt1 = params[:Lv_pnts][:max] + T_fltr = params[:T_fltr] + K_hv = params[:K_hv] + Iqr_min = params[:Iqr_lims][:min] + Iqr_max = params[:Iqr_lims][:max] + Q_ref = params[:Q_ref] + R_source = params[:R_source] + X_source = params[:X_source] converter = PSY.get_converter(dynamic_device) Lvpl_sw = PSY.get_Lvpl_sw(converter) diff --git a/src/models/inverter_models/filter_models.jl b/src/models/inverter_models/filter_models.jl index acb5b796f..ddacb7453 100644 --- a/src/models/inverter_models/filter_models.jl +++ b/src/models/inverter_models/filter_models.jl @@ -119,7 +119,7 @@ end function mdl_filter_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -141,8 +141,8 @@ function mdl_filter_ode!( ratio_power = basepower / sys_Sbase #Obtain parameters - rf = device_parameters[:Filter][:rf] - lf = device_parameters[:Filter][:lf] + rf = p[:params][:Filter][:rf] + lf = p[:params][:Filter][:lf] Vr_cnv = inner_vars[Vr_cnv_var] Vi_cnv = inner_vars[Vi_cnv_var] diff --git a/src/models/inverter_models/inner_control_models.jl b/src/models/inverter_models/inner_control_models.jl index fbba6a728..3e4641098 100644 --- a/src/models/inverter_models/inner_control_models.jl +++ b/src/models/inverter_models/inner_control_models.jl @@ -55,19 +55,14 @@ function _mdl_ode_RE_inner_controller_B!( #Get Current Controller parameters PQ_Flag = PSY.get_PQ_Flag(inner_control) - Vdip_min, - Vdip_max, - T_rv, - dbd1, - dbd2, - K_qv, - I_ql1, - I_qh1, - V_ref0, - K_vp, - K_vi, - T_iq, - I_max = inner_controller_parameters + T_rv = inner_controller_parameters[:T_rv] + dbd1 = inner_controller_parameters[:dbd_pnts1] + dbd2 = inner_controller_parameters[:dbd_pnts2] + K_qv = inner_controller_parameters[:K_qv] + I_ql1 = inner_controller_parameters[:Iqinj_lim][:min] + I_qh1 = inner_controller_parameters[:Iqinj_lim][:max] + V_ref0 = inner_controller_parameters[:V_ref0] + T_iq = inner_controller_parameters[:T_iq] #Read local states Vt_filt = inner_controller_states[1] @@ -120,19 +115,15 @@ function _mdl_ode_RE_inner_controller_B!( #Get Current Controller parameters PQ_Flag = PSY.get_PQ_Flag(inner_control) - Vdip_min, - Vdip_max, - T_rv, - dbd1, - dbd2, - K_qv, - I_ql1, - I_qh1, - V_ref0, - K_vp, - K_vi, - T_iq, - I_max = inner_controller_parameters + T_rv = inner_controller_parameters[:T_rv] + dbd1 = inner_controller_parameters[:dbd_pnts1] + dbd2 = inner_controller_parameters[:dbd_pnts2] + K_qv = inner_controller_parameters[:K_qv] + I_ql1 = inner_controller_parameters[:Iqinj_lim][:min] + I_qh1 = inner_controller_parameters[:Iqinj_lim][:max] + K_vp = inner_controller_parameters[:K_vp] + K_vi = inner_controller_parameters[:K_vi] + V_ref0 = inner_controller_parameters[:V_ref0] #Read local states Vt_filt = inner_controller_states[1] @@ -351,7 +342,7 @@ end function mdl_inner_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{ PSY.DynamicInverter{C, O, PSY.RECurrentControlB, DC, P, F, L}, @@ -372,11 +363,10 @@ function mdl_inner_ode!( #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.RECurrentControlB) - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.RECurrentControlB) #Define internal states for Inner Control internal_states = @view device_states[local_ix] internal_ode = @view output_ode[local_ix] - internal_parameters = @view device_parameters[local_ix_params] + internal_parameters = @view p[:params][:InnerControl] # TODO: Voltage Dip Freeze logic #Dispatch inner controller ODE calculation diff --git a/src/models/inverter_models/outer_control_models.jl b/src/models/inverter_models/outer_control_models.jl index 78e6c58d0..1d3e2bd0b 100644 --- a/src/models/inverter_models/outer_control_models.jl +++ b/src/models/inverter_models/outer_control_models.jl @@ -16,7 +16,7 @@ end function _mdl_ode_RE_active_controller_AB!( active_controller_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, active_controller_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, p_elec_out::ACCEPTED_REAL_TYPES, ω_sys::ACCEPTED_REAL_TYPES, Vt_filt::ACCEPTED_REAL_TYPES, @@ -47,27 +47,28 @@ function _mdl_ode_RE_active_controller_AB!( } #Obtain external parameters - p_ref = get_P_ref(dynamic_device) - ω_ref = get_ω_ref(dynamic_device) + p_ref = p[:refs][:P_ref] + ω_ref = p[:refs][:ω_ref] # To do: Obtain proper frequency for a plant. For now using the system frequency. ω_plant = ω_sys - #Obtain additional Active Power Controller parameters - K_pg = device_parameters[:OuterControl][:ActivePowerControl][:K_pg] - K_ig = device_parameters[:OuterControl][:ActivePowerControl][:K_ig] - T_p = device_parameters[:OuterControl][:ActivePowerControl][:T_p] - fe_min = device_parameters[:OuterControl][:ActivePowerControl][:fe_lim][:min] - fe_max = device_parameters[:OuterControl][:ActivePowerControl][:fe_lim][:max] - P_min = device_parameters[:OuterControl][:ActivePowerControl][:P_lim][:min] - P_max = device_parameters[:OuterControl][:ActivePowerControl][:P_lim][:max] - T_g = device_parameters[:OuterControl][:ActivePowerControl][:T_g] - D_dn = device_parameters[:OuterControl][:ActivePowerControl][:D_dn] - D_up = device_parameters[:OuterControl][:ActivePowerControl][:D_up] - dP_min = device_parameters[:OuterControl][:ActivePowerControl][:dP_lim][:min] - dP_max = device_parameters[:OuterControl][:ActivePowerControl][:dP_lim][:max] - P_min_inner = device_parameters[:OuterControl][:ActivePowerControl][:P_lim_inner][:min] - P_max_inner = device_parameters[:OuterControl][:ActivePowerControl][:P_lim_inner][:max] - T_pord = device_parameters[:OuterControl][:ActivePowerControl][:T_pord] + #Obtain additional Active Power Controller parameters + params = p[:params][:OuterControl][:ActivePowerControl] + K_pg = params[:K_pg] + K_ig = params[:K_ig] + T_p = params[:T_p] + fe_min = params[:fe_lim][:min] + fe_max = params[:fe_lim][:max] + P_min = params[:P_lim][:min] + P_max = params[:P_lim][:max] + T_g = params[:T_g] + D_dn = params[:D_dn] + D_up = params[:D_up] + dP_min = params[:dP_lim][:min] + dP_max = params[:dP_lim][:max] + P_min_inner = params[:P_lim_inner][:min] + P_max_inner = params[:P_lim_inner][:max] + T_pord = params[:T_pord] # Not considered parameters because not named tuple fdbd1, fdbd2 = PSY.get_fdbd_pnts(active_power_control) @@ -115,7 +116,7 @@ end function _mdl_ode_RE_active_controller_AB!( active_controller_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, active_controller_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, p_elec_out::ACCEPTED_REAL_TYPES, ω_sys::ACCEPTED_REAL_TYPES, Vt_filt::ACCEPTED_REAL_TYPES, @@ -146,9 +147,9 @@ function _mdl_ode_RE_active_controller_AB!( } #Obtain external parameters - p_ref = get_P_ref(dynamic_device) + p_ref = p[:refs][:P_ref] #Obtain additional Active Power Controller parameters - T_pord = device_parameters[:OuterControl][:ActivePowerControl][:T_pord] + T_pord = p[:params][:OuterControl][:ActivePowerControl][:T_pord] #Define internal states for outer control p_ord = active_controller_states[1] @@ -175,7 +176,7 @@ end function _mdl_ode_RE_reactive_controller_AB!( reactive_controller_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, reactive_controller_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, q_elec_out::ACCEPTED_REAL_TYPES, Vt_filt::ACCEPTED_REAL_TYPES, ::Val{0}, @@ -207,45 +208,27 @@ function _mdl_ode_RE_reactive_controller_AB!( } #Obtain external parameters - q_ref = get_Q_ref(dynamic_device) - + q_ref = p[:refs][:Q_ref] + params = p[:params][:OuterControl][:ReactivePowerControl] # Get Reactive Controller parameters - local_ix_params = get_local_parameter_ix( - dynamic_device, - PSY.OuterControl{ - PSY.ActiveRenewableControllerAB, - PSY.ReactiveRenewableControllerAB, - }, - ) - outer_control = PSY.get_outer_control(dynamic_device) - active_power_control = PSY.get_active_power_control(outer_control) - internal_params = @view device_parameters[local_ix_params] - active_n_params = length(get_params(active_power_control)) - reactive_n_params = length(get_params(reactive_power_control)) - reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) - reactive_params = @view internal_params[reactive_ix_range_params] - T_fltr, - K_p, - K_i, - T_ft, - T_fv, - V_frz, # V_frz not implemented yet - R_c, - X_c, - K_c, - e_min, - e_max, - dbd1, - dbd2, - Q_min, - Q_max, - T_p, - Q_min_inner, - Q_max_inner, - V_min, - V_max, - K_qp, - K_qi = reactive_params + T_fltr = params[:T_fltr] + K_p = params[:K_p] + K_i = params[:K_i] + T_ft = params[:T_ft] + T_fv = params[:T_fv] + e_min = params[:e_lim][:min] + e_max = params[:e_lim][:max] + dbd1 = params[:dbd_pnts1] + dbd2 = params[:dbd_pnts2] + Q_min = params[:Q_lim][:min] + Q_max = params[:Q_lim][:max] + # V_frz not implemented yet + Q_min_inner = params[:Q_lim_inner][:min] + Q_max_inner = params[:Q_lim_inner][:max] + V_min = params[:V_lim][:min] + V_max = params[:V_lim][:max] + K_qp = params[:K_qp] + K_qi = params[:K_qi] #Define internal states for Reactive Control q_flt = reactive_controller_states[1] @@ -282,7 +265,7 @@ end function _mdl_ode_RE_reactive_controller_AB!( reactive_controller_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, reactive_controller_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, q_elec_out::ACCEPTED_REAL_TYPES, Vt_filt::ACCEPTED_REAL_TYPES, ::Val{0}, @@ -313,45 +296,21 @@ function _mdl_ode_RE_reactive_controller_AB!( L <: Union{Nothing, PSY.InverterLimiter}, } #Obtain external parameters - q_ref = get_Q_ref(dynamic_device) - outer_control = PSY.get_outer_control(dynamic_device) - active_power_control = PSY.get_active_power_control(outer_control) + q_ref = p[:refs][:Q_ref] # Get Reactive Controller parameters - local_ix_params = get_local_parameter_ix( - dynamic_device, - PSY.OuterControl{ - PSY.ActiveRenewableControllerAB, - PSY.ReactiveRenewableControllerAB, - }, - ) - internal_params = @view device_parameters[local_ix_params] - active_n_params = length(get_params(active_power_control)) - reactive_n_params = length(get_params(reactive_power_control)) - reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) - reactive_params = @view internal_params[reactive_ix_range_params] - T_fltr, - K_p, - K_i, - T_ft, - T_fv, - V_frz, # V_frz not implemented yet - R_c, - X_c, - K_c, - e_min, - e_max, - dbd1, - dbd2, - Q_min, - Q_max, - T_p, - Q_min_inner, - Q_max_inner, - V_min, - V_max, - K_qp, - K_qi = reactive_params - + params = p[:params][:OuterControl][:ReactivePowerControl] + T_fltr = params[:T_fltr] + K_p = params[:K_p] + K_i = params[:K_i] + T_ft = params[:T_ft] + T_fv = params[:T_fv] + e_min = params[:e_lim][:min] + e_max = params[:e_lim][:max] + dbd1 = params[:dbd_pnts1] + dbd2 = params[:dbd_pnts2] + Q_min = params[:Q_lim][:min] + Q_max = params[:Q_lim][:max] + # V_frz not implemented yet #Define internal states for Reactive Control q_flt = reactive_controller_states[1] ξq_oc = reactive_controller_states[2] @@ -385,7 +344,7 @@ end function _mdl_ode_RE_reactive_controller_AB!( reactive_controller_ode, reactive_controller_states, - device_parameters, + p, q_elec_out, Vt_filt, ::Val{1}, @@ -416,7 +375,7 @@ function _mdl_ode_RE_reactive_controller_AB!( L <: Union{Nothing, PSY.InverterLimiter}, } #Obtain external parameters - V_ref = get_V_ref(dynamic_device) + V_ref = p[:refs][:V_ref] #Obtain regulated voltage (assumed to be terminal voltage) V_reg = sqrt(inner_vars[Vr_inv_var]^2 + inner_vars[Vi_inv_var]^2) @@ -426,42 +385,28 @@ function _mdl_ode_RE_reactive_controller_AB!( VC_Flag = PSY.get_VC_Flag(reactive_power_control) # Get Reactive Controller parameters - local_ix_params = get_local_parameter_ix( - dynamic_device, - PSY.OuterControl{ - PSY.ActiveRenewableControllerAB, - PSY.ReactiveRenewableControllerAB, - }, - ) - internal_params = @view device_parameters[local_ix_params] - outer_control = PSY.get_outer_control(dynamic_device) - active_power_control = PSY.get_active_power_control(outer_control) - active_n_params = length(get_params(active_power_control)) - reactive_n_params = length(get_params(reactive_power_control)) - reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) - reactive_params = @view internal_params[reactive_ix_range_params] - T_fltr, - K_p, - K_i, - T_ft, - T_fv, - V_frz, # V_frz not implemented yet - R_c, - X_c, - K_c, - e_min, - e_max, - dbd1, - dbd2, - Q_min, - Q_max, - T_p, - Q_min_inner, - Q_max_inner, - V_min, - V_max, - K_qp, - K_qi = reactive_params + params = p[:params][:OuterControl][:ReactivePowerControl] + T_fltr = params[:T_fltr] + K_p = params[:K_p] + K_i = params[:K_i] + T_ft = params[:T_ft] + T_fv = params[:T_fv] + e_min = params[:e_lim][:min] + e_max = params[:e_lim][:max] + dbd1 = params[:dbd_pnts1] + dbd2 = params[:dbd_pnts2] + Q_min = params[:Q_lim][:min] + Q_max = params[:Q_lim][:max] + # V_frz not implemented yet + R_c = params[:R_c] + X_c = params[:X_c] + K_c = params[:K_c] + Q_min_inner = params[:Q_lim_inner][:min] + Q_max_inner = params[:Q_lim_inner][:max] + V_min = params[:V_lim][:min] + V_max = params[:V_lim][:max] + K_qp = params[:K_qp] + K_qi = params[:K_qi] #Define internal states for Reactive Control V_cflt = reactive_controller_states[1] @@ -514,7 +459,7 @@ end function _mdl_ode_RE_reactive_controller_AB!( reactive_controller_ode, reactive_controller_states, - device_parameters, + p, q_elec_out, Vt_filt, ::Val{1}, @@ -545,7 +490,7 @@ function _mdl_ode_RE_reactive_controller_AB!( L <: Union{Nothing, PSY.InverterLimiter}, } #Obtain external parameters - V_ref = get_V_ref(dynamic_device) + V_ref = p[:refs][:V_ref] #Obtain regulated voltage (assumed to be terminal voltage) V_reg = sqrt(inner_vars[Vr_inv_var]^2 + inner_vars[Vi_inv_var]^2) @@ -554,42 +499,25 @@ function _mdl_ode_RE_reactive_controller_AB!( # Get Reactive Controller parameters VC_Flag = PSY.get_VC_Flag(reactive_power_control) - local_ix_params = get_local_parameter_ix( - dynamic_device, - PSY.OuterControl{ - PSY.ActiveRenewableControllerAB, - PSY.ReactiveRenewableControllerAB, - }, - ) - internal_params = @view device_parameters[local_ix_params] - outer_control = PSY.get_outer_control(dynamic_device) - active_power_control = PSY.get_active_power_control(outer_control) - active_n_params = length(get_params(active_power_control)) - reactive_n_params = length(get_params(reactive_power_control)) - reactive_ix_range_params = (active_n_params + 1):(active_n_params + reactive_n_params) - reactive_params = @view internal_params[reactive_ix_range_params] - T_fltr, - K_p, - K_i, - T_ft, - T_fv, - V_frz, # V_frz not implemented yet - R_c, - X_c, - K_c, - e_min, - e_max, - dbd1, - dbd2, - Q_min, - Q_max, - T_p, - Q_min_inner, - Q_max_inner, - V_min, - V_max, - K_qp, - K_qi = reactive_params + + params = p[:params][:OuterControl][:ReactivePowerControl] + T_fltr = params[:T_fltr] + K_p = params[:K_p] + K_i = params[:K_i] + T_ft = params[:T_ft] + T_fv = params[:T_fv] + e_min = params[:e_lim][:min] + e_max = params[:e_lim][:max] + dbd1 = params[:dbd_pnts1] + dbd2 = params[:dbd_pnts2] + Q_min = params[:Q_lim][:min] + Q_max = params[:Q_lim][:max] + # V_frz not implemented yet + R_c = params[:R_c] + X_c = params[:X_c] + K_c = params[:K_c] + V_min = params[:V_lim][:min] + V_max = params[:V_lim][:max] #Define internal states for Reactive Control V_cflt = reactive_controller_states[1] @@ -1007,7 +935,7 @@ end function mdl_outer_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -1083,13 +1011,6 @@ function mdl_outer_ode!( PSY.ReactiveRenewableControllerAB, }, ) - local_ix_params = get_local_parameter_ix( - dynamic_device, - PSY.OuterControl{ - PSY.ActiveRenewableControllerAB, - PSY.ReactiveRenewableControllerAB, - }, - ) internal_states = @view device_states[local_ix] internal_ode = @view output_ode[local_ix] @@ -1106,7 +1027,7 @@ function mdl_outer_ode!( _mdl_ode_RE_active_controller_AB!( active_ode, active_states, - device_parameters, + p, p_elec_out, ω_sys, Vt_filt, @@ -1120,7 +1041,7 @@ function mdl_outer_ode!( _mdl_ode_RE_reactive_controller_AB!( reactive_ode, reactive_states, - device_parameters, + p, q_elec_out, Vt_filt, Val(Ref_Flag), diff --git a/src/models/load_models.jl b/src/models/load_models.jl index e39b647c9..8465fffa0 100644 --- a/src/models/load_models.jl +++ b/src/models/load_models.jl @@ -44,8 +44,8 @@ function mdl_zip_load!( current_i::AbstractArray{T}, wrapper::StaticLoadWrapper, ) where {T <: ACCEPTED_REAL_TYPES} - V0_mag_inv = 1.0 / p[:refs][:V_ref] - #V0_mag_inv = 1.0 / PSY.get_magnitude(PSY.get_bus(wrapper)) + #V0_mag_inv = 1.0 / p[:refs][:V_ref] + V0_mag_inv = 1.0 / PSY.get_magnitude(PSY.get_bus(wrapper)) V0_mag_sq_inv = V0_mag_inv^2 V_mag = sqrt(voltage_r^2 + voltage_i^2) diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index 30aa0787b..860aeafc9 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -214,6 +214,8 @@ get_params(x::PSY.ReactiveRenewableControllerAB) = ( X_c = PSY.get_X_c(x), K_c = PSY.get_K_c(x), e_lim = (min = PSY.get_e_lim(x)[:min], max = PSY.get_e_lim(x)[:max]), + dbd_pnts1 = PSY.get_dbd_pnts(x)[1], + dbd_pnts2 = PSY.get_dbd_pnts(x)[2], Q_lim = (min = PSY.get_Q_lim(x)[:min], max = PSY.get_Q_lim(x)[:max]), T_p = PSY.get_T_p(x), Q_lim_inner = (min = PSY.get_Q_lim_inner(x)[:min], max = PSY.get_Q_lim_inner(x)[:max]), @@ -235,6 +237,8 @@ get_params_metadata(::PSY.ReactiveRenewableControllerAB) = min = ParamsMetadata(DEVICE_PARAM, false, false), max = ParamsMetadata(DEVICE_PARAM, false, false), ), + dbd_pnts1 = ParamsMetadata(DEVICE_PARAM, false, false), + dbd_pnts2 = ParamsMetadata(DEVICE_PARAM, false, false), Q_lim = ( min = ParamsMetadata(DEVICE_PARAM, false, false), max = ParamsMetadata(DEVICE_PARAM, false, false), @@ -251,14 +255,6 @@ get_params_metadata(::PSY.ReactiveRenewableControllerAB) = K_qp = ParamsMetadata(DEVICE_PARAM, false, false), K_qi = ParamsMetadata(DEVICE_PARAM, false, true), ) -#= -= PSY.get_dbd_pnts(x)[1], -= PSY.get_dbd_pnts(x)[2], - -ParamsMetadata(:dbd_pnts1_ReactivePowerControl, false, false, false, false), -ParamsMetadata(:dbd_pnts2_ReactivePowerControl, false, false, false, false), - =# - #INNER CONTROL get_params(x::PSY.VoltageModeControl) = ( kpv = PSY.get_kpv(x), @@ -294,38 +290,39 @@ get_params_metadata(::PSY.CurrentModeControl) = ( kic = ParamsMetadata(DEVICE_PARAM, false, true), kffv = ParamsMetadata(DEVICE_PARAM, false, true), ) -#= -get_params(x::PSY.RECurrentControlB) = [ - PSY.get_Vdip_lim(x)[1], - PSY.get_Vdip_lim(x)[2], - PSY.get_T_rv(x), - PSY.get_dbd_pnts(x)[1], - PSY.get_dbd_pnts(x)[2], - PSY.get_K_qv(x), - PSY.get_Iqinj_lim(x)[1], - PSY.get_Iqinj_lim(x)[2], - PSY.get_V_ref0(x), - PSY.get_K_vp(x), - PSY.get_K_vi(x), - PSY.get_T_iq(x), - PSY.get_I_max(x), -] -get_params_metadata(::PSY.RECurrentControlB) = [ - ParamsMetadata(:Vdip_min_InnerControl, false, false, false, false), - ParamsMetadata(:Vdip_max_InnerControl, false, false, false, false), - ParamsMetadata(:T_rv_InnerControl, true, false, false, false), - ParamsMetadata(:dbd_pnts_1_InnerControl, false, false, false, false), - ParamsMetadata(:dbd_pnts_2_InnerControl, false, false, false, false), - ParamsMetadata(:K_qv_InnerControl, false, false, false, false), - ParamsMetadata(:Iqinj_min_InnerControl, false, false, false, false), - ParamsMetadata(:Iqinj_max_InnerControl, false, false, false, false), - ParamsMetadata(:V_ref0_InnerControl, false, false, true, false), - ParamsMetadata(:K_vp_InnerControl, false, false, false, false), - ParamsMetadata(:K_vi_InnerControl, false, false, true, false), - ParamsMetadata(:T_iq_InnerControl, true, false, false, false), - ParamsMetadata(:I_max_InnerControl, false, false, false, false), -] - =# +get_params(x::PSY.RECurrentControlB) = ( + Vdip_lim = PSY.get_Vdip_lim(x), + T_rv = PSY.get_T_rv(x), + dbd_pnts1 = PSY.get_dbd_pnts(x)[1], + dbd_pnts2 = PSY.get_dbd_pnts(x)[2], + K_qv = PSY.get_K_qv(x), + Iqinj_lim = PSY.get_Iqinj_lim(x), + V_ref0 = PSY.get_V_ref0(x), + K_vp = PSY.get_K_vp(x), + K_vi = PSY.get_K_vi(x), + T_iq = PSY.get_T_iq(x), + I_max = PSY.get_I_max(x), +) +get_params_metadata(::PSY.RECurrentControlB) = ( + Vdip_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + T_rv = ParamsMetadata(DEVICE_PARAM, true, false), + dbd_pnts1 = ParamsMetadata(DEVICE_PARAM, false, false), + dbd_pnts2 = ParamsMetadata(DEVICE_PARAM, false, false), + K_qv = ParamsMetadata(DEVICE_PARAM, false, false), + Iqinj_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + V_ref0 = ParamsMetadata(DEVICE_PARAM, false, true), + K_vp = ParamsMetadata(DEVICE_PARAM, false, false), + K_vi = ParamsMetadata(DEVICE_PARAM, false, true), + T_iq = ParamsMetadata(DEVICE_PARAM, true, false), + I_max = ParamsMetadata(DEVICE_PARAM, false, false), +) + #DC SOURCE get_params(x::PSY.FixedDCSource) = (voltage = PSY.get_voltage(x),) get_params_metadata(::PSY.FixedDCSource) = @@ -359,46 +356,46 @@ get_params_metadata(::PSY.FixedFrequency) = #CONVERTER get_params(::PSY.AverageConverter) = (;) get_params_metadata(::PSY.AverageConverter) = (;) - -#= get_params(x::PSY.RenewableEnergyConverterTypeA) = [ - PSY.get_T_g(x), - PSY.get_Rrpwr(x), - PSY.get_Brkpt(x), - PSY.get_Zerox(x), - PSY.get_Lvpl1(x), - PSY.get_Vo_lim(x), - PSY.get_Lv_pnts(x)[1], - PSY.get_Lv_pnts(x)[2], - PSY.get_Io_lim(x), - PSY.get_T_fltr(x), - PSY.get_K_hv(x), - PSY.get_Iqr_lims(x)[1], - PSY.get_Iqr_lims(x)[2], - PSY.get_Accel(x), - PSY.get_Q_ref(x), - PSY.get_R_source(x), - PSY.get_X_source(x), -] -get_params_metadata(::PSY.RenewableEnergyConverterTypeA) = [ - ParamsMetadata(:T_g_Converter, false, false, false, false) - ParamsMetadata(:Rrpwr_Converter, false, false, false, false) - ParamsMetadata(:Brkpt_Converter, false, false, false, false) - ParamsMetadata(:Zerox_Converter, false, false, false, false) - ParamsMetadata(:Lvpl1_Converter, false, false, false, false) - ParamsMetadata(:Vo_lim_Converter, false, false, true, false) - ParamsMetadata(:Lv_pnt0_Converter, false, false, false, false) - ParamsMetadata(:Lv_pnt1_Converter, false, false, true, false) - ParamsMetadata(:Io_lim_Converter, false, false, true, false) - ParamsMetadata(:T_fltr_Converter, false, false, false, false) - ParamsMetadata(:K_hv_Converter, false, false, false, false) - ParamsMetadata(:Iqr_min_Converter, false, false, false, false) - ParamsMetadata(:Iqr_max_Converter, false, false, false, false) - ParamsMetadata(:Accel_Converter, false, false, false, false) - ParamsMetadata(:Q_ref_Converter, false, false, false, false) - ParamsMetadata(:R_source_Converter, false, false, false, false) - ParamsMetadata(:X_source_Converter, false, false, false, false) -] - =# +get_params(x::PSY.RenewableEnergyConverterTypeA) = ( + T_g = PSY.get_T_g(x), + Rrpwr = PSY.get_Rrpwr(x), + Brkpt = PSY.get_Brkpt(x), + Zerox = PSY.get_Zerox(x), + Lvpl1 = PSY.get_Lvpl1(x), + Vo_lim = PSY.get_Vo_lim(x), + Lv_pnts = PSY.get_Lv_pnts(x), + Io_lim = PSY.get_Io_lim(x), + T_fltr = PSY.get_T_fltr(x), + K_hv = PSY.get_K_hv(x), + Iqr_lims = PSY.get_Iqr_lims(x), + Accel = PSY.get_Accel(x), + Q_ref = PSY.get_Q_ref(x), + R_source = PSY.get_R_source(x), + X_source = PSY.get_X_source(x), +) +get_params_metadata(::PSY.RenewableEnergyConverterTypeA) = ( + T_g = ParamsMetadata(DEVICE_PARAM, false, false), + Rrpwr = ParamsMetadata(DEVICE_PARAM, false, false), + Brkpt = ParamsMetadata(DEVICE_PARAM, false, false), + Zerox = ParamsMetadata(DEVICE_PARAM, false, false), + Lvpl1 = ParamsMetadata(DEVICE_PARAM, false, false), + Vo_lim = ParamsMetadata(DEVICE_PARAM, false, true), + Lv_pnts = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), #confirm + max = ParamsMetadata(DEVICE_PARAM, false, true), #confirm + ), + Io_lim = ParamsMetadata(DEVICE_PARAM, false, true), + T_fltr = ParamsMetadata(DEVICE_PARAM, false, false), + K_hv = ParamsMetadata(DEVICE_PARAM, false, false), + Iqr_lims = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + Accel = ParamsMetadata(DEVICE_PARAM, false, false), + Q_ref = ParamsMetadata(DEVICE_PARAM, false, false), + R_source = ParamsMetadata(DEVICE_PARAM, false, false), + X_source = ParamsMetadata(DEVICE_PARAM, false, false), +) ########### GENERATORS ############# function get_params(g::PSY.DynamicGenerator) return ( @@ -481,40 +478,40 @@ get_params_metadata(::PSY.SauerPaiMachine) = ( γ_d2 = ParamsMetadata(DEVICE_PARAM, false, true), γ_q2 = ParamsMetadata(DEVICE_PARAM, false, true), ) -#= #TODO - SimpleMarconatoMachine -get_params(x::PSY.MarconatoMachine) = [ - PSY.get_R(x), - PSY.get_Xd(x), - PSY.get_Xq(x), - PSY.get_Xd_p(x), - PSY.get_Xq_p(x), - PSY.get_Xd_pp(x), - PSY.get_Xq_pp(x), - PSY.get_Td0_p(x), - PSY.get_Tq0_p(x), - PSY.get_Td0_pp(x), - PSY.get_Tq0_pp(x), - PSY.get_T_AA(x), - PSY.get_γd(x), - PSY.get_γq(x), -] -get_params_metadata(::PSY.MarconatoMachine) = [ - ParamsMetadata(:R_Machine, false, false, true, false), - ParamsMetadata(:Xd_Machine, false, false, true, false), - ParamsMetadata(:Xq_Machine, false, false, true, false), - ParamsMetadata(:Xd_p_Machine, false, false, true, false), - ParamsMetadata(:Xq_p_Machine, false, false, true, false), - ParamsMetadata(:Xd_pp_Machine, false, false, true, false), - ParamsMetadata(:Xq_pp_Machine, false, false, true, false), - ParamsMetadata(:Td0_p_Machine, false, false, true, false), - ParamsMetadata(:Tq0_p_Machine, false, false, false, false), - ParamsMetadata(:Td0_pp_Machine, false, false, false, false), - ParamsMetadata(:Tq0_pp_Machine, false, false, false, false), - ParamsMetadata(:T_AA_Machine, false, false, true, false), - ParamsMetadata(:γd_Machine, false, false, true, false), - ParamsMetadata(:γq_Machine, false, false, true, false), -] +get_params(x::PSY.MarconatoMachine) = ( + R = PSY.get_R(x), + Xd = PSY.get_Xd(x), + Xq = PSY.get_Xq(x), + Xd_p = PSY.get_Xd_p(x), + Xq_p = PSY.get_Xq_p(x), + Xd_pp = PSY.get_Xd_pp(x), + Xq_pp = PSY.get_Xq_pp(x), + Td0_p = PSY.get_Td0_p(x), + Tq0_p = PSY.get_Tq0_p(x), + Td0_pp = PSY.get_Td0_pp(x), + Tq0_pp = PSY.get_Tq0_pp(x), + T_AA = PSY.get_T_AA(x), + γd = PSY.get_γd(x), + γq = PSY.get_γq(x), +) +get_params_metadata(::PSY.MarconatoMachine) = ( + R = ParamsMetadata(DEVICE_PARAM, false, true), + Xd = ParamsMetadata(DEVICE_PARAM, false, true), + Xq = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_p = ParamsMetadata(DEVICE_PARAM, false, true), + Xq_p = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Xq_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Td0_p = ParamsMetadata(DEVICE_PARAM, false, true), + Tq0_p = ParamsMetadata(DEVICE_PARAM, false, false), + Td0_pp = ParamsMetadata(DEVICE_PARAM, false, false), + Tq0_pp = ParamsMetadata(DEVICE_PARAM, false, false), + γ_d = ParamsMetadata(DEVICE_PARAM, false, true), + γ_q = ParamsMetadata(DEVICE_PARAM, false, true), +) +#= + get_params(x::PSY.AndersonFouadMachine) = [ PSY.get_R(x), PSY.get_Xd(x), @@ -735,41 +732,43 @@ get_params_metadata(::PSY.AVRTypeII) = ( Ae = ParamsMetadata(DEVICE_PARAM, false, true), Be = ParamsMetadata(DEVICE_PARAM, false, true), ) +get_params(x::PSY.ESAC1A) = ( + Tr = PSY.get_Tr(x), + Tb = PSY.get_Tb(x), + Tc = PSY.get_Tc(x), + Ka = PSY.get_Ka(x), + Ta = PSY.get_Ta(x), + Va_lim = PSY.get_Va_lim(x), + Te = PSY.get_Te(x), + Kf = PSY.get_Kf(x), + Tf = PSY.get_Tf(x), + Kc = PSY.get_Kc(x), + Kd = PSY.get_Kd(x), + Ke = PSY.get_Ke(x), + Vr_lim = PSY.get_Vr_lim(x), +) +get_params_metadata(::PSY.ESAC1A) = ( + Tr = ParamsMetadata(DEVICE_PARAM, true, false), + Tb = ParamsMetadata(DEVICE_PARAM, true, false), + Tc = ParamsMetadata(DEVICE_PARAM, true, false), + Ka = ParamsMetadata(DEVICE_PARAM, true, false), + Ta = ParamsMetadata(DEVICE_PARAM, false, false), + Va_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + Te = ParamsMetadata(DEVICE_PARAM, false, false), + Kf = ParamsMetadata(DEVICE_PARAM, true, false), + Tf = ParamsMetadata(DEVICE_PARAM, true, false), + Kc = ParamsMetadata(DEVICE_PARAM, true, false), + Kd = ParamsMetadata(DEVICE_PARAM, true, false), + Ke = ParamsMetadata(DEVICE_PARAM, true, false), + Vr_lim = ( + min = ParamsMetadata(DEVICE_PARAM, true, false), + max = ParamsMetadata(DEVICE_PARAM, true, false), + ), +) #= -get_params(x::PSY.ESAC1A) = [ - PSY.get_Tr(x), - PSY.get_Tb(x), - PSY.get_Tc(x), - PSY.get_Ka(x), - PSY.get_Ta(x), - PSY.get_Va_lim(x)[1], - PSY.get_Va_lim(x)[2], - PSY.get_Te(x), - PSY.get_Kf(x), - PSY.get_Tf(x), - PSY.get_Kc(x), - PSY.get_Kd(x), - PSY.get_Ke(x), - PSY.get_Vr_lim(x)[1], - PSY.get_Vr_lim(x)[2], -] -get_params_metadata(::PSY.ESAC1A) = [ - ParamsMetadata(:Tr, false, false, true, false), - ParamsMetadata(:Tb_AVR, false, false, true, false), - ParamsMetadata(:Tc_AVR, false, false, true, false), - ParamsMetadata(:Ka_AVR, false, false, true, false), - ParamsMetadata(:Ta_AVR, false, false, false, false), - ParamsMetadata(:Va_min_AVR, false, false, false, false), - ParamsMetadata(:Va_max_AVR, false, false, false, false), - ParamsMetadata(:Te_AVR, false, false, false, false), - ParamsMetadata(:Kf_AVR, false, false, true, false), - ParamsMetadata(:Tf_AVR, false, false, true, false), - ParamsMetadata(:Kc_AVR, false, false, true, false), - ParamsMetadata(:Kd_AVR, false, false, true, false), - ParamsMetadata(:Ke_AVR, false, false, true, false), - ParamsMetadata(:Vr_min_AVR, false, false, true, false), - ParamsMetadata(:Vr_max_AVR, false, false, true, false), -] get_params(x::PSY.EXST1) = [ PSY.get_Tr(x), PSY.get_Vi_lim(x)[1], @@ -925,35 +924,35 @@ get_params_metadata(::PSY.SteamTurbineGov1) = ( T3 = ParamsMetadata(DEVICE_PARAM, false, true), D_T = ParamsMetadata(DEVICE_PARAM, false, true), ) -#= get_params(x::PSY.HydroTurbineGov) = [ - PSY.get_R(x), - PSY.get_r(x), - PSY.get_Tr(x), - PSY.get_Tf(x), - PSY.get_Tg(x), - PSY.get_VELM(x), - PSY.get_gate_position_limits(x)[1], - PSY.get_gate_position_limits(x)[2], - PSY.get_Tw(x), - PSY.get_At(x), - PSY.get_D_T(x), - PSY.get_q_nl(x), -] -get_params_metadata(::PSY.HydroTurbineGov) = [ - ParamsMetadata(:R_TurbineGov, false, false, true, false), - ParamsMetadata(:r_TurbineGov, false, false, true, false), - ParamsMetadata(:Tr_TurbineGov, false, false, true, false), - ParamsMetadata(:Tf_TurbineGov, true, false, false, false), - ParamsMetadata(:Tg_TurbineGov, true, false, false, false), - ParamsMetadata(:VELM_TurbineGov, false, false, false, false), - ParamsMetadata(:G_min_TurbineGov, false, false, true, false), - ParamsMetadata(:G_max_TurbineGov, false, false, true, false), - ParamsMetadata(:Tw_TurbineGov, false, false, false, false), - ParamsMetadata(:At_TurbineGov, false, false, true, false), - ParamsMetadata(:D_T_TurbineGov, false, false, true, false), - ParamsMetadata(:q_nl_TurbineGov, false, false, true, false), -] =# - +get_params(x::PSY.HydroTurbineGov) = ( + R = PSY.get_R(x), + r = PSY.get_r(x), + Tr = PSY.get_Tr(x), + Tf = PSY.get_Tf(x), + Tg = PSY.get_Tg(x), + VELM = PSY.get_VELM(x), + gate_position_limits = PSY.get_gate_position_limits(x), + Tw = PSY.get_Tw(x), + At = PSY.get_At(x), + D_T = PSY.get_D_T(x), + q_nl = PSY.get_q_nl(x), +) +get_params_metadata(::PSY.HydroTurbineGov) = ( + R = ParamsMetadata(DEVICE_PARAM, false, true), + r = ParamsMetadata(DEVICE_PARAM, false, true), + Tr = ParamsMetadata(DEVICE_PARAM, false, true), + Tf = ParamsMetadata(DEVICE_PARAM, true, false), + Tg = ParamsMetadata(DEVICE_PARAM, true, false), + VELM = ParamsMetadata(DEVICE_PARAM, false, false), + gate_position_limits = ( + min = ParamsMetadata(DEVICE_PARAM, false, true), + max = ParamsMetadata(DEVICE_PARAM, false, true), + ), + Tw = ParamsMetadata(DEVICE_PARAM, false, false), + At = ParamsMetadata(DEVICE_PARAM, false, true), + D_T = ParamsMetadata(DEVICE_PARAM, false, true), + q_nl = ParamsMetadata(DEVICE_PARAM, false, true), +) #PSS get_params(x::PSY.PSSFixed) = (; V_pss = PSY.get_V_pss(x)) get_params_metadata(::PSY.PSSFixed) = (; V_pss = ParamsMetadata(DEVICE_PARAM, false, false)) @@ -1021,37 +1020,40 @@ get_params_metadata(::PSY.ActiveConstantPowerLoad) = [ ParamsMetadata(:kic, false, false, true, false), ParamsMetadata(:base_power, false, false, true, false), ] -get_params(x::PSY.SingleCageInductionMachine) = [ - PSY.get_R_s(x), - PSY.get_R_r(x), - PSY.get_X_ls(x), - PSY.get_X_lr(x), - PSY.get_X_m(x), - PSY.get_H(x), - PSY.get_A(x), - PSY.get_B(x), - PSY.get_base_power(x), - PSY.get_C(x), - PSY.get_τ_ref(x), - PSY.get_B_shunt(x), - PSY.get_X_ad(x), - PSY.get_X_aq(x)] -get_params_metadata(::PSY.SingleCageInductionMachine) = [ - ParamsMetadata(:R_s, false, false, true, false), - ParamsMetadata(:R_r, false, false, true, false), - ParamsMetadata(:X_ls, false, false, true, false), - ParamsMetadata(:X_lr, false, false, true, false), - ParamsMetadata(:X_m, false, false, false, false), - ParamsMetadata(:H, false, false, false, false), - ParamsMetadata(:A, false, false, true, false), - ParamsMetadata(:B, false, false, true, false), - ParamsMetadata(:base_power, false, false, true, false), - ParamsMetadata(:C, false, false, true, false), - ParamsMetadata(:τ_ref, false, false, true, false), - ParamsMetadata(:B_shunt, false, false, true, false), - ParamsMetadata(:X_ad, false, false, true, false), - ParamsMetadata(:X_aq, false, false, true, false), -] +=# +get_params(x::PSY.SingleCageInductionMachine) = ( + R_s = PSY.get_R_s(x), + R_r = PSY.get_R_r(x), + X_ls = PSY.get_X_ls(x), + X_lr = PSY.get_X_lr(x), + X_m = PSY.get_X_m(x), + H = PSY.get_H(x), + A = PSY.get_A(x), + B = PSY.get_B(x), + base_power = PSY.get_base_power(x), + C = PSY.get_C(x), + τ_ref = PSY.get_τ_ref(x), + B_shunt = PSY.get_B_shunt(x), + X_ad = PSY.get_X_ad(x), + X_aq = PSY.get_X_aq(x), +) +get_params_metadata(::PSY.SingleCageInductionMachine) = ( + R_s = ParamsMetadata(DEVICE_PARAM, false, true), + R_r = ParamsMetadata(DEVICE_PARAM, false, true), + X_ls = ParamsMetadata(DEVICE_PARAM, false, true), + X_lr = ParamsMetadata(DEVICE_PARAM, false, true), + X_m = ParamsMetadata(DEVICE_PARAM, false, false), + H = ParamsMetadata(DEVICE_PARAM, false, false), + A = ParamsMetadata(DEVICE_PARAM, false, true), + B = ParamsMetadata(DEVICE_PARAM, false, true), + base_power = ParamsMetadata(DEVICE_PARAM, false, true), + C = ParamsMetadata(DEVICE_PARAM, false, true), + τ_ref = ParamsMetadata(DEVICE_PARAM, false, true), + B_shunt = ParamsMetadata(DEVICE_PARAM, false, true), + X_ad = ParamsMetadata(DEVICE_PARAM, false, true), + X_aq = ParamsMetadata(DEVICE_PARAM, false, true), +) +#= get_params(x::PSY.SimplifiedSingleCageInductionMachine) = [ PSY.get_R_s(x), PSY.get_R_r(x), @@ -1178,4 +1180,5 @@ get_params_metadata(::PSY.CSVGN1) = [ ParamsMetadata(:R_th, false, false, false, false), ParamsMetadata(:X_th, false, false, false, false), ] + =# From beae601c7ae5135f3cc34c929da2537967700f9c Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 2 Jul 2024 10:19:11 -0400 Subject: [PATCH 40/76] more models; passes through test45 (except gast) --- .../generator_components/init_avr.jl | 74 ++-- .../generator_components/init_pss.jl | 34 +- src/initialization/init_device.jl | 73 ++-- .../inverter_components/init_inner.jl | 2 +- .../inverter_components/init_outer.jl | 6 +- src/models/device.jl | 155 ++++--- src/models/generator_models/avr_models.jl | 64 ++- src/models/generator_models/pss_models.jl | 55 +-- .../inverter_models/converter_models.jl | 1 - .../inverter_models/outer_control_models.jl | 21 +- src/utils/parameters.jl | 401 ++++++++++-------- 11 files changed, 463 insertions(+), 423 deletions(-) diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index 008c19c6b..a04f766f1 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -464,7 +464,7 @@ end function initialize_avr!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.EXST1, TG, P}}, inner_vars::AbstractVector, @@ -478,20 +478,15 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.EXST1) - internal_params = @view device_parameters[local_ix_params] - Tr, - Vi_min, - Vi_max, - Tc, - Tb, - Ka, - Ta, - Vr_min, - Vr_max, - Kc, - Kf, - Tf = internal_params + params = p[:params][:AVR] + Tc = params[:Tc] + Tb = params[:Tb] + Ka = params[:Ka] + Vr_min = params[:Vr_lim][:min] + Vr_max = params[:Vr_lim][:max] + Kc = params[:Kc] + Kf = params[:Kf] + Tf = params[:Tf] # Check limits to field voltage if (Vt * Vr_min - Kc * Ifd > Vf0) || (Vf0 > Vt * Vr_max - Kc * Ifd) @@ -504,7 +499,7 @@ function initialize_avr!( Vref0 = Vt + Vf0 / Ka PSY.set_V_ref!(avr, Vref0) - set_V_ref(dynamic_device, Vref0) + set_V_ref!(p, Vref0) #States of EXST1_PTI are Vm, Vll, Vr, Vfb @@ -520,7 +515,7 @@ end function initialize_avr!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.EXAC1, TG, P}}, inner_vars::AbstractVector, @@ -535,37 +530,40 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.EXAC1) - internal_params = @view device_parameters[local_ix_params] - Tr, - Tb, - Tc, - Ka, - Ta, - Vr_min, - Vr_max, - Te, - Kf, - Tf, - Kc, - Kd, - Ke = internal_params - + params = p[:params][:AVR] + Tb = params[:Tb] + Tc = params[:Tc] + Ka = params[:Ka] + Vr_min = params[:Vr_lim][:min] + Vr_max = params[:Vr_lim][:max] + Kf = params[:Kf] + Tf = params[:Tf] + Kc = params[:Kc] + Kd = params[:Kd] + Ke = params[:Ke] + params_nl = [Ifd0, Kc] #Solve Ve from rectifier function - function f_Ve!(out, x) + function f_Ve!(out, x, params) Ve = x[1] + Ifd0, Kc = params IN = Kc * Ifd0 / Ve out[1] = Vf0 - Ve * rectifier_function(IN) end x0 = [10.0] # initial guess for Ve - sol = NLsolve.nlsolve(f_Ve!, x0) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f_Ve!, x0, params_nl) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u Ve = sol_x0[1] IN = Kc * Ifd0 / Ve end @@ -583,7 +581,7 @@ function initialize_avr!( #Update V_ref PSY.set_V_ref!(avr, Vref0) - set_V_ref(dynamic_device, Vref0) + set_V_ref!(p, Vref0) #States of EXAC1 are Vm, Vr1, Vr2, Ve, Vr3 diff --git a/src/initialization/generator_components/init_pss.jl b/src/initialization/generator_components/init_pss.jl index db5733aab..9617019b5 100644 --- a/src/initialization/generator_components/init_pss.jl +++ b/src/initialization/generator_components/init_pss.jl @@ -1,6 +1,6 @@ function initialize_pss!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSSFixed}}, inner_vars::AbstractVector, @@ -32,20 +32,22 @@ function initialize_pss!( pss_states = @view device_states[pss_ix] # Get Parameters - A1 = PSY.get_A1(pss) - A2 = PSY.get_A2(pss) - A5 = PSY.get_A5(pss) - A6 = PSY.get_A6(pss) - T1 = PSY.get_T1(pss) - T2 = PSY.get_T2(pss) - T3 = PSY.get_T3(pss) - T4 = PSY.get_T4(pss) - T5 = PSY.get_T5(pss) - T6 = PSY.get_T6(pss) - Ks = PSY.get_Ks(pss) - Ls_min, Ls_max = PSY.get_Ls_lim(pss) - V_cu = PSY.get_Vcu(pss) - V_cl = PSY.get_Vcl(pss) + params = p[:params][:PSS] + A1 = params[:A1] + A2 = params[:A2] + A5 = params[:A5] + A6 = params[:A6] + T1 = params[:T1] + T2 = params[:T2] + T3 = params[:T3] + T4 = params[:T4] + T5 = params[:T5] + T6 = params[:T6] + Ks = params[:Ks] + Ls_min = params[:Ls_lim1] + Ls_max = params[:Ls_lim2] + V_cu = params[:V_cu] + V_cl = params[:V_cl] #Error non-valid parameters if A6 > eps() && A2 < eps() @@ -118,7 +120,7 @@ end function initialize_pss!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.STAB1}}, inner_vars::AbstractVector, diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index 9b6795af8..7262d5c19 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -214,7 +214,7 @@ function initialize_dynamic_device!( # Get parameters dynamic_device = get_device(dynamic_wrapper) - params = p[:params] + params = @view(p[:params]) R_s = params[:R_s] X_ls = params[:X_ls] X_lr = params[:X_lr] @@ -322,28 +322,19 @@ function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.SimplifiedSingleCageInductionMachine}, device::PSY.StaticInjection, ::AbstractVector, - device_parameters::AbstractVector, + p::AbstractVector, device_states::AbstractVector, ) Sbase = get_system_base_power(dynamic_wrapper) dynamic_device = get_device(dynamic_wrapper) #Get parameters - R_s, - R_r, - X_ls, - X_lr, - X_m, - H, - A, - B, - base_power, - C, - τ_m0, - B_sh, - X_ss, - X_rr, - X_p = device_parameters + params = @view(p[:params]) + R_s = params[:R_s] + X_m = params[:X_m] + base_power = params[:base_power] + X_rr = params[:X_rr] + X_p = params[:X_p] #PowerFlow Data if isa(device, PSY.StandardLoad) @@ -381,8 +372,7 @@ function initialize_dynamic_device!( τ_m00 = P0 / ωr0 x0 = [i_qs0, i_ds0, i_qr0, i_dr0, B_sh0, ψ_qs0, ψ_ds0, ψ_qr0, ψ_dr0, ωr0, τ_m00] - # - function f!(out, x) + function f!(out, x, params) i_qs = x[1] i_ds = x[2] i_qr = x[3] @@ -395,6 +385,15 @@ function initialize_dynamic_device!( ωr = x[10] τ_m0 = x[11] + R_s = params[:R_s] + R_r = params[:R_r] + X_m = params[:X_m] + A = params[:A] + B = params[:B] + C = params[:C] + X_ss = params[:X_ss] + X_rr = params[:X_rr] + out[1] = -I_R + i_ds - V_I * B_sh # network interface out[2] = -I_I + i_qs + V_R * B_sh # network interface out[3] = v_qs - ψ_ds - R_s * i_qs # dψ_qs/dt = 0 @@ -407,22 +406,26 @@ function initialize_dynamic_device!( out[10] = (1.0 - ωr) * ψ_qr - R_r * i_dr # dψ_dr/dt = 0 out[11] = ψ_qr * i_dr - ψ_dr * i_qr - τ_m0 * (A * ωr^2 + B * ωr + C) # dωr/dt = 0 end - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) - @warn( - "Initialization in Ind. Motor $(PSY.get_name(device)) failed" - ) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) + @warn("Initialization in Ind. Motor $(PSY.get_name(device)) failed") else - sol_x0 = sol.zero + sol_x0 = sol.u device_states[1] = sol_x0[8] # ψ_qr device_states[2] = sol_x0[9] # ψ_dr device_states[3] = sol_x0[10] # ωr # update τ_ref and B_sh PSY.set_B_shunt!(dynamic_device, sol_x0[5]) # B_sh - device_parameters[12] = sol_x0[5] # B_sh + params[:B_shunt] = sol_x0[5] # B_sh PSY.set_τ_ref!(dynamic_device, sol_x0[11]) # τ_m0 - device_parameters[11] = sol_x0[11] # τ_m0 - set_P_ref(dynamic_wrapper, sol_x0[11]) # τ_m0 + params[:τ_ref] = sol_x0[11] # τ_m0 + set_P_ref!(p, sol_x0[11]) # τ_m0 end return device_states end @@ -599,7 +602,7 @@ function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.AggregateDistributedGenerationA}, static::PSY.StaticInjection, ::AbstractVector, - device_parameters::AbstractVector, + p::AbstractVector, device_states::AbstractVector, ) dynamic_device = get_device(dynamic_wrapper) @@ -673,7 +676,7 @@ function initialize_dynamic_device!( #See Note 2 on PSSE Documentation Vref0 = PSY.get_V_ref(dynamic_device) - K_qv = device_parameters[5] + K_qv = p[:params][:K_qv] (dbd1, dbd2) = PSY.get_dbd_pnts(dynamic_device) if Vref0 == 0.0 Vref = Vmeas @@ -683,12 +686,12 @@ function initialize_dynamic_device!( Vref = Vmeas end - set_P_ref(dynamic_wrapper, Pref) + set_P_ref!(p, Pref) PSY.set_P_ref!(dynamic_device, Pref) - set_Q_ref(dynamic_wrapper, Qref) - set_V_ref(dynamic_wrapper, Vref) - set_ω_ref(dynamic_wrapper, Freq_ref) + set_Q_ref!(p, Qref) + set_V_ref!(p, Vref) + set_ω_ref!(p, Freq_ref) PSY.set_Pfa_ref!(dynamic_device, pfaref) - device_parameters[29] = pfaref + @view(p[:params])[:Pfa_ref] = pfaref return end diff --git a/src/initialization/inverter_components/init_inner.jl b/src/initialization/inverter_components/init_inner.jl index 756dde4b8..9310f8004 100644 --- a/src/initialization/inverter_components/init_inner.jl +++ b/src/initialization/inverter_components/init_inner.jl @@ -266,7 +266,7 @@ function initialize_inner!( inner_control = PSY.get_inner_control(dynamic_device) Q_Flag = PSY.get_Q_Flag(inner_control) PQ_Flag = PSY.get_PQ_Flag(inner_control) - params = p[:params][:InnerControl] + params = @view(@view(p[:params])[:InnerControl]) V_ref0 = params[:V_ref0] K_vi = params[:K_vi] diff --git a/src/initialization/inverter_components/init_outer.jl b/src/initialization/inverter_components/init_outer.jl index c38e9fab5..54e72a710 100644 --- a/src/initialization/inverter_components/init_outer.jl +++ b/src/initialization/inverter_components/init_outer.jl @@ -190,14 +190,14 @@ function initialize_outer!( #Update inner vars inner_vars[θ_oc_var] = θ0_oc - inner_vars[ω_oc_var] = get_ω_ref(dynamic_device) + inner_vars[ω_oc_var] = p[:refs][:ω_ref] #Update Q_ref. Initialization assumes q_ref = q_elec_out of PF solution - set_P_ref(dynamic_device, p_elec_out) + set_P_ref!(p, p_elec_out) PSY.set_P_ref!( PSY.get_active_power_control(PSY.get_outer_control(dynamic_device)), p_elec_out, ) - set_Q_ref(dynamic_device, q_elec_out) + set_Q_ref!(p, q_elec_out) end function initialize_outer!( diff --git a/src/models/device.jl b/src/models/device.jl index e7feabf29..a81b57775 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -850,7 +850,7 @@ Oleg Wasynczuk and Scott Sudhoff. function device!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -877,21 +877,21 @@ function device!( ωr = device_states[3] #Get parameters - R_s, - R_r, - X_ls, - X_lr, - X_m, - H, - A, - B, - base_power, - C, - τ_m0, - B_sh, - X_ss, - X_rr, - X_p = device_parameters + params = p[:params] + R_s = params[:R_s] + R_r = params[:R_r] + X_ls = params[:X_ls] + X_lr = params[:X_lr] + X_m = params[:X_m] + H = params[:H] + A = params[:A] + B = params[:B] + base_power = params[:base_power] + C = params[:C] + τ_m0 = params[:τ_ref] + B_sh = params[:B_shunt] + X_rr = params[:X_rr] + X_p = params[:X_p] # voltages in QD v_qs = voltage_i @@ -1246,7 +1246,7 @@ end function _mdl_ode_AggregateDistributedGenerationA!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::Val{0}, voltage_r::T, voltage_i::T, @@ -1263,9 +1263,9 @@ function _mdl_ode_AggregateDistributedGenerationA!( dynamic_device = get_device(dynamic_wrapper) #Obtain References (from wrapper and device) Pfa_ref = PSY.get_Pfa_ref(dynamic_device) - P_ref = get_P_ref(dynamic_wrapper) - Q_ref = get_Q_ref(dynamic_wrapper) - V_ref = get_V_ref(dynamic_wrapper) + P_ref = p[:refs][:P_ref] + Q_ref = p[:refs][:Q_ref] + V_ref = p[:refs][:V_ref] #Get flags Pf_Flag = PSY.get_Pf_Flag(dynamic_device) @@ -1283,35 +1283,25 @@ function _mdl_ode_AggregateDistributedGenerationA!( Iq_cmd = Iq #Get parameters - T_rv, - Trf, - dbd1, - dbd2, - K_qv, - Tp, - T_iq, - D_dn, - D_up, - fdbd_pnts, - fdbd_pnts, - fe_min, - fe_max, - P_min, - P_max, - dP_min, - dP_max, - Tpord, - Kpg, - Kig, - I_max, - Tg, - rrpwr, - Tv, - Vpr, - Iq_min, - Iq_max, - basepower, - Pfa_ref = device_parameters + params = p[:params] + T_rv = params[:T_rv] + Trf = params[:Trf] + dbd1 = params[:dbd_pnts1] + dbd2 = params[:dbd_pnts2] + K_qv = params[:K_qv] + Tp = params[:Tp] + T_iq = params[:T_iq] + D_dn = params[:D_dn] + D_up = params[:D_up] + fdbd_pnts1 = params[:fdbd_pnts1] + fdbd_pnts2 = params[:fdbd_pnts2] + Tg = params[:Tg] + rrpwr = params[:rrpwr] + Tv = params[:Tv] + Iq_min = params[:Iq_lim][:min] + Iq_max = params[:Iq_lim][:max] + basepower = params[:base_power] + Pfa_ref = params[:Pfa_ref] base_power_ratio = basepower / Sbase @@ -1387,7 +1377,7 @@ end function _mdl_ode_AggregateDistributedGenerationA!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, ::Val{1}, voltage_r::T, voltage_i::T, @@ -1404,10 +1394,10 @@ function _mdl_ode_AggregateDistributedGenerationA!( dynamic_device = get_device(dynamic_wrapper) #Obtain References (from wrapper and device) Pfa_ref = PSY.get_Pfa_ref(dynamic_device) - P_ref = get_P_ref(dynamic_wrapper) - Q_ref = get_Q_ref(dynamic_wrapper) - V_ref = get_V_ref(dynamic_wrapper) - ω_ref = get_ω_ref(dynamic_wrapper) + P_ref = p[:refs][:P_ref] + Q_ref = p[:refs][:Q_ref] + V_ref = p[:refs][:V_ref] + ω_ref = p[:refs][:ω_ref] #Get flags Pf_Flag = PSY.get_Pf_Flag(dynamic_device) @@ -1428,35 +1418,34 @@ function _mdl_ode_AggregateDistributedGenerationA!( Iq_cmd = Iq #Get parameters - T_rv, - Trf, - dbd1, - dbd2, - K_qv, - Tp, - T_iq, - D_dn, - D_up, - fdbd1, - fdbd2, - fe_min, - fe_max, - P_min, - P_max, - dP_min, - dP_max, - Tpord, - Kpg, - Kig, - I_max, - Tg, - rrpwr, - Tv, - Vpr, - Iq_min, - Iq_max, - basepower, - Pfa_ref = device_parameters + params = p[:params] + T_rv = params[:T_rv] + Trf = params[:Trf] + dbd1 = params[:dbd_pnts1] + dbd2 = params[:dbd_pnts2] + K_qv = params[:K_qv] + Tp = params[:Tp] + T_iq = params[:T_iq] + D_dn = params[:D_dn] + D_up = params[:D_up] + fdbd1 = params[:fdbd_pnts1] + fdbd2 = params[:fdbd_pnts2] + fe_min = params[:fe_lim][:min] + fe_max = params[:fe_lim][:max] + P_min = params[:P_lim][:min] + P_max = params[:P_lim][:max] + dP_min = params[:dP_lim][:min] + dP_max = params[:dP_lim][:max] + Tpord = params[:Tpord] + Kpg = params[:Kpg] + Kig = params[:Kig] + Tg = params[:Tg] + rrpwr = params[:rrpwr] + Tv = params[:Tv] + Iq_min = params[:Iq_lim][:min] + Iq_max = params[:Iq_lim][:max] + basepower = params[:base_power] + Pfa_ref = params[:Pfa_ref] base_power_ratio = basepower / Sbase diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index a364cfb58..a3ba53eb6 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -430,7 +430,7 @@ end function mdl_avr_ode!( device_states::AbstractArray, output_ode::AbstractArray, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.EXST1, TG, P}}, h, @@ -438,7 +438,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = p[:refs][:V_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.EXST1) @@ -456,20 +456,19 @@ function mdl_avr_ode!( Ifd = inner_vars[Xad_Ifd_var] # machine's field current in exciter base #Get Parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.EXST1) - internal_params = @view device_parameters[local_ix_params] - Tr, - Vi_min, - Vi_max, - Tc, - Tb, - Ka, - Ta, - Vr_min, - Vr_max, - Kc, - Kf, - Tf = internal_params + params = p[:params][:AVR] + Tr = params[:Tr] + Vi_min = params[:Vi_lim][:min] + Vi_max = params[:Vi_lim][:max] + Tc = params[:Tc] + Tb = params[:Tb] + Ka = params[:Ka] + Ta = params[:Ta] + Vr_min = params[:Vr_lim][:min] + Vr_max = params[:Vr_lim][:max] + Kc = params[:Kc] + Kf = params[:Kf] + Tf = params[:Tf] #Compute auxiliary parameters V_ref = V0_ref + Vs @@ -496,7 +495,7 @@ end function mdl_avr_ode!( device_states::AbstractArray, output_ode::AbstractArray, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.EXAC1, TG, P}}, h, @@ -504,7 +503,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V_ref = get_V_ref(dynamic_device) + V_ref = p[:refs][:V_ref] #Obtain avr avr = PSY.get_avr(dynamic_device) @@ -526,21 +525,20 @@ function mdl_avr_ode!( Xad_Ifd = inner_vars[Xad_Ifd_var] # machine's field current in exciter base #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.EXAC1) - internal_params = @view device_parameters[local_ix_params] - Tr, - Tb, - Tc, - Ka, - Ta, - Vr_min, - Vr_max, - Te, - Kf, - Tf, - Kc, - Kd, - Ke = internal_params + params = p[:params][:AVR] + Tr = params[:Tr] + Tb = params[:Tb] + Tc = params[:Tc] + Ka = params[:Ka] + Ta = params[:Ta] + Vr_min = params[:Vr_lim][:min] + Vr_max = params[:Vr_lim][:max] + Te = params[:Te] + Kf = params[:Kf] + Tf = params[:Tf] + Kc = params[:Kc] + Kd = params[:Kd] + Ke = params[:Ke] #Obtain saturation Se = saturation_function(avr, Ve) diff --git a/src/models/generator_models/pss_models.jl b/src/models/generator_models/pss_models.jl index fba77bfc9..50a1f3dc7 100644 --- a/src/models/generator_models/pss_models.jl +++ b/src/models/generator_models/pss_models.jl @@ -131,7 +131,7 @@ end function mdl_pss_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.IEEEST}}, @@ -166,22 +166,24 @@ function mdl_pss_ode!( x_p7 = internal_states[7] # Get Parameters - A1 = PSY.get_A1(pss) - A2 = PSY.get_A2(pss) - A3 = PSY.get_A3(pss) - A4 = PSY.get_A4(pss) - A5 = PSY.get_A5(pss) - A6 = PSY.get_A6(pss) - T1 = PSY.get_T1(pss) - T2 = PSY.get_T2(pss) - T3 = PSY.get_T3(pss) - T4 = PSY.get_T4(pss) - T5 = PSY.get_T5(pss) - T6 = PSY.get_T6(pss) - Ks = PSY.get_Ks(pss) - Ls_min, Ls_max = PSY.get_Ls_lim(pss) - V_cu = PSY.get_Vcu(pss) - V_cl = PSY.get_Vcl(pss) + params = p[:params][:PSS] + A1 = params[:A1] + A2 = params[:A2] + A3 = params[:A3] + A4 = params[:A4] + A5 = params[:A5] + A6 = params[:A6] + T1 = params[:T1] + T2 = params[:T2] + T3 = params[:T3] + T4 = params[:T4] + T5 = params[:T5] + T6 = params[:T6] + Ks = params[:Ks] + Ls_min = params[:Ls_lim1] + Ls_max = params[:Ls_lim2] + V_cu = params[:Vcu] + V_cl = params[:Vcl] #Compute Parameter Ratios #A6_A2 = A2 < eps() ? 0.0 : (A6 / A2) @@ -231,7 +233,7 @@ end function mdl_pss_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.STAB1}}, @@ -254,15 +256,14 @@ function mdl_pss_ode!( x_p3 = internal_states[3] # state for Lead Lag 2 # Get Parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.STAB1) - internal_params = @view device_parameters[local_ix_params] - KT, - T, - T1T3, - T3, - T2T4, - T4, - H_lim = internal_params + params = p[:params][:PSS] + KT = params[:KT] + T = params[:T] + T1T3 = params[:T1T3] + T3 = params[:T3] + T2T4 = params[:T2T4] + T4 = params[:T4] + H_lim = params[:H_lim] K = T * KT T1 = T3 * T1T3 diff --git a/src/models/inverter_models/converter_models.jl b/src/models/inverter_models/converter_models.jl index c04f5ad8b..4f2326bcb 100644 --- a/src/models/inverter_models/converter_models.jl +++ b/src/models/inverter_models/converter_models.jl @@ -164,7 +164,6 @@ function mdl_converter_ode!( #Compute converter voltage Vr_cnv, Vi_cnv = V_cnv_calc(Ir_cnv, Ii_cnv, V_R, V_I) - #Update ODEs output_ode[local_ix[1]] = Ip_binary * (1.0 / T_g) * Ip_in #(Ip_cmd - Ip) output_ode[local_ix[2]] = (1.0 / T_g) * Iq_in # (Iq_cmd - Iq) diff --git a/src/models/inverter_models/outer_control_models.jl b/src/models/inverter_models/outer_control_models.jl index 1d3e2bd0b..1280aea72 100644 --- a/src/models/inverter_models/outer_control_models.jl +++ b/src/models/inverter_models/outer_control_models.jl @@ -745,7 +745,7 @@ end function mdl_outer_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{ @@ -781,21 +781,20 @@ function mdl_outer_ode!( Ii_filter = device_states[external_ix[4]] #Get Active Power Controller parameters - outer_control = PSY.get_outer_control(dynamic_device) - active_power_control = PSY.get_active_power_control(outer_control) - k1 = PSY.get_k1(active_power_control) - ψ = PSY.get_ψ(active_power_control) + params_active = p[:params][:OuterControl][:ActivePowerControl] + k1 = params_active[:k1] + ψ = params_active[:ψ] f0 = get_system_base_frequency(dynamic_device) ωb = 2 * pi * f0 #Rated angular frequency #Get Reactive Power Controller parameters - reactive_power_control = PSY.get_reactive_power_control(outer_control) - k2 = PSY.get_k2(reactive_power_control) + params_reactive = p[:params][:OuterControl][:ReactivePowerControl] + k2 = params_reactive[:k2] #Obtain external parameters - p_ref = get_P_ref(dynamic_device) - V_ref = get_V_ref(dynamic_device) - q_ref = get_Q_ref(dynamic_device) + p_ref = p[:refs][:P_ref] + V_ref = p[:refs][:V_ref] + q_ref = p[:refs][:Q_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix( @@ -824,7 +823,7 @@ function mdl_outer_ode!( (k1 / E_oc) * (-sin(γ) * (p_ref - p_elec_out) + cos(γ) * (q_ref - q_elec_out)) + k2 * (V_ref^2 - E_oc^2) * E_oc ) - + outer_control = PSY.get_outer_control(dynamic_device) ext = PSY.get_ext(outer_control) bool_val = get(ext, "is_not_reference", 1.0) diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index 860aeafc9..9c14c6e71 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -148,6 +148,11 @@ get_params_metadata(::PSY.VirtualInertia) = ( kd = ParamsMetadata(DEVICE_PARAM, false, false), kω = ParamsMetadata(DEVICE_PARAM, false, false), ) +get_params(x::PSY.ActiveVirtualOscillator) = (k1 = PSY.get_k1(x), ψ = PSY.get_ψ(x)) +get_params_metadata(::PSY.ActiveVirtualOscillator) = ( + k1 = ParamsMetadata(DEVICE_PARAM, false, false), + ψ = ParamsMetadata(DEVICE_PARAM, false, false), +) #Note: Removed fbdd_pnts from parameters because it is not a NamedTuple get_params(x::PSY.ActiveRenewableControllerAB) = ( K_pg = PSY.get_K_pg(x), @@ -203,6 +208,9 @@ get_params_metadata(::PSY.ReactivePowerDroop) = ( kq = ParamsMetadata(DEVICE_PARAM, false, false), ωf = ParamsMetadata(DEVICE_PARAM, false, false), ) +get_params(x::PSY.ReactiveVirtualOscillator) = (k2 = PSY.get_k2(x),) +get_params_metadata(::PSY.ReactiveVirtualOscillator) = + (k2 = ParamsMetadata(DEVICE_PARAM, false, false),) get_params(x::PSY.ReactiveRenewableControllerAB) = ( T_fltr = PSY.get_T_fltr(x), K_p = PSY.get_K_p(x), @@ -768,65 +776,67 @@ get_params_metadata(::PSY.ESAC1A) = ( max = ParamsMetadata(DEVICE_PARAM, true, false), ), ) -#= -get_params(x::PSY.EXST1) = [ - PSY.get_Tr(x), - PSY.get_Vi_lim(x)[1], - PSY.get_Vi_lim(x)[2], - PSY.get_Tc(x), - PSY.get_Tb(x), - PSY.get_Ka(x), - PSY.get_Ta(x), - PSY.get_Vr_lim(x)[1], - PSY.get_Vr_lim(x)[2], - PSY.get_Kc(x), - PSY.get_Kf(x), - PSY.get_Tf(x), -] -get_params_metadata(::PSY.EXST1) = [ - ParamsMetadata(:Tr_AVR, true, false, false, false), - ParamsMetadata(:Vi_min_AVR, false, false, false, false), - ParamsMetadata(:Vi_max_AVR, false, false, false, false), - ParamsMetadata(:Tc_AVR, false, false, true, false), - ParamsMetadata(:Tb_AVR, true, false, true, false), - ParamsMetadata(:Ka_AVR, false, false, true, false), - ParamsMetadata(:Ta_AVR, true, false, false, false), - ParamsMetadata(:Vr_min_AVR, false, false, true, false), - ParamsMetadata(:Vr_max_AVR, false, false, true, false), - ParamsMetadata(:Kc_AVR, false, false, true, false), - ParamsMetadata(:Kf_AVR, false, false, true, false), - ParamsMetadata(:Tf_AVR, false, false, true, false), -] -get_params(x::PSY.EXAC1) = [ - PSY.get_Tr(x), - PSY.get_Tb(x), - PSY.get_Tc(x), - PSY.get_Ka(x), - PSY.get_Ta(x), - PSY.get_Vr_lim(x)[1], - PSY.get_Vr_lim(x)[2], - PSY.get_Te(x), - PSY.get_Kf(x), - PSY.get_Tf(x), - PSY.get_Kc(x), - PSY.get_Kd(x), - PSY.get_Ke(x)] -get_params_metadata(::PSY.EXAC1) = [ - ParamsMetadata(:Tr_AVR, true, false, false, false), - ParamsMetadata(:Tb_AVR, true, false, true, false), - ParamsMetadata(:Tc_AVR, false, false, true, false), - ParamsMetadata(:Ka_AVR, false, false, true, false), - ParamsMetadata(:Ta_AVR, true, false, false, false), - ParamsMetadata(:Vr_min_AVR, false, false, true, false), - ParamsMetadata(:Vr_max_AVR, false, false, true, false), - ParamsMetadata(:Te_AVR, false, false, false, false), - ParamsMetadata(:Kf_AVR, false, false, true, false), - ParamsMetadata(:Tf_AVR, false, false, true, false), - ParamsMetadata(:Kc_AVR, false, false, true, false), - ParamsMetadata(:Kd_AVR, false, false, true, false), - ParamsMetadata(:Ke_AVR, false, false, true, false), -] - =# +get_params(x::PSY.EXST1) = ( + Tr = PSY.get_Tr(x), + Vi_lim = PSY.get_Vi_lim(x), + Tc = PSY.get_Tc(x), + Tb = PSY.get_Tb(x), + Ka = PSY.get_Ka(x), + Ta = PSY.get_Ta(x), + Vr_lim = PSY.get_Vr_lim(x), + Kc = PSY.get_Kc(x), + Kf = PSY.get_Kf(x), + Tf = PSY.get_Tf(x), +) +get_params_metadata(::PSY.EXST1) = ( + Tr = ParamsMetadata(DEVICE_PARAM, true, false), + Vi_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + Tc = ParamsMetadata(DEVICE_PARAM, false, true), + Tb = ParamsMetadata(DEVICE_PARAM, true, true), + Ka = ParamsMetadata(DEVICE_PARAM, false, true), + Ta = ParamsMetadata(DEVICE_PARAM, true, false), + Vr_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, true), + max = ParamsMetadata(DEVICE_PARAM, false, true), + ), + Kc = ParamsMetadata(DEVICE_PARAM, false, true), + Kf = ParamsMetadata(DEVICE_PARAM, false, true), + Tf = ParamsMetadata(DEVICE_PARAM, false, true), +) +get_params(x::PSY.EXAC1) = ( + Tr = PSY.get_Tr(x), + Tb = PSY.get_Tb(x), + Tc = PSY.get_Tc(x), + Ka = PSY.get_Ka(x), + Ta = PSY.get_Ta(x), + Vr_lim = PSY.get_Vr_lim(x), + Te = PSY.get_Te(x), + Kf = PSY.get_Kf(x), + Tf = PSY.get_Tf(x), + Kc = PSY.get_Kc(x), + Kd = PSY.get_Kd(x), + Ke = PSY.get_Ke(x), +) +get_params_metadata(::PSY.EXAC1) = ( + Tr = ParamsMetadata(DEVICE_PARAM, true, false), + Tb = ParamsMetadata(DEVICE_PARAM, true, true), + Tc = ParamsMetadata(DEVICE_PARAM, false, true), + Ka = ParamsMetadata(DEVICE_PARAM, false, true), + Ta = ParamsMetadata(DEVICE_PARAM, true, false), + Vr_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, true), + max = ParamsMetadata(DEVICE_PARAM, false, true), + ), + Te = ParamsMetadata(DEVICE_PARAM, false, false), + Kf = ParamsMetadata(DEVICE_PARAM, false, true), + Tf = ParamsMetadata(DEVICE_PARAM, false, true), + Kc = ParamsMetadata(DEVICE_PARAM, false, true), + Kd = ParamsMetadata(DEVICE_PARAM, false, true), + Ke = ParamsMetadata(DEVICE_PARAM, false, true), +) #TurbineGov get_params(x::PSY.TGFixed) = (; efficiency = PSY.get_efficiency(x)) get_params_metadata(::PSY.TGFixed) = @@ -956,26 +966,62 @@ get_params_metadata(::PSY.HydroTurbineGov) = ( #PSS get_params(x::PSY.PSSFixed) = (; V_pss = PSY.get_V_pss(x)) get_params_metadata(::PSY.PSSFixed) = (; V_pss = ParamsMetadata(DEVICE_PARAM, false, false)) -#= -get_params(x::PSY.STAB1) = [ - PSY.get_KT(x), - PSY.get_T(x), - PSY.get_T1T3(x), - PSY.get_T3(x), - PSY.get_T2T4(x), - PSY.get_T4(x), - PSY.get_H_lim(x), -] -get_params_metadata(::PSY.STAB1) = [ - ParamsMetadata(:KT_PSS, false, false, false, false), - ParamsMetadata(:T_PSS, false, false, false, false), - ParamsMetadata(:T1T3_PSS, false, false, false, false), - ParamsMetadata(:T3_PSS, false, false, false, false), - ParamsMetadata(:T2T4_PSS, false, false, false, false), - ParamsMetadata(:T4_PSS, false, false, false, false), - ParamsMetadata(:H_lim_PSS, false, false, false, false), -] =# - +get_params(x::PSY.STAB1) = ( + KT = PSY.get_KT(x), + T = PSY.get_T(x), + T1T3 = PSY.get_T1T3(x), + T3 = PSY.get_T3(x), + T2T4 = PSY.get_T2T4(x), + T4 = PSY.get_T4(x), + H_lim = PSY.get_H_lim(x), +) +get_params_metadata(::PSY.STAB1) = ( + KT = ParamsMetadata(DEVICE_PARAM, false, false), + T = ParamsMetadata(DEVICE_PARAM, false, false), + T1T3 = ParamsMetadata(DEVICE_PARAM, false, false), + T3 = ParamsMetadata(DEVICE_PARAM, false, false), + T2T4 = ParamsMetadata(DEVICE_PARAM, false, false), + T4 = ParamsMetadata(DEVICE_PARAM, false, false), + H_lim = ParamsMetadata(DEVICE_PARAM, false, false), +) +get_params(x::PSY.IEEEST) = ( + A1 = PSY.get_A1(x), + A2 = PSY.get_A2(x), + A3 = PSY.get_A3(x), + A4 = PSY.get_A4(x), + A5 = PSY.get_A5(x), + A6 = PSY.get_A6(x), + T1 = PSY.get_T1(x), + T2 = PSY.get_T2(x), + T3 = PSY.get_T3(x), + T4 = PSY.get_T4(x), + T5 = PSY.get_T5(x), + T6 = PSY.get_T6(x), + Ks = PSY.get_Ks(x), + Ls_lim1 = PSY.get_Ls_lim(x)[1], + Ls_lim2 = PSY.get_Ls_lim(x)[2], + Vcu = PSY.get_Vcu(x), + Vcl = PSY.get_Vcl(x), +) +get_params_metadata(::PSY.IEEEST) = ( + A1 = ParamsMetadata(DEVICE_PARAM, false, true), + A2 = ParamsMetadata(DEVICE_PARAM, true, true), + A3 = ParamsMetadata(DEVICE_PARAM, false, false), + A4 = ParamsMetadata(DEVICE_PARAM, true, false), + A5 = ParamsMetadata(DEVICE_PARAM, false, true), + A6 = ParamsMetadata(DEVICE_PARAM, false, true), + T1 = ParamsMetadata(DEVICE_PARAM, false, true), + T2 = ParamsMetadata(DEVICE_PARAM, true, true), + T3 = ParamsMetadata(DEVICE_PARAM, false, true), + T4 = ParamsMetadata(DEVICE_PARAM, true, true), + T5 = ParamsMetadata(DEVICE_PARAM, false, true), + T6 = ParamsMetadata(DEVICE_PARAM, true, true), + Ks = ParamsMetadata(DEVICE_PARAM, false, true), + Ls_lim1 = ParamsMetadata(DEVICE_PARAM, false, true), + Ls_lim2 = ParamsMetadata(DEVICE_PARAM, false, true), + Vcu = ParamsMetadata(DEVICE_PARAM, false, true), + Vcl = ParamsMetadata(DEVICE_PARAM, false, true), +) #SOURCE get_params(x::PSY.Source) = ( R_th = PSY.get_R_th(x), @@ -1053,103 +1099,108 @@ get_params_metadata(::PSY.SingleCageInductionMachine) = ( X_ad = ParamsMetadata(DEVICE_PARAM, false, true), X_aq = ParamsMetadata(DEVICE_PARAM, false, true), ) -#= -get_params(x::PSY.SimplifiedSingleCageInductionMachine) = [ - PSY.get_R_s(x), - PSY.get_R_r(x), - PSY.get_X_ls(x), - PSY.get_X_lr(x), - PSY.get_X_m(x), - PSY.get_H(x), - PSY.get_A(x), - PSY.get_B(x), - PSY.get_base_power(x), - PSY.get_C(x), - PSY.get_τ_ref(x), - PSY.get_B_shunt(x), - PSY.get_X_ss(x), - PSY.get_X_rr(x), - PSY.get_X_p(x)] -get_params_metadata(::PSY.SimplifiedSingleCageInductionMachine) = [ - ParamsMetadata(:R_s, false, false, true, false), - ParamsMetadata(:R_r, false, false, true, false), - ParamsMetadata(:X_ls, false, false, false, false), - ParamsMetadata(:X_lr, false, false, false, false), - ParamsMetadata(:X_m, false, false, true, false), - ParamsMetadata(:H, false, false, false, false), - ParamsMetadata(:A, false, false, true, false), - ParamsMetadata(:B, false, false, true, false), - ParamsMetadata(:base_power, false, false, true, false), - ParamsMetadata(:C, false, false, true, false), - ParamsMetadata(:τ_ref, false, false, true, false), - ParamsMetadata(:B_shunt, false, false, true, false), - ParamsMetadata(:X_ss, false, false, true, false), - ParamsMetadata(:X_rr, false, false, true, false), - ParamsMetadata(:X_p, false, false, true, false), -] -get_params(x::PSY.AggregateDistributedGenerationA) = [ - PSY.get_T_rv(x), - PSY.get_Trf(x), - PSY.get_dbd_pnts(x)[1], - PSY.get_dbd_pnts(x)[2], - PSY.get_K_qv(x), - PSY.get_Tp(x), - PSY.get_T_iq(x), - PSY.get_D_dn(x), - PSY.get_D_up(x), - PSY.get_fdbd_pnts(x)[1], - PSY.get_fdbd_pnts(x)[2], - PSY.get_fe_lim(x)[1], - PSY.get_fe_lim(x)[2], - PSY.get_P_lim(x)[1], - PSY.get_P_lim(x)[2], - PSY.get_dP_lim(x)[1], - PSY.get_dP_lim(x)[2], - PSY.get_Tpord(x), - PSY.get_Kpg(x), - PSY.get_Kig(x), - PSY.get_I_max(x), - PSY.get_Tg(x), - PSY.get_rrpwr(x), - PSY.get_Tv(x), - PSY.get_Vpr(x), - PSY.get_Iq_lim(x)[1], - PSY.get_Iq_lim(x)[2], - PSY.get_base_power(x), - PSY.get_Pfa_ref(x), -] -get_params_metadata(::PSY.AggregateDistributedGenerationA) = [ - ParamsMetadata(:T_rv, true, false, false, false), - ParamsMetadata(:Trf, true, false, false, false), - ParamsMetadata(:dbd_pnts, false, false, false, false), - ParamsMetadata(:dbd_pnts, false, false, false, false), - ParamsMetadata(:K_qv, false, false, true, false), - ParamsMetadata(:Tp, true, false, false, false), - ParamsMetadata(:T_iq, true, false, false, false), - ParamsMetadata(:D_dn, false, false, false, false), - ParamsMetadata(:D_up, false, false, false, false), - ParamsMetadata(:fdbd_pnts, false, false, false, false), - ParamsMetadata(:fdbd_pnts, false, false, false, false), - ParamsMetadata(:fe_lim, false, false, false, false), - ParamsMetadata(:fe_lim, false, false, false, false), - ParamsMetadata(:P_lim, false, false, false, false), - ParamsMetadata(:P_lim, false, false, false, false), - ParamsMetadata(:dP_lim, false, false, false, false), - ParamsMetadata(:dP_lim, false, false, false, false), - ParamsMetadata(:Tpord, true, false, false, false), - ParamsMetadata(:Kpg, false, false, false, false), - ParamsMetadata(:Kig, false, false, false, false), - ParamsMetadata(:I_max, false, false, false, false), - ParamsMetadata(:Tg, false, false, false, false), - ParamsMetadata(:rrpwr, false, false, false, false), - ParamsMetadata(:Tv, true, false, false, false), - ParamsMetadata(:Vpr, false, false, false, false), - ParamsMetadata(:Iq_lim, false, false, false, false), - ParamsMetadata(:Iq_lim, false, false, false, false), - ParamsMetadata(:base_power, false, false, false, false), - ParamsMetadata(:Pfa_ref, false, false, true, false), -] +get_params(x::PSY.SimplifiedSingleCageInductionMachine) = ( + R_s = PSY.get_R_s(x), + R_r = PSY.get_R_r(x), + X_ls = PSY.get_X_ls(x), + X_lr = PSY.get_X_lr(x), + X_m = PSY.get_X_m(x), + H = PSY.get_H(x), + A = PSY.get_A(x), + B = PSY.get_B(x), + base_power = PSY.get_base_power(x), + C = PSY.get_C(x), + τ_ref = PSY.get_τ_ref(x), + B_shunt = PSY.get_B_shunt(x), + X_ss = PSY.get_X_ss(x), + X_rr = PSY.get_X_rr(x), + X_p = PSY.get_X_p(x), +) +get_params_metadata(::PSY.SimplifiedSingleCageInductionMachine) = ( + R_s = ParamsMetadata(DEVICE_PARAM, false, true), + R_r = ParamsMetadata(DEVICE_PARAM, false, true), + X_ls = ParamsMetadata(DEVICE_PARAM, false, false), + X_lr = ParamsMetadata(DEVICE_PARAM, false, false), + X_m = ParamsMetadata(DEVICE_PARAM, false, true), + H = ParamsMetadata(DEVICE_PARAM, false, false), + A = ParamsMetadata(DEVICE_PARAM, false, true), + B = ParamsMetadata(DEVICE_PARAM, false, true), + base_power = ParamsMetadata(DEVICE_PARAM, false, true), + C = ParamsMetadata(DEVICE_PARAM, false, true), + τ_ref = ParamsMetadata(DEVICE_PARAM, false, true), + B_shunt = ParamsMetadata(DEVICE_PARAM, false, true), + X_ss = ParamsMetadata(DEVICE_PARAM, false, true), + X_rr = ParamsMetadata(DEVICE_PARAM, false, true), + X_p = ParamsMetadata(DEVICE_PARAM, false, true), +) +get_params(x::PSY.AggregateDistributedGenerationA) = ( + T_rv = PSY.get_T_rv(x), + Trf = PSY.get_Trf(x), + dbd_pnts1 = PSY.get_dbd_pnts(x)[1], + dbd_pnts2 = PSY.get_dbd_pnts(x)[2], + K_qv = PSY.get_K_qv(x), + Tp = PSY.get_Tp(x), + T_iq = PSY.get_T_iq(x), + D_dn = PSY.get_D_dn(x), + D_up = PSY.get_D_up(x), + fdbd_pnts1 = PSY.get_fdbd_pnts(x)[1], + fdbd_pnts2 = PSY.get_fdbd_pnts(x)[2], + fe_lim = PSY.get_fe_lim(x), + P_lim = PSY.get_P_lim(x), + dP_lim = PSY.get_dP_lim(x), + Tpord = PSY.get_Tpord(x), + Kpg = PSY.get_Kpg(x), + Kig = PSY.get_Kig(x), + I_max = PSY.get_I_max(x), + Tg = PSY.get_Tg(x), + rrpwr = PSY.get_rrpwr(x), + Tv = PSY.get_Tv(x), + Vpr = PSY.get_Vpr(x), + Iq_lim = PSY.get_Iq_lim(x), + base_power = PSY.get_base_power(x), + Pfa_ref = PSY.get_Pfa_ref(x), +) +get_params_metadata(::PSY.AggregateDistributedGenerationA) = ( + T_rv = ParamsMetadata(DEVICE_PARAM, true, false), + Trf = ParamsMetadata(DEVICE_PARAM, true, false), + dbd_pnts1 = ParamsMetadata(DEVICE_PARAM, false, false), + dbd_pnts2 = ParamsMetadata(DEVICE_PARAM, false, false), + K_qv = ParamsMetadata(DEVICE_PARAM, false, true), + Tp = ParamsMetadata(DEVICE_PARAM, true, false), + T_iq = ParamsMetadata(DEVICE_PARAM, true, false), + D_dn = ParamsMetadata(DEVICE_PARAM, false, false), + D_up = ParamsMetadata(DEVICE_PARAM, false, false), + fdbd_pnts1 = ParamsMetadata(DEVICE_PARAM, false, false), + fdbd_pnts2 = ParamsMetadata(DEVICE_PARAM, false, false), + fe_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + P_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + dP_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + Tpord = ParamsMetadata(DEVICE_PARAM, true, false), + Kpg = ParamsMetadata(DEVICE_PARAM, false, false), + Kig = ParamsMetadata(DEVICE_PARAM, false, false), + I_max = ParamsMetadata(DEVICE_PARAM, false, false), + Tg = ParamsMetadata(DEVICE_PARAM, false, false), + rrpwr = ParamsMetadata(DEVICE_PARAM, false, false), + Tv = ParamsMetadata(DEVICE_PARAM, true, false), + Vpr = ParamsMetadata(DEVICE_PARAM, false, false), + Iq_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + base_power = ParamsMetadata(DEVICE_PARAM, false, false), + Pfa_ref = ParamsMetadata(DEVICE_PARAM, false, true), +) +#= get_params(x::PSY.CSVGN1) = [ PSY.get_K(x), PSY.get_T1(x), From 9e671ab99bd00f71296e551ae4ce9a435143b86f Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 2 Jul 2024 10:52:51 -0400 Subject: [PATCH 41/76] small fix in pss --- src/initialization/generator_components/init_pss.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/initialization/generator_components/init_pss.jl b/src/initialization/generator_components/init_pss.jl index 9617019b5..85ddb6969 100644 --- a/src/initialization/generator_components/init_pss.jl +++ b/src/initialization/generator_components/init_pss.jl @@ -8,7 +8,7 @@ function initialize_pss!( function initialize_pss!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.IEEEST}}, inner_vars::AbstractVector, @@ -46,8 +46,8 @@ function initialize_pss!( Ks = params[:Ks] Ls_min = params[:Ls_lim1] Ls_max = params[:Ls_lim2] - V_cu = params[:V_cu] - V_cl = params[:V_cl] + V_cu = params[:Vcu] + V_cl = params[:Vcl] #Error non-valid parameters if A6 > eps() && A2 < eps() From 3ec3bbd68b08629e324c593f08d091c7440409fa Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 2 Jul 2024 14:43:55 -0400 Subject: [PATCH 42/76] use NLsolve (wrapped) --- Project.toml | 2 ++ src/PowerSimulationsDynamics.jl | 1 + src/base/nlsolve_wrapper.jl | 6 +++--- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index 6501ddcb8..ba673252f 100644 --- a/Project.toml +++ b/Project.toml @@ -15,6 +15,7 @@ ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" +NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" PowerFlows = "94fada2c-fd9a-4e89-8d82-81405f5cb4f6" PowerNetworkMatrices = "bed98974-b02a-5e2f-9fe0-a103f5c450dd" @@ -37,6 +38,7 @@ ForwardDiff = "~v0.10" InfrastructureSystems = "^1.21" LinearAlgebra = "1" Logging = "1" +NLsolve = "4" NonlinearSolve = "3.11" PowerFlows = "^0.6" PowerNetworkMatrices = "^0.10" diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index 162cc686d..ede48b2bd 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -76,6 +76,7 @@ import SparseArrays import LinearAlgebra import Base.to_index import Base.length +import NLsolve #Using Nlsovle wrapped using NonlinearSolve interfaace import NonlinearSolve import PrettyTables import Base.ImmutableDict diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index dbcc12ee2..437280468 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -59,7 +59,7 @@ end function _convergence_check( sys_solve::NLsolveWrapper, tol::Float64, - solv::NonlinearSolve.AbstractNonlinearSolveAlgorithm, + solv::Symbol, ) if converged(sys_solve) @warn( @@ -181,7 +181,7 @@ function refine_initial_condition!( if converged break end - for solv in [NonlinearSolve.TrustRegion(), NonlinearSolve.NewtonRaphson()] + for solv in [:trust_region, :newton] @debug "Start NLSolve System Run with $(solv) and F_tol = $tol" show_trace = sim.console_level <= Logging.Info sys_solve = _nlsolve_call( @@ -190,7 +190,7 @@ function refine_initial_condition!( f!, jacobian, tol, - solv, + NonlinearSolve.NLsolveJL(; method = solv), show_trace, ) failed(sys_solve) && return BUILD_FAILED From 4f570eb788aaf40e2dd902b5021e8a2593593bc2 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 2 Jul 2024 14:44:14 -0400 Subject: [PATCH 43/76] sensitivity tests pass (no delays) --- src/base/sensitivity_analysis.jl | 7 +- test/test_case_enzyme.jl | 244 ++++++++++++++++++++++--------- test/test_case_sensitivity.jl | 4 +- 3 files changed, 179 insertions(+), 76 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 0db195964..c3458d543 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -134,8 +134,11 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; elseif init_level == INITIALIZED @info "I.C.s not impacted by parameter change" end - prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) - sol = SciMLBase.solve(prob_new, solver) + h(p, t; idxs = nothing) = begin + typeof(idxs) <: Number ? x0[idxs] : x0 + end + prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) # TODO - Need to add h here for delays + sol = SciMLBase.solve(prob_new, solver) # TODO - wrap = Val(false) gets a different enzyme error, but ruins ODE @assert length(state_ixs) == 1 #Hardcode for single state for now ix = state_ixs[1] diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index f69de76d2..ae3ec10d3 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -8,15 +8,12 @@ source voltage. This test also checks that incorrect user data is handled correc ############### LOAD DATA ###################### ## ################################################## -omib_sys = build_system(PSIDTestSystems, "psid_test_omib") ieee_9bus_sys = build_system(PSIDTestSystems, "psid_test_ieee_9bus") andes_11bus_sys = build_system(PSIDSystems, "psid_11bus_andes") ################################################## ############### SOLVE PROBLEM #################### ################################################## -s_device = get_component(Source, omib_sys, "InfBus") -s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) using PlotlyJS #NOTES ON SENSITIVITY ALGORITHMS FROM SCIMLSENSITIVITY @@ -26,6 +23,9 @@ using PlotlyJS @testset "Test Gradients - OMIB; H" begin path = mktempdir() try + omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + s_device = get_component(Source, omib_sys, "InfBus") + s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) sim = Simulation!( MassMatrixModel, omib_sys, @@ -42,8 +42,12 @@ using PlotlyJS #GET PARAMETER VALUES p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing function f_loss(δ, δ_gt) - #display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + #plot_traces(δ, δ_gt) return sum(abs.(δ - δ_gt)) end @@ -82,6 +86,9 @@ end @testset "Test Optimization - OMIB; H" begin path = mktempdir() try + omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + s_device = get_component(Source, omib_sys, "InfBus") + s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) sim = Simulation!( MassMatrixModel, omib_sys, @@ -89,7 +96,6 @@ end (0.0, 5.0), s_change, ) - #GET GROUND TRUTH DATA execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) res = read_results(sim) @@ -98,8 +104,12 @@ end #GET PARAMETER VALUES p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing function f_loss(δ, δ_gt) - #display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + #plot_traces(δ, δ_gt) return sum(abs.(δ - δ_gt)) end @@ -141,7 +151,72 @@ end end end -function add_degov_to_omib!(omib_sys) +@testset "Test Gradients - OMIB; Xd_p" begin + path = mktempdir() + try + omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + s_device = get_component(Source, omib_sys, "InfBus") + s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + + #GET GROUND TRUTH DATA + execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-102-1", :Machine, :Xd_p)]) + + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing + function f_loss(δ, δ_gt) + #plot_traces(δ, δ_gt) + return sum(abs.(δ - δ_gt)) + end + + #GET SENSITIVITY FUNCTIONS + f_forward, f_grad = get_sensitivity_functions( + sim, + [("generator-102-1", :Machine, :Xd_p)], + [("generator-102-1", :δ)], + Rodas4(), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + + loss_zero = f_forward(p, δ_gt) + loss_non_zero_1 = f_forward(p * 1.01, δ_gt) + loss_non_zero_2 = f_forward(p * 0.99, δ_gt) + @test isapprox(loss_zero, 0.0, atol = 1e-9) + @test loss_non_zero_1 != 0.0 + @test loss_non_zero_2 != 0.0 + grad_zero = f_grad(p, δ_gt) + grad_nonzero_1 = f_grad(p * 1.01, δ_gt) + grad_nonzero_2 = f_grad(p * 0.99, δ_gt) + @test isapprox(grad_zero[1], -4.0, atol = 1.0) + @test isapprox(grad_nonzero_1[1], 499.0, atol = 1.0) + @test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + +#BELOW HERE: TESTS FOR SENSITIVITY OF DDES + +#= function add_degov_to_omib!(omib_sys) gen = get_component(ThermalStandard, omib_sys, "generator-102-1") dyn_gen = get_component(DynamicGenerator, omib_sys, "generator-102-1") new_gov = PSY.DEGOV(; @@ -169,22 +244,26 @@ function add_degov_to_omib!(omib_sys) add_component!(omib_sys, dyn_gen_new, gen) end -#= @testset "Test Gradients - OMIB; H; Delays" begin +@testset "Test Gradients - OMIB; H; Delays" begin path = mktempdir() try + #EnzymeRules.inactive(::typeof(Base.hasproperty), args...) = nothing # To allow wrap_sol to work? --> causes gradient to b zero; bad idea to go marking functions invalid without clear reason. + omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + s_device = get_component(Source, omib_sys, "InfBus") + s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) add_degov_to_omib!(omib_sys) sim = Simulation!( MassMatrixModel, omib_sys, - path, - (0.0, 5.0), + pwd(), + (0.0, 0.4), #Inside of the delay time... s_change, ) #GET GROUND TRUTH DATA execute!( sim, - MethodOfSteps(Rodas4(; autodiff = false)); + MethodOfSteps(Rodas5(; autodiff = false)); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, @@ -196,8 +275,12 @@ end #GET PARAMETER VALUES p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing function f_loss(δ, δ_gt) - #display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + plot_traces(δ, δ_gt) return sum(abs.(δ - δ_gt)) end @@ -206,89 +289,104 @@ end sim, [("generator-102-1", :Shaft, :H)], [("generator-102-1", :δ)], - MethodOfSteps(Rodas4()), + MethodOfSteps(Rodas5(; autodiff = false)), + #MethodOfSteps(QNDF(;autodiff=true)), f_loss; + # wrap = Val(false), #error related to wrapping of solution? sensealg = ForwardDiffSensitivity(), - abstol = 1e-9, - reltol = 1e-9, + abstol = 1e-2, # 1e-6 + reltol = 1e-2, # 1e-6 dtmax = 0.005, saveat = 0.005, ) loss_zero = f_forward(p, δ_gt) - loss_non_zero_1 = f_forward([3.2], δ_gt) + loss_non_zero_1 = f_forward([5.2], δ_gt) loss_non_zero_2 = f_forward(p, δ_gt .* 2) - @test loss_zero == 0.0 + @test isapprox(loss_zero, 0.0, atol = 3e-9) @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 grad_zero = f_grad(p, δ_gt) grad_nonzero_1 = f_grad([3.14], δ_gt) grad_nonzero_2 = f_grad([3.15], δ_gt) @test isapprox(grad_zero[1], 0.0, atol = 1.0) - @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) + @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) #-10 and 10 in Zygote... if the timespan and all settings are identical... @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) finally @info("removing test files") rm(path; force = true, recursive = true) end -end =# +end -@testset "Test Gradients - OMIB; Xd_p" begin - path = mktempdir() - try - sim = Simulation!( - MassMatrixModel, - omib_sys, - path, - (0.0, 5.0), - s_change, - ) +#Can we get the gradient based on the I.Cs when we have a delay differential equation? +#@testset "Test Gradients - OMIB; Xd_p; delays" begin +path = mktempdir() +#try +omib_sys = build_system(PSIDTestSystems, "psid_test_omib") +add_degov_to_omib!(omib_sys) +s_device = get_component(Source, omib_sys, "InfBus") +s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) +sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + #s_change, +) - #GET GROUND TRUTH DATA - execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) - res = read_results(sim) - t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) +#GET GROUND TRUTH DATA +execute!( + sim, + MethodOfSteps(Rodas4()); + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, +) +res = read_results(sim) +t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) - #GET PARAMETER VALUES - p = get_parameter_values(sim, [("generator-102-1", :Machine, :Xd_p)]) +#GET PARAMETER VALUES +p = get_parameter_values(sim, [("generator-102-1", :Machine, :Xd_p)]) - function plot_traces(δ, δ_gt) - display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) - end - EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(δ, δ_gt) - #plot_traces(δ, δ_gt) - return sum(abs.(δ - δ_gt)) - end +function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) +end +EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing +function f_loss(δ, δ_gt) + plot_traces(δ, δ_gt) + return sum(abs.(δ - δ_gt)) +end - #GET SENSITIVITY FUNCTIONS - f_forward, f_grad = get_sensitivity_functions( - sim, - [("generator-102-1", :Machine, :Xd_p)], - [("generator-102-1", :δ)], - Rodas4(), - f_loss; - sensealg = ForwardDiffSensitivity(), - abstol = 1e-9, - reltol = 1e-9, - dtmax = 0.005, - saveat = 0.005, - ) +#GET SENSITIVITY FUNCTIONS +f_forward, f_grad = get_sensitivity_functions( + sim, + [("generator-102-1", :Machine, :Xd_p)], + [("generator-102-1", :δ)], + MethodOfSteps(Rodas4()), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-6, + reltol = 1e-6, + dtmax = 0.005, + saveat = 0.005, +) - loss_zero = f_forward(p, δ_gt) - loss_non_zero_1 = f_forward(p * 1.01, δ_gt) - loss_non_zero_2 = f_forward(p * 0.99, δ_gt) - @test isapprox(loss_zero, 0.0, atol = 1e-9) - @test loss_non_zero_1 != 0.0 - @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, δ_gt) - grad_nonzero_1 = f_grad(p * 1.01, δ_gt) - grad_nonzero_2 = f_grad(p * 0.99, δ_gt) - @test isapprox(grad_zero[1], 497, atol = 1.0) - @test isapprox(grad_nonzero_1[1], 499.0, atol = 1.0) - @test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) - finally - @info("removing test files") - rm(path; force = true, recursive = true) - end -end +loss_zero = f_forward(p, δ_gt) +loss_non_zero_1 = f_forward(p * 1.01, δ_gt) +loss_non_zero_2 = f_forward(p * 0.99, δ_gt) +@test isapprox(loss_zero, 0.0, atol = 1e-9) +@test loss_non_zero_1 != 0.0 +@test loss_non_zero_2 != 0.0 +grad_zero = f_grad(p, δ_gt) +grad_nonzero_1 = f_grad(p * 1.01, δ_gt) +grad_nonzero_2 = f_grad(p * 0.99, δ_gt) +@test isapprox(grad_zero[1], 497, atol = 1.0) +@test isapprox(grad_nonzero_1[1], 499.0, atol = 1.0) +@test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) +#finally +# @info("removing test files") +# rm(path; force = true, recursive = true) +#end +#end + =# diff --git a/test/test_case_sensitivity.jl b/test/test_case_sensitivity.jl index c85842531..1c163b2f5 100644 --- a/test/test_case_sensitivity.jl +++ b/test/test_case_sensitivity.jl @@ -1,4 +1,5 @@ - +#Replaced by test_case_enzyme; this is the old version for Zygote +#= """ Case 1: This case study defines a classical machine against an infinite bus. Sensitivitiy @@ -409,3 +410,4 @@ end rm(path; force = true, recursive = true) end end =# + =# From 4de5fb74383941a8642b5f52746c81c7a8f13b41 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 3 Jul 2024 09:13:29 -0400 Subject: [PATCH 44/76] typo --- test/test_case_source_bus_voltage_change.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_case_source_bus_voltage_change.jl b/test/test_case_source_bus_voltage_change.jl index 82ca453cf..81d97ff3d 100644 --- a/test/test_case_source_bus_voltage_change.jl +++ b/test/test_case_source_bus_voltage_change.jl @@ -1,7 +1,7 @@ """ Case 27: This case study a three bus system with 1 machine (One d- One q-: 4th order model), a VSM of 19 states and an infinite source. -The test changes botht he voltage magnitude and phase angle of the source bus. +The test changes both the voltage magnitude and phase angle of the source bus. """ ################################################## From 1f0a0354c9b1002206ec606f292493a9b9ed5dc1 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 3 Jul 2024 15:02:23 -0400 Subject: [PATCH 45/76] don't index parameter component array by symbol in cb --- src/base/perturbations.jl | 139 +++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 39 deletions(-) diff --git a/src/base/perturbations.jl b/src/base/perturbations.jl index bac87b205..15bd841ed 100644 --- a/src/base/perturbations.jl +++ b/src/base/perturbations.jl @@ -472,12 +472,16 @@ end function get_affect(inputs::SimulationInputs, ::PSY.System, pert::ControlReferenceChange) wrapped_device_ix = _find_device_index(inputs, pert.device) + p = get_parameters(inputs) return (integrator) -> begin wrapped_device = get_dynamic_injectors(inputs)[wrapped_device_ix] wrapped_device_name = _get_wrapper_name(wrapped_device) - refs = @view(@view(integrator.p[wrapped_device_name])[:refs]) + p_change_ix = ComponentArrays.label2index( + p, + join((wrapped_device_name, "refs", pert.signal), "."), + ) @debug "Changing $(PSY.get_name(wrapped_device)) $(pert.signal) to $(pert.ref_value)" - refs[pert.signal] = pert.ref_value + integrator.p[p_change_ix] .= pert.ref_value return end end @@ -510,17 +514,21 @@ end function get_affect(inputs::SimulationInputs, ::PSY.System, pert::SourceBusVoltageChange) wrapped_device_ix = _find_device_index(inputs, pert.device) + wrapped_device = get_static_injectors(inputs)[wrapped_device_ix] + wrapped_device_name = _get_wrapper_name(wrapped_device) + p = get_parameters(inputs) + if pert.signal == :θ_ref || pert.signal == :V_ref + p_change_ix = ComponentArrays.label2index( + p, + join((wrapped_device_name, "refs", pert.signal), "."), + ) + else + error( + "Signal $(pert.signal) not accepted as a control reference change in SourceBus", + ) + end return (integrator) -> begin - wrapped_device = get_static_injectors(inputs)[wrapped_device_ix] - wrapped_device_name = _get_wrapper_name(wrapped_device) - refs = @view(@view(integrator.p[wrapped_device_name])[:refs]) - if pert.signal == :V_ref - refs[:V_ref] = pert.ref_value - elseif pert.signal == :θ_ref - refs[:θ_ref] = pert.ref_value - else - error("Signal $signal not accepted as a control reference change in SourceBus") - end + integrator.p[p_change_ix] .= pert.ref_value return end end @@ -616,6 +624,7 @@ end function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) sys_base_power = PSY.get_base_power(sys) wrapped_device_ix = _find_zip_load_ix(inputs, pert.device) + p = get_parameters(inputs) ld = pert.device if !PSY.get_available(ld) @error( @@ -626,6 +635,12 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) ref_value = pert.ref_value signal = pert.signal if isa(ld, PSY.PowerLoad) + wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] + wrapped_zip_name = _get_wrapper_name(wrapped_zip) + P_power_ix = + ComponentArrays.label2index(p, join((wrapped_zip_name, "refs", "P_power"), ".")) + Q_power_ix = + ComponentArrays.label2index(p, join((wrapped_zip_name, "refs", "P_power"), ".")) return (integrator) -> begin base_power_conversion = PSY.get_base_power(ld) / sys_base_power P_old = PSY.get_active_power(ld) @@ -641,13 +656,8 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) "Signal is not accepted for Constant PowerLoad. Please specify the correct signal type.", ) end - wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] - wrapped_zip_name = _get_wrapper_name(wrapped_zip) - refs = @view(@view(integrator.p[wrapped_zip_name])[:refs]) - P_power = refs[:P_power] - Q_power = refs[:Q_power] - refs[:P_power] = P_power + P_change - refs[:Q_power] = Q_power + Q_change + integrator.p[P_power_ix] .= integrator.p[P_power_ix] .+ P_change + integrator.p[Q_power_ix] .= integrator.p[Q_power_ix] .+ Q_change @debug "Changing load at bus $(PSY.get_name(wrapped_zip)) $(pert.signal) to $(pert.ref_value)" return end @@ -656,32 +666,55 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) base_power_conversion = PSY.get_base_power(ld) / sys_base_power wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] wrapped_zip_name = _get_wrapper_name(wrapped_zip) - refs = @view(@view(integrator.p[wrapped_zip_name])[:refs]) + P_impedance_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "P_impedance"), "."), + ) + Q_impedance_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "Q_impedance"), "."), + ) + P_power_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "P_power"), "."), + ) + Q_power_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "Q_power"), "."), + ) + P_current_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "P_current"), "."), + ) + Q_current_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "Q_current"), "."), + ) # List all cases for StandardLoad changes if signal ∈ [:P_ref, :P_ref_impedance] P_old = PSY.get_impedance_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - refs[:P_impedance] = refs[:P_impedance] + P_change + integrator.p[P_impedance_ix] .= integrator.p[P_impedance_ix] .+ P_change elseif signal ∈ [:Q_ref, :Q_ref_impedance] Q_old = PSY.get_impedance_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - refs[:Q_impedance] = refs[:Q_impedance] + Q_change + integrator.p[Q_impedance_ix] .= integrator.p[Q_impedance_ix] .+ Q_change elseif signal == :P_ref_power P_old = PSY.get_constant_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - refs[:P_power] = refs[:P_power] + P_change + integrator.p[P_power_ix] .= integrator.p[P_power_ix] .+ P_change elseif signal == :Q_ref_power Q_old = PSY.get_constant_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - refs[:Q_power] = refs[:Q_power] + Q_change + integrator.p[Q_power_ix] .= integrator.p[Q_power_ix] .+ Q_change elseif signal == :P_ref_current P_old = PSY.get_current_active_power(ld) P_change = (ref_value - P_old) * base_power_conversion - refs[:P_current] = refs[:P_current] + P_change + integrator.p[P_current_ix] .= integrator.p[P_current_ix] .+ P_change elseif signal == :Q_ref_current Q_old = PSY.get_current_reactive_power(ld) Q_change = (ref_value - Q_old) * base_power_conversion - refs[:Q_current] = refs[:Q_current] + Q_change + integrator.p[Q_current_ix] .= integrator.p[Q_current_ix] .+ Q_change else error("It should never be here. Should have failed in the constructor.") end @@ -691,7 +724,6 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadChange) ld_name = PSY.get_name(ld) wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] wrapped_zip_name = _get_wrapper_name(wrapped_zip) - refs = @view(@view(integrator.p[wrapped_zip_name])[:refs]) exp_names = get_exp_names(wrapped_zip) exp_vects = get_exp_params(wrapped_zip) tuple_ix = exp_names[ld_name] @@ -732,6 +764,7 @@ end function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) sys_base_power = PSY.get_base_power(sys) wrapped_device_ix = _find_zip_load_ix(inputs, pert.device) + p = get_parameters(inputs) ld = pert.device if !PSY.get_available(ld) @error( @@ -743,13 +776,16 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) base_power_conversion = PSY.get_base_power(ld) / sys_base_power P_trip = PSY.get_active_power(ld) * base_power_conversion Q_trip = PSY.get_reactive_power(ld) * base_power_conversion + wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] + wrapped_zip_name = _get_wrapper_name(wrapped_zip) + P_power_ix = + ComponentArrays.label2index(p, join((wrapped_zip_name, "refs", "P_power"), ".")) + Q_power_ix = + ComponentArrays.label2index(p, join((wrapped_zip_name, "refs", "Q_power"), ".")) return (integrator) -> begin PSY.set_available!(ld, false) - wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] - wrapped_zip_name = _get_wrapper_name(wrapped_zip) - refs = @view(@view(integrator.p[wrapped_zip_name])[:refs]) - refs[:P_power] = refs[:P_power] - P_trip - refs[:Q_power] = refs[:Q_power] - Q_trip + integrator.p[P_power_ix] .= integrator.p[P_power_ix] .- P_trip + integrator.p[Q_power_ix] .= integrator.p[Q_power_ix] .- Q_trip @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end @@ -765,16 +801,41 @@ function get_affect(inputs::SimulationInputs, sys::PSY.System, pert::LoadTrip) PSY.set_available!(ld, false) wrapped_zip = get_static_loads(inputs)[wrapped_device_ix] wrapped_zip_name = _get_wrapper_name(wrapped_zip) - refs = @view(@view(integrator.p[wrapped_zip_name])[:refs]) + P_impedance_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "P_impedance"), "."), + ) + Q_impedance_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "Q_impedance"), "."), + ) + P_power_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "P_power"), "."), + ) + Q_power_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "Q_power"), "."), + ) + P_current_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "P_current"), "."), + ) + Q_current_ix = ComponentArrays.label2index( + p, + join((wrapped_zip_name, "refs", "Q_current"), "."), + ) # Update Constant Power - refs[:P_power] = refs[:P_power] - P_power_trip - refs[:Q_power] = refs[:Q_power] - Q_power_trip + integrator.p[P_power_ix] .= integrator.p[P_power_ix] .- P_power_trip + integrator.p[Q_power_ix] .= integrator.p[Q_power_ix] .- Q_power_trip # Update Constant Current - refs[:P_current] = refs[:P_current] - P_current_trip - refs[:Q_current] = refs[:Q_current] - Q_current_trip + integrator.p[P_current_ix] .= integrator.p[P_current_ix] .- P_current_trip + integrator.p[Q_current_ix] .= integrator.p[Q_current_ix] .- Q_current_trip # Update Constant Impedance - refs[:P_impedance] = refs[:P_impedance] - P_impedance_trip - refs[:Q_impedance] = refs[:Q_impedance] - Q_impedance_trip + integrator.p[P_impedance_ix] .= + integrator.p[P_impedance_ix] .- P_impedance_trip + integrator.p[Q_impedance_ix] .= + integrator.p[Q_impedance_ix] .- Q_impedance_trip @debug "Removing load power values from ZIP load at $(PSY.get_name(wrapped_zip))" return end From 9acd155744409377522dcfa436dd301b2437ba88 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 10 Jul 2024 09:14:22 -0400 Subject: [PATCH 46/76] more model conversions --- .../generator_components/init_avr.jl | 67 ++-- .../generator_components/init_machine.jl | 73 ++-- .../generator_components/init_pss.jl | 9 +- .../generator_components/init_shaft.jl | 56 +-- src/initialization/init_device.jl | 74 ++-- src/models/device.jl | 64 +-- src/models/generator_models/avr_models.jl | 57 +-- src/models/generator_models/machine_models.jl | 53 ++- src/models/generator_models/pss_models.jl | 37 +- src/models/generator_models/shaft_models.jl | 41 +- src/utils/parameters.jl | 365 +++++++++++------- 11 files changed, 506 insertions(+), 390 deletions(-) diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index a04f766f1..9b784e6f0 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -379,7 +379,7 @@ end function initialize_avr!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.SCRX, TG, P}}, inner_vars::AbstractVector, @@ -392,23 +392,26 @@ function initialize_avr!( Vm = sqrt(inner_vars[VR_gen_var]^2 + inner_vars[VI_gen_var]^2) #Get parameters + params = p[:params][:AVR] avr = PSY.get_avr(dynamic_device) - Ta_Tb = PSY.get_Ta_Tb(avr) - Tb = PSY.get_Tb(avr) - Ta = Tb * Ta_Tb - # dont need Te >> no derivative so block is 0 (multiply by K in steady state) - K = PSY.get_K(avr) - V_min, V_max = PSY.get_Efd_lim(avr) #Efd_lim (V_lim) **n - switch = PSY.get_switch(avr) # reads switch parameters **n - rc_rfd = PSY.get_rc_rfd(avr) + V_min, V_max = params[:Efd_lim] + Ta_Tb = params[:Ta_Tb] + K = params[:K] # do the negative current and switch? or is that alr counted in? #States of AVRTypeI are Vf, Vr1, Vr2, Vm #To solve V_ref, Vr - function f!(out, x) + function f!(out, x, params) V_ref = x[1] Vr1 = x[2] + Ta_Tb = params[:Ta_Tb] + Tb = params[:Tb] + Ta = Tb * Ta_Tb + switch = PSY.get_switch(avr) + K = params[:K] + rc_rfd = params[:rc_rfd] + V_in = V_ref - Vm # assume Vs is 0 when init #lead lag block #V_LL = Vr2 + Ta_Tb * V_in @@ -437,13 +440,19 @@ function initialize_avr!( end # solve for Vref x0 = [1.0, Vf0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( "Initialization of AVR in $(PSY.get_name(static)) failed" ) - else # if converge - sol_x0 = sol.zero + else + sol_x0 = sol.u Vr2_0 = (sol_x0[2] + Ta_Tb * (sol_x0[1] - Vm)) * K # K * V_LL #check the limits if (Vr2_0 >= V_max + BOUNDS_TOLERANCE) || (Vr2_0 <= V_min - BOUNDS_TOLERANCE) @@ -453,7 +462,7 @@ function initialize_avr!( end #Update V_ref PSY.set_V_ref!(avr, sol_x0[1]) - set_V_ref(dynamic_device, sol_x0[1]) + set_V_ref!(p, sol_x0[1]) #Update AVR states avr_ix = get_local_state_ix(dynamic_device, PSY.SCRX) avr_states = @view device_states[avr_ix] @@ -598,7 +607,7 @@ end function initialize_avr!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.ESST1A, TG, P}}, inner_vars::AbstractVector, @@ -612,17 +621,19 @@ function initialize_avr!( #Get parameters avr = PSY.get_avr(dynamic_device) - Tc = PSY.get_Tc(avr) - Tb = PSY.get_Tb(avr) - Tc1 = PSY.get_Tc1(avr) - Tb1 = PSY.get_Tb1(avr) - Ka = PSY.get_Ka(avr) - Vr_min, Vr_max = PSY.get_Vr_lim(avr) - Kc = PSY.get_Kc(avr) - Kf = PSY.get_Kf(avr) - Tf = PSY.get_Tf(avr) - K_lr = PSY.get_K_lr(avr) - I_lr = PSY.get_I_lr(avr) + params = p[:params][:AVR] + Tc = params[:Tc] + Tb = params[:Tb] + Tc1 = params[:Tc1] + Tb1 = params[:Tb1] + Ka = params[:Ka] + Vr_min = params[:Vr_lim][:min] + Vr_max = params[:Vr_lim][:max] + Kc = params[:Kc] + Kf = params[:Kf] + Tf = params[:Tf] + K_lr = params[:K_lr] + I_lr = params[:I_lr] # Check limits to field voltage if (Vt * Vr_min > Vf0) || (Vf0 > Vt * Vr_max - Kc * Ifd) @@ -641,7 +652,7 @@ function initialize_avr!( Vref0 = Vt + Va / Ka PSY.set_V_ref!(avr, Vref0) - set_V_ref(dynamic_device, Vref0) + set_V_ref!(p, Vref0) #States of ESST1A_PTI are Vm, Vr1, Vr2, Va, Vr3 diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index 748aec485..6c2d51fdd 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -516,7 +516,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{ PSY.DynamicGenerator{PSY.AndersonFouadMachine, S, A, TG, P}, @@ -536,19 +536,9 @@ function initialize_mach_shaft!( I = conj(S0 / V) #Machine Data - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AndersonFouadMachine) - internal_params = @view device_parameters[local_ix_params] - R, - Xd, - Xq, - Xd_p, - Xq_p, - Xd_pp, - Xq_pp, - _, - _, - _, - _ = internal_params + params = p[:params][:Machine] + R = params[:R] + Xq = params[:Xq] #States of Anderson-Fouad are [1] ψq, [2] ψd, [3] eq_p, [4] ed_p, [5] eq_pp and [6] ed_pp δ0 = angle(V + (R + Xq * 1im) * I) @@ -557,7 +547,7 @@ function initialize_mach_shaft!( @assert isapprox(τm0, P0; atol = STRICT_NLSOLVE_F_TOLERANCE) #To solve: δ, τm, Vf0, eq_p, ed_p - function f!(out, x) + function f!(out, x, params) δ = x[1] τm = x[2] Vf0 = x[3] @@ -567,6 +557,13 @@ function initialize_mach_shaft!( ed_p = x[7] eq_pp = x[8] ed_pp = x[9] + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xq_pp = params[:Xq_pp] V_dq = ri_dq(δ) * [V_R; V_I] i_d = (1.0 / Xd_pp) * (eq_pp - ψd) #15.18 @@ -585,13 +582,19 @@ function initialize_mach_shaft!( V_dq0 = ri_dq(δ0) * [V_R; V_I] x0 = [δ0, τm0, 1.0, V_dq0[1], V_dq0[2], V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages inner_vars[VR_gen_var] = V_R inner_vars[VI_gen_var] = V_I @@ -627,7 +630,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations """ function initialize_mach_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{PSY.SimpleAFMachine, S, A, TG, P}}, inner_vars::AbstractVector, @@ -645,14 +648,9 @@ function initialize_mach_shaft!( I = conj(S0 / V) #Get parameters - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) - Xq_pp = PSY.get_Xq_pp(machine) + params = p[:params][:Machine] + R = params[:R] + Xq = params[:Xq] #States of SimpleAndersonFouad are [1] eq_p, [2] ed_p, [3] eq_pp and [4] ed_pp δ0 = angle(V + (R + Xq * 1im) * I) @@ -660,7 +658,7 @@ function initialize_mach_shaft!( τm0 = real(V * conj(I)) @assert isapprox(τm0, P0; atol = STRICT_NLSOLVE_F_TOLERANCE) #To solve: δ, τm, Vf0, eq_p, ed_p - function f!(out, x) + function f!(out, x, params) δ = x[1] τm = x[2] Vf0 = x[3] @@ -668,6 +666,13 @@ function initialize_mach_shaft!( ed_p = x[5] eq_pp = x[6] ed_pp = x[7] + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xq_pp = params[:Xq_pp] V_dq = ri_dq(δ) * [V_R; V_I] i_d = @@ -687,13 +692,19 @@ function initialize_mach_shaft!( end V_dq0 = ri_dq(δ0) * [V_R; V_I] x0 = [δ0, τm0, 1.0, V_dq0[2], V_dq0[1], V_dq0[2], V_dq0[1]] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) @warn( "Initialization in Machine $(PSY.get_name(static)) failed" ) else - sol_x0 = sol.zero + sol_x0 = sol.u #Update terminal voltages inner_vars[VR_gen_var] = V_R inner_vars[VI_gen_var] = V_I diff --git a/src/initialization/generator_components/init_pss.jl b/src/initialization/generator_components/init_pss.jl index 85ddb6969..218695247 100644 --- a/src/initialization/generator_components/init_pss.jl +++ b/src/initialization/generator_components/init_pss.jl @@ -274,7 +274,7 @@ end function initialize_pss!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSS2B}}, inner_vars::AbstractVector, @@ -321,11 +321,12 @@ function initialize_pss!( pss_states = @view device_states[pss_ix] # Get Required Parameters + params = p[:params][:PSS] M_rtf = PSY.get_M_rtf(pss) N_rtf = PSY.get_N_rtf(pss) - Tw1 = PSY.get_Tw1(pss) - Tw3 = PSY.get_Tw3(pss) - T9 = PSY.get_T9(pss) + Tw1 = params[:Tw1] + Tw3 = params[:Tw3] + T9 = params[:T9] Vs1_min, Vs1_max = PSY.get_Vs1_lim(pss) Vs2_min, Vs2_max = PSY.get_Vs2_lim(pss) diff --git a/src/initialization/generator_components/init_shaft.jl b/src/initialization/generator_components/init_shaft.jl index 2fc24c1a4..3b00beca5 100644 --- a/src/initialization/generator_components/init_shaft.jl +++ b/src/initialization/generator_components/init_shaft.jl @@ -1,6 +1,6 @@ function initialize_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, PSY.SingleMass, A, TG, P}}, inner_vars::AbstractVector, @@ -8,7 +8,7 @@ function initialize_shaft!( function initialize_shaft!( device_states, - device_parameters, + p, static::PSY.StaticInjection, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, PSY.FiveMassShaft, A, TG, P}}, inner_vars::AbstractVector, @@ -25,37 +25,31 @@ function initialize_shaft!( ω_sys = ω #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.FiveMassShaft) - internal_params = @view device_parameters[local_ix_params] - _, - _, - _, - _, - _, - D, - D_hp, - D_ip, - D_lp, - D_ex, - D_12, - D_23, - D_34, - D_45, - K_hp, - K_ip, - K_lp, - K_ex = internal_params + params = p[:params][:Shaft] #Obtain inner vars τe = inner_vars[τe_var] τm0 = inner_vars[τm_var] - function f!(out, x) + function f!(out, x, params) τm = x[1] δ_hp = x[2] δ_ip = x[3] δ_lp = x[4] δ_ex = x[5] + D = params[:D] + D_hp = params[:D_hp] + D_ip = params[:D_ip] + D_lp = params[:D_lp] + D_ex = params[:D_ex] + D_12 = params[:D_12] + D_23 = params[:D_23] + D_34 = params[:D_34] + D_45 = params[:D_45] + K_hp = params[:K_hp] + K_ip = params[:K_ip] + K_lp = params[:K_lp] + K_ex = params[:K_ex] out[1] = ( -τe - D * (ω - ω_sys) - D_34 * (ω - ω_lp) - D_45 * (ω - ω_ex) + @@ -80,11 +74,19 @@ function initialize_shaft!( end x0 = [τm0, δ0, δ0, δ0, δ0] - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) - @warn("Initialization in Shaft failed") + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) + @warn( + "Initialization in Shaft failed" + ) else - sol_x0 = sol.zero + sol_x0 = sol.u inner_vars[τm_var] = sol_x0[1] #τm shaft_states[3] = sol_x0[2] #δ_hp shaft_states[4] = ω #ω_hp diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index 7262d5c19..1ed9b896b 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -434,25 +434,18 @@ function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.CSVGN1}, device::PSY.StaticInjection, ::AbstractVector, - device_parameters::AbstractVector, + p::AbstractVector, device_states::AbstractVector, ) Sbase = get_system_base_power(dynamic_wrapper) # Get parameters - dynamic_device = get_device(dynamic_wrapper) - K, - T1, - T2, - T3, - T4, - T5, - Rmin, - Vmax, - Vmin, - Cbase, - Mbase, - R_th, - X_th = device_parameters + params = p[:params] + K = params[:K] + Rmin = params[:Rmin] + Vmax = params[:Vmax] + Vmin = params[:Vmin] + Cbase = params[:CBase] + Mbase = params[:base_power] # FIXME: base_power is changed to system's base_power when a CSVGN1 is attached to a Source using add_component!() # Temporarily, to avoid that, set_dynamic_injector!() could be used Rbase = Mbase @@ -466,7 +459,7 @@ function initialize_dynamic_device!( V_ref0 = V_abs - (Cbase / Sbase - Y) * 1 / K * Sbase / Mbase # update V_ref - set_V_ref(dynamic_wrapper, V_ref0) + set_V_ref!(p, V_ref0) thy = K * (V_abs - V_ref0) vr2 = thy @@ -489,7 +482,7 @@ function initialize_dynamic_device!( dynamic_wrapper::DynamicWrapper{PSY.ActiveConstantPowerLoad}, device::PSY.StaticInjection, ::AbstractVector, - device_parameters::AbstractVector, + p::AbstractVector, device_states::AbstractVector, ) Sbase = get_system_base_power(dynamic_wrapper) @@ -497,20 +490,14 @@ function initialize_dynamic_device!( dynamic_device = get_device(dynamic_wrapper) #Get parameters - r_load, - _, - rf, - lf, - cf, - rg, - lg, - _, - _, - _, - kiv, - _, - kic, - base_power = device_parameters + params = p[:params] + r_load = params[:r_load] + rf = params[:rf] + lf = params[:lf] + cf = params[:cf] + rg = params[:rg] + lg = params[:lg] + base_power = params[:base_power] #PowerFlow Data if isa(device, PSY.StandardLoad) @@ -547,12 +534,15 @@ function initialize_dynamic_device!( V_ref0 = sqrt(P_cnv0 * r_load) x0 = [θ_pll0, 0.0, 0.0, 0.0, 0.0] - function f!(out, x) + function f!(out, x, params) θ_pll = x[1] η = x[2] γd = x[3] γq = x[4] Iq_ref = x[5] + lf = params[:lf] + kiv = params[:kiv] + kic = params[:kic] V_dq_pll = ri_dq(θ_pll + pi / 2) * [Vr_filter0; Vi_filter0] I_dq_cnv = ri_dq(θ_pll + pi / 2) * [Ir_cnv0; Ii_cnv0] @@ -570,13 +560,17 @@ function initialize_dynamic_device!( out[4] = V_dq_cnv0[q] - Vq_cnv out[5] = V_dq_cnv0[d] - Vd_cnv end - sol = NLsolve.nlsolve(f!, x0; ftol = STRICT_NLSOLVE_F_TOLERANCE) - if !NLsolve.converged(sol) - @warn( - "Initialization in Active Load $(PSY.get_name(device)) failed" - ) + prob = NonlinearSolve.NonlinearProblem{true}(f!, x0, params) + sol = NonlinearSolve.solve( + prob, + NonlinearSolve.TrustRegion(); + reltol = STRICT_NLSOLVE_F_TOLERANCE, + abstol = STRICT_NLSOLVE_F_TOLERANCE, + ) + if !SciMLBase.successful_retcode(sol) + @warn("Initialization in Active Load $(PSY.get_name(device)) failed") else - sol_x0 = sol.zero + sol_x0 = sol.u device_states[1] = sol_x0[1] # θ_pll device_states[2] = 0.0 # ϵ device_states[3] = sol_x0[2] # η @@ -592,8 +586,8 @@ function initialize_dynamic_device!( # update V_ref PSY.set_V_ref!(dynamic_device, V_ref0) - set_V_ref(dynamic_wrapper, V_ref0) - set_Q_ref(dynamic_wrapper, sol_x0[5]) + set_V_ref!(p, V_ref0) + set_Q_ref!(p, sol_x0[5]) end return device_states end diff --git a/src/models/device.jl b/src/models/device.jl index a81b57775..e50a2d58d 100644 --- a/src/models/device.jl +++ b/src/models/device.jl @@ -950,7 +950,7 @@ Model of Static Shunt Compensator: CSVGN1. function device!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -962,7 +962,7 @@ function device!( t, ) where {T <: ACCEPTED_REAL_TYPES} Sbase = get_system_base_power(dynamic_wrapper) - V_ref = get_V_ref(dynamic_wrapper) + V_ref = p[:refs][:V_ref] # TODO: V_abs is the voltage magnitude on the high side of generator step-up transformer, if present. V_abs = sqrt(voltage_r^2 + voltage_i^2) @@ -978,19 +978,18 @@ function device!( vr2 = device_states[3] #Get parameters - K, - T1, - T2, - T3, - T4, - T5, - Rmin, - Vmax, - Vmin, - Cbase, - Mbase, - R_th, - X_th = device_parameters + params = p[:params] + K = params[:K] + T1 = params[:T1] + T2 = params[:T2] + T3 = params[:T3] + T4 = params[:T4] + T5 = params[:T5] + Rmin = params[:Rmin] + Vmax = params[:Vmax] + Vmin = params[:Vmin] + Cbase = params[:CBase] + Mbase = params[:base_power] # FIXME: base_power is changed to system's base_power when a CSVGN1 is attached to a Source using add_component!() # Temporarily, to avoid that, set_dynamic_injector!() could be used @@ -1063,7 +1062,7 @@ by C. Roberts, U. Markovic, D. Arnold and D. Callaway. function device!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{T}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, voltage_r::T, voltage_i::T, current_r::AbstractArray{T}, @@ -1076,7 +1075,7 @@ function device!( ) where {T <: ACCEPTED_REAL_TYPES} Sbase = get_system_base_power(dynamic_wrapper) f0 = get_system_base_frequency(dynamic_wrapper) - V_ref = get_V_ref(dynamic_wrapper) + V_ref = p[:refs][:V_ref] if get_connection_status(dynamic_wrapper) < 1.0 output_ode .= zero(T) return @@ -1107,20 +1106,21 @@ function device!( I_dq_cnv = ri_dq(θ_pll + pi / 2) * [Ir_cnv; Ii_cnv] #Get parameters - r_load, - c_dc, - rf, - lf, - cf, - rg, - lg, - kp_pll, - ki_pll, - kpv, - kiv, - kpc, - kic, - base_power = device_parameters + params = p[:params] + r_load = params[:r_load] + c_dc = params[:c_dc] + rf = params[:rf] + lf = params[:lf] + cf = params[:cf] + rg = params[:rg] + lg = params[:lg] + kp_pll = params[:kp_pll] + ki_pll = params[:ki_pll] + kpv = params[:kpv] + kiv = params[:kiv] + kpc = params[:kpc] + kic = params[:kic] + base_power = params[:base_power] # Compute PLL expressions V_dq_pll = ri_dq(θ_pll + pi / 2) * [Vr_filter; Vi_filter] @@ -1129,7 +1129,7 @@ function device!( # Compute DC side output Id_ref, dη_dt = pi_block(V_ref - v_dc, η, kpv, kiv) - Iq_ref = get_Q_ref(dynamic_wrapper) + Iq_ref = p[:refs][:Q_ref] # Compute AC controller expressions Vd_ref_uncomp, dγd_dt = pi_block(-Id_ref + I_dq_cnv[d], γd, kpc, kic) Vq_ref_uncomp, dγq_dt = pi_block(-Iq_ref + I_dq_cnv[q], γq, kpc, kic) diff --git a/src/models/generator_models/avr_models.jl b/src/models/generator_models/avr_models.jl index a3ba53eb6..b57d527d6 100644 --- a/src/models/generator_models/avr_models.jl +++ b/src/models/generator_models/avr_models.jl @@ -367,7 +367,7 @@ end function mdl_avr_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.SCRX, TG, P}}, h, @@ -375,7 +375,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = p[:refs][:V_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.SCRX) # @@ -392,14 +392,15 @@ function mdl_avr_ode!( #Get parameters << keep avr = PSY.get_avr(dynamic_device) - Ta_Tb = PSY.get_Ta_Tb(avr) # Ta/Tb - Tb = PSY.get_Tb(avr) + params = p[:params][:AVR] + Ta_Tb = params[:Ta_Tb] + Tb = params[:Tb] Ta = Tb * Ta_Tb - Te = PSY.get_Te(avr) - K = PSY.get_K(avr) - V_min, V_max = PSY.get_Efd_lim(avr) #Efd_lim (V_lim) - switch = PSY.get_switch(avr) # reads switch parameters - rc_rfd = PSY.get_rc_rfd(avr) + Te = params[:Te] + K = params[:K] + V_min, V_max = params[:Efd_lim] + switch = PSY.get_switch(avr) + rc_rfd = params[:rc_rfd] #Compute auxiliary parameters << keep V_in = V0_ref + Vs - V_th #sum of V @@ -571,7 +572,7 @@ end function mdl_avr_ode!( device_states::AbstractArray, output_ode::AbstractArray, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, PSY.ESST1A, TG, P}}, h, @@ -579,7 +580,7 @@ function mdl_avr_ode!( ) where {M <: PSY.Machine, S <: PSY.Shaft, TG <: PSY.TurbineGov, P <: PSY.PSS} #Obtain references - V0_ref = get_V_ref(dynamic_device) + V0_ref = p[:refs][:V_ref] #Obtain indices for component w/r to device local_ix = get_local_state_ix(dynamic_device, PSY.ESST1A) @@ -599,23 +600,27 @@ function mdl_avr_ode!( #Get parameters avr = PSY.get_avr(dynamic_device) + params = p[:params][:AVR] UEL = PSY.get_UEL_flags(avr) VOS = PSY.get_PSS_flags(avr) - Tr = PSY.get_Tr(avr) - Vi_min, Vi_max = PSY.get_Vi_lim(avr) - Tc = PSY.get_Tc(avr) - Tb = PSY.get_Tb(avr) - Tc1 = PSY.get_Tc1(avr) - Tb1 = PSY.get_Tb1(avr) - Ka = PSY.get_Ka(avr) - Ta = PSY.get_Ta(avr) - Va_min, Va_max = PSY.get_Va_lim(avr) - Vr_min, Vr_max = PSY.get_Vr_lim(avr) - Kc = PSY.get_Kc(avr) - Kf = PSY.get_Kf(avr) - Tf = PSY.get_Tf(avr) - K_lr = PSY.get_K_lr(avr) - I_lr = PSY.get_I_lr(avr) + Tr = params[:Tr] + Vi_min = params[:Vi_lim][:min] + Vi_max = params[:Vi_lim][:max] + Tc = params[:Tc] + Tb = params[:Tb] + Tc1 = params[:Tc1] + Tb1 = params[:Tb1] + Ka = params[:Ka] + Ta = params[:Ta] + Va_min = params[:Va_lim][:min] + Va_max = params[:Va_lim][:max] + Vr_min = params[:Vr_lim][:min] + Vr_max = params[:Vr_lim][:max] + Kc = params[:Kc] + Kf = params[:Kf] + Tf = params[:Tf] + K_lr = params[:K_lr] + I_lr = params[:I_lr] #Compute auxiliary parameters Itemp = K_lr * (Ifd - I_lr) diff --git a/src/models/generator_models/machine_models.jl b/src/models/generator_models/machine_models.jl index 99f64a743..ecef0cb32 100644 --- a/src/models/generator_models/machine_models.jl +++ b/src/models/generator_models/machine_models.jl @@ -408,7 +408,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -444,19 +444,18 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.AndersonFouadMachine) - internal_params = @view device_parameters[local_ix_params] - R, - Xd, - Xq, - Xd_p, - Xq_p, - Xd_pp, - Xq_pp, - Td0_p, - Tq0_p, - Td0_pp, - Tq0_pp = internal_params + params = p[:params][:Machine] + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xq_pp = params[:Xq_pp] + Td0_p = params[:Td0_p] + Tq0_p = params[:Tq0_p] + Td0_pp = params[:Td0_pp] + Tq0_pp = params[:Tq0_pp] basepower = PSY.get_base_power(dynamic_device) #RI to dq transformation @@ -495,7 +494,7 @@ Refer to Power System Modelling and Scripting by F. Milano for the equations function mdl_machine_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_r::AbstractArray{<:ACCEPTED_REAL_TYPES}, current_i::AbstractArray{<:ACCEPTED_REAL_TYPES}, @@ -527,18 +526,18 @@ function mdl_machine_ode!( Vf = inner_vars[Vf_var] #Get parameters - machine = PSY.get_machine(dynamic_device) - R = PSY.get_R(machine) - Xd = PSY.get_Xd(machine) - Xq = PSY.get_Xq(machine) - Xd_p = PSY.get_Xd_p(machine) - Xq_p = PSY.get_Xq_p(machine) - Xd_pp = PSY.get_Xd_pp(machine) - Xq_pp = PSY.get_Xq_pp(machine) - Td0_p = PSY.get_Td0_p(machine) - Tq0_p = PSY.get_Tq0_p(machine) - Td0_pp = PSY.get_Td0_pp(machine) - Tq0_pp = PSY.get_Tq0_pp(machine) + params = p[:params][:Machine] + R = params[:R] + Xd = params[:Xd] + Xq = params[:Xq] + Xd_p = params[:Xd_p] + Xq_p = params[:Xq_p] + Xd_pp = params[:Xd_pp] + Xq_pp = params[:Xq_pp] + Td0_p = params[:Td0_p] + Tq0_p = params[:Tq0_p] + Td0_pp = params[:Td0_pp] + Tq0_pp = params[:Tq0_pp] basepower = PSY.get_base_power(dynamic_device) #RI to dq transformation diff --git a/src/models/generator_models/pss_models.jl b/src/models/generator_models/pss_models.jl index 50a1f3dc7..a6f4f70b2 100644 --- a/src/models/generator_models/pss_models.jl +++ b/src/models/generator_models/pss_models.jl @@ -460,7 +460,7 @@ end function mdl_pss_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, S, A, TG, PSY.PSS2B}}, @@ -531,26 +531,27 @@ function mdl_pss_ode!( # Get Parameters M_rtf = PSY.get_M_rtf(pss) N_rtf = PSY.get_N_rtf(pss) - Tw1 = PSY.get_Tw1(pss) - Tw2 = PSY.get_Tw2(pss) - T6 = PSY.get_T6(pss) - Tw3 = PSY.get_Tw3(pss) - Tw4 = PSY.get_Tw4(pss) - T7 = PSY.get_T7(pss) - Ks2 = PSY.get_Ks2(pss) - Ks3 = PSY.get_Ks3(pss) - T8 = PSY.get_T8(pss) - T9 = PSY.get_T9(pss) - Ks1 = PSY.get_Ks1(pss) - T1 = PSY.get_T1(pss) - T2 = PSY.get_T2(pss) - T3 = PSY.get_T3(pss) - T4 = PSY.get_T4(pss) - T10 = PSY.get_T10(pss) - T11 = PSY.get_T11(pss) Vs1_min, Vs1_max = PSY.get_Vs1_lim(pss) Vs2_min, Vs2_max = PSY.get_Vs2_lim(pss) Vst_min, Vst_max = PSY.get_Vst_lim(pss) + params = p[:params][:PSS] + Tw1 = params[:Tw1] + Tw2 = params[:Tw2] + T6 = params[:T6] + Tw3 = params[:Tw3] + Tw4 = params[:Tw4] + T7 = params[:T7] + Ks2 = params[:Ks2] + Ks3 = params[:Ks3] + T8 = params[:T8] + T9 = params[:T9] + Ks1 = params[:Ks1] + T1 = params[:T1] + T2 = params[:T2] + T3 = params[:T3] + T4 = params[:T4] + T10 = params[:T10] + T11 = params[:T11] # Clamp inputs u_1 = clamp(u_1, Vs1_min, Vs1_max) diff --git a/src/models/generator_models/shaft_models.jl b/src/models/generator_models/shaft_models.jl index be8bd8f40..58b6f5cfd 100644 --- a/src/models/generator_models/shaft_models.jl +++ b/src/models/generator_models/shaft_models.jl @@ -42,7 +42,7 @@ end function mdl_shaft_ode!( device_states::AbstractArray{<:ACCEPTED_REAL_TYPES}, output_ode::AbstractArray{<:ACCEPTED_REAL_TYPES}, - device_parameters::AbstractArray{<:ACCEPTED_REAL_TYPES}, + p::AbstractArray{<:ACCEPTED_REAL_TYPES}, inner_vars::AbstractArray{<:ACCEPTED_REAL_TYPES}, ω_sys::ACCEPTED_REAL_TYPES, dynamic_device::DynamicWrapper{PSY.DynamicGenerator{M, PSY.FiveMassShaft, A, TG, P}}, @@ -72,26 +72,25 @@ function mdl_shaft_ode!( τm = inner_vars[τm_var] #Get parameters - local_ix_params = get_local_parameter_ix(dynamic_device, PSY.SingleMass) - internal_params = @view device_parameters[local_ix_params] - H, - H_hp, - H_ip, - H_lp, - H_ex, - D, - D_hp, - D_ip, - D_lp, - D_ex, - D_12, - D_23, - D_34, - D_45, - K_hp, - K_ip, - K_lp, - K_ex = internal_params + params = p[:params][:Shaft] + H = params[:H] + H_hp = params[:H_hp] + H_ip = params[:H_ip] + H_lp = params[:H_lp] + H_ex = params[:H_ex] + D = params[:D] + D_hp = params[:D_hp] + D_ip = params[:D_ip] + D_lp = params[:D_lp] + D_ex = params[:D_ex] + D_12 = params[:D_12] + D_23 = params[:D_23] + D_34 = params[:D_34] + D_45 = params[:D_45] + K_hp = params[:K_hp] + K_ip = params[:K_ip] + K_lp = params[:K_lp] + K_ex = params[:K_ex] #Compute 10 states ODEs #15.51 output_ode[local_ix[1]] = 2.0 * π * f0 * (ω - ω_sys) diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index 9c14c6e71..4846db67e 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -518,35 +518,33 @@ get_params_metadata(::PSY.MarconatoMachine) = ( γ_d = ParamsMetadata(DEVICE_PARAM, false, true), γ_q = ParamsMetadata(DEVICE_PARAM, false, true), ) -#= - -get_params(x::PSY.AndersonFouadMachine) = [ - PSY.get_R(x), - PSY.get_Xd(x), - PSY.get_Xq(x), - PSY.get_Xd_p(x), - PSY.get_Xq_p(x), - PSY.get_Xd_pp(x), - PSY.get_Xq_pp(x), - PSY.get_Td0_p(x), - PSY.get_Tq0_p(x), - PSY.get_Td0_pp(x), - PSY.get_Tq0_pp(x)] -get_params_metadata(::PSY.AndersonFouadMachine) = [ - ParamsMetadata(:R_Machine, false, false, true, false), - ParamsMetadata(:Xd_Machine, false, false, true, false), - ParamsMetadata(:Xq_Machine, false, false, true, false), - ParamsMetadata(:Xd_p_Machine, false, false, true, false), - ParamsMetadata(:Xq_p_Machine, false, false, true, false), - ParamsMetadata(:Xd_pp_Machine, false, false, true, false), - ParamsMetadata(:Xq_pp_Machine, false, false, true, false), - ParamsMetadata(:Td0_p_Machine, false, false, false, false), - ParamsMetadata(:Tq0_p_Machine, false, false, false, false), - ParamsMetadata(:Td0_pp_Machine, false, false, false, false), - ParamsMetadata(:Tq0_pp_Machine, false, false, false, false), -] +get_params(x::Union{PSY.AndersonFouadMachine, PSY.SimpleAFMachine}) = ( + R = PSY.get_R(x), + Xd = PSY.get_Xd(x), + Xq = PSY.get_Xq(x), + Xd_p = PSY.get_Xd_p(x), + Xq_p = PSY.get_Xq_p(x), + Xd_pp = PSY.get_Xd_pp(x), + Xq_pp = PSY.get_Xq_pp(x), + Td0_p = PSY.get_Td0_p(x), + Tq0_p = PSY.get_Tq0_p(x), + Td0_pp = PSY.get_Td0_pp(x), + Tq0_pp = PSY.get_Tq0_pp(x), +) +get_params_metadata(::Union{PSY.AndersonFouadMachine, PSY.SimpleAFMachine}) = ( + R = ParamsMetadata(DEVICE_PARAM, false, true), + Xd = ParamsMetadata(DEVICE_PARAM, false, true), + Xq = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_p = ParamsMetadata(DEVICE_PARAM, false, true), + Xq_p = ParamsMetadata(DEVICE_PARAM, false, true), + Xd_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Xq_pp = ParamsMetadata(DEVICE_PARAM, false, true), + Td0_p = ParamsMetadata(DEVICE_PARAM, false, false), + Tq0_p = ParamsMetadata(DEVICE_PARAM, false, false), + Td0_pp = ParamsMetadata(DEVICE_PARAM, false, false), + Tq0_pp = ParamsMetadata(DEVICE_PARAM, false, false), +) #NOTE: Saturation not considered as paramters -=# get_params( x::Union{PSY.RoundRotorMachine, PSY.RoundRotorExponential, PSY.RoundRotorQuadratic}, ) = ( @@ -627,47 +625,46 @@ get_params_metadata(::PSY.SingleMass) = ( H = ParamsMetadata(DEVICE_PARAM, false, false), D = ParamsMetadata(DEVICE_PARAM, false, false), ) - -#= get_params(x::PSY.FiveMassShaft) = [ - PSY.get_H(x), - PSY.get_H_hp(x), - PSY.get_H_ip(x), - PSY.get_H_lp(x), - PSY.get_H_ex(x), - PSY.get_D(x), - PSY.get_D_hp(x), - PSY.get_D_ip(x), - PSY.get_D_lp(x), - PSY.get_D_ex(x), - PSY.get_D_12(x), - PSY.get_D_23(x), - PSY.get_D_34(x), - PSY.get_D_45(x), - PSY.get_K_hp(x), - PSY.get_K_ip(x), - PSY.get_K_lp(x), - PSY.get_K_ex(x), -] -get_params_metadata(::PSY.FiveMassShaft) = [ - ParamsMetadata(:H_Shaft, false, false, false, false) - ParamsMetadata(:H_hp_Shaft, false, false, false, false) - ParamsMetadata(:H_ip_Shaft, false, false, false, false) - ParamsMetadata(:H_lp_Shaft, false, false, false, false) - ParamsMetadata(:H_ex_Shaft, false, false, false, false) - ParamsMetadata(:D_Shaft, false, false, true, false) - ParamsMetadata(:D_hp_Shaft, false, false, true, false) - ParamsMetadata(:D_ip_Shaft, false, false, true, false) - ParamsMetadata(:D_lp_Shaft, false, false, true, false) - ParamsMetadata(:D_ex_Shaft, false, false, true, false) - ParamsMetadata(:D_12_Shaft, false, false, true, false) - ParamsMetadata(:D_23_Shaft, false, false, true, false) - ParamsMetadata(:D_34_Shaft, false, false, true, false) - ParamsMetadata(:D_45_Shaft, false, false, true, false) - ParamsMetadata(:K_hp_Shaft, false, false, true, false) - ParamsMetadata(:K_ip_Shaft, false, false, true, false) - ParamsMetadata(:K_lp_Shaft, false, false, true, false) - ParamsMetadata(:K_ex_Shaft, false, false, true, false) -] =# +get_params(x::PSY.FiveMassShaft) = ( + H = PSY.get_H(x), + H_hp = PSY.get_H_hp(x), + H_ip = PSY.get_H_ip(x), + H_lp = PSY.get_H_lp(x), + H_ex = PSY.get_H_ex(x), + D = PSY.get_D(x), + D_hp = PSY.get_D_hp(x), + D_ip = PSY.get_D_ip(x), + D_lp = PSY.get_D_lp(x), + D_ex = PSY.get_D_ex(x), + D_12 = PSY.get_D_12(x), + D_23 = PSY.get_D_23(x), + D_34 = PSY.get_D_34(x), + D_45 = PSY.get_D_45(x), + K_hp = PSY.get_K_hp(x), + K_ip = PSY.get_K_ip(x), + K_lp = PSY.get_K_lp(x), + K_ex = PSY.get_K_ex(x), +) +get_params_metadata(::PSY.FiveMassShaft) = ( + H = ParamsMetadata(DEVICE_PARAM, false, false), + H_hp = ParamsMetadata(DEVICE_PARAM, false, false), + H_ip = ParamsMetadata(DEVICE_PARAM, false, false), + H_lp = ParamsMetadata(DEVICE_PARAM, false, false), + H_ex = ParamsMetadata(DEVICE_PARAM, false, false), + D = ParamsMetadata(DEVICE_PARAM, false, true), + D_hp = ParamsMetadata(DEVICE_PARAM, false, true), + D_ip = ParamsMetadata(DEVICE_PARAM, false, true), + D_lp = ParamsMetadata(DEVICE_PARAM, false, true), + D_ex = ParamsMetadata(DEVICE_PARAM, false, true), + D_12 = ParamsMetadata(DEVICE_PARAM, false, true), + D_23 = ParamsMetadata(DEVICE_PARAM, false, true), + D_34 = ParamsMetadata(DEVICE_PARAM, false, true), + D_45 = ParamsMetadata(DEVICE_PARAM, false, true), + K_hp = ParamsMetadata(DEVICE_PARAM, false, true), + K_ip = ParamsMetadata(DEVICE_PARAM, false, true), + K_lp = ParamsMetadata(DEVICE_PARAM, false, true), + K_ex = ParamsMetadata(DEVICE_PARAM, false, true), +) #AVRS get_params(::PSY.AVRFixed) = (;) @@ -837,6 +834,68 @@ get_params_metadata(::PSY.EXAC1) = ( Kd = ParamsMetadata(DEVICE_PARAM, false, true), Ke = ParamsMetadata(DEVICE_PARAM, false, true), ) +get_params(x::PSY.SCRX) = ( + Ta_Tb = PSY.get_Ta_Tb(x), + Tb = PSY.get_Tb(x), + K = PSY.get_K(x), + Te = PSY.get_Te(x), + Efd_lim = PSY.get_Efd_lim(x), + rc_rfd = PSY.get_rc_rfd(x), +) +get_params_metadata(::PSY.SCRX) = ( + Ta_Tb = ParamsMetadata(DEVICE_PARAM, false, true), + Tb = ParamsMetadata(DEVICE_PARAM, true, true), + K = ParamsMetadata(DEVICE_PARAM, false, true), + Te = ParamsMetadata(DEVICE_PARAM, true, false), + Efd_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, true), + max = ParamsMetadata(DEVICE_PARAM, false, true), + ), + rc_rfd = ParamsMetadata(DEVICE_PARAM, false, true), +) +get_params(x::PSY.ESST1A) = ( + Tr = PSY.get_Tr(x), + Vi_lim = (min = PSY.get_Vi_lim(x)[1], max = min = PSY.get_Vi_lim(x)[2]), + Tc = PSY.get_Tc(x), + Tb = PSY.get_Tb(x), + Tc1 = PSY.get_Tc1(x), + Tb1 = PSY.get_Tb1(x), + Ka = PSY.get_Ka(x), + Ta = PSY.get_Ta(x), + Va_lim = PSY.get_Va_lim(x), + Vr_lim = PSY.get_Vr_lim(x), + Kc = PSY.get_Kc(x), + Kf = PSY.get_Kf(x), + Tf = PSY.get_Tf(x), + K_lr = PSY.get_K_lr(x), + I_lr = PSY.get_I_lr(x), +) +get_params_metadata(::PSY.ESST1A) = ( + Tr = ParamsMetadata(DEVICE_PARAM, true, false), + Vi_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + Tc = ParamsMetadata(DEVICE_PARAM, false, true), + Tb = ParamsMetadata(DEVICE_PARAM, true, true), + Tc1 = ParamsMetadata(DEVICE_PARAM, false, true), + Tb1 = ParamsMetadata(DEVICE_PARAM, true, true), + Ka = ParamsMetadata(DEVICE_PARAM, false, true), + Ta = ParamsMetadata(DEVICE_PARAM, true, false), + Va_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, false), + max = ParamsMetadata(DEVICE_PARAM, false, false), + ), + Vr_lim = ( + min = ParamsMetadata(DEVICE_PARAM, false, true), + max = ParamsMetadata(DEVICE_PARAM, false, true), + ), + Kc = ParamsMetadata(DEVICE_PARAM, false, true), + Kf = ParamsMetadata(DEVICE_PARAM, false, true), + Tf = ParamsMetadata(DEVICE_PARAM, false, true), + K_lr = ParamsMetadata(DEVICE_PARAM, false, true), + I_lr = ParamsMetadata(DEVICE_PARAM, false, true), +) #TurbineGov get_params(x::PSY.TGFixed) = (; efficiency = PSY.get_efficiency(x)) get_params_metadata(::PSY.TGFixed) = @@ -1022,6 +1081,44 @@ get_params_metadata(::PSY.IEEEST) = ( Vcu = ParamsMetadata(DEVICE_PARAM, false, true), Vcl = ParamsMetadata(DEVICE_PARAM, false, true), ) +get_params(x::PSY.PSS2B) = ( + Tw1 = PSY.get_Tw1(x), + Tw2 = PSY.get_Tw2(x), + T6 = PSY.get_T6(x), + Tw3 = PSY.get_Tw3(x), + Tw4 = PSY.get_Tw4(x), + T7 = PSY.get_T7(x), + Ks2 = PSY.get_Ks2(x), + Ks3 = PSY.get_Ks3(x), + T8 = PSY.get_T8(x), + T9 = PSY.get_T9(x), + Ks1 = PSY.get_Ks1(x), + T1 = PSY.get_T1(x), + T2 = PSY.get_T2(x), + T3 = PSY.get_T3(x), + T4 = PSY.get_T4(x), + T10 = PSY.get_T10(x), + T11 = PSY.get_T11(x), +) +get_params_metadata(::PSY.PSS2B) = ( + Tw1 = ParamsMetadata(DEVICE_PARAM, false, true), + Tw2 = ParamsMetadata(DEVICE_PARAM, false, false), + T6 = ParamsMetadata(DEVICE_PARAM, false, false), + Tw3 = ParamsMetadata(DEVICE_PARAM, false, true), + Tw4 = ParamsMetadata(DEVICE_PARAM, false, false), + T7 = ParamsMetadata(DEVICE_PARAM, false, false), + Ks2 = ParamsMetadata(DEVICE_PARAM, false, false), + Ks3 = ParamsMetadata(DEVICE_PARAM, false, false), + T8 = ParamsMetadata(DEVICE_PARAM, false, false), + T9 = ParamsMetadata(DEVICE_PARAM, false, true), + Ks1 = ParamsMetadata(DEVICE_PARAM, false, false), + T1 = ParamsMetadata(DEVICE_PARAM, false, false), + T2 = ParamsMetadata(DEVICE_PARAM, false, false), + T3 = ParamsMetadata(DEVICE_PARAM, false, false), + T4 = ParamsMetadata(DEVICE_PARAM, false, false), + T10 = ParamsMetadata(DEVICE_PARAM, false, false), + T11 = ParamsMetadata(DEVICE_PARAM, false, false), +) #SOURCE get_params(x::PSY.Source) = ( R_th = PSY.get_R_th(x), @@ -1032,41 +1129,40 @@ get_params_metadata(::PSY.Source) = ( X_th = ParamsMetadata(DEVICE_PARAM, false, true), ) #Parameters not implemented for PeriodicVariableSource - requires change in PSY Struct to have information required to construct and deconstruct parameter vector -#= + #DYNAMIC LOADS -get_params(x::PSY.ActiveConstantPowerLoad) = [ - PSY.get_r_load(x), - PSY.get_c_dc(x), - PSY.get_rf(x), - PSY.get_lf(x), - PSY.get_cf(x), - PSY.get_rg(x), - PSY.get_lg(x), - PSY.get_kp_pll(x), - PSY.get_ki_pll(x), - PSY.get_kpv(x), - PSY.get_kiv(x), - PSY.get_kpc(x), - PSY.get_kic(x), - PSY.get_base_power(x), -] -get_params_metadata(::PSY.ActiveConstantPowerLoad) = [ - ParamsMetadata(:r_load, false, false, true, false), - ParamsMetadata(:c_dc, false, false, false, false), - ParamsMetadata(:rf, false, false, true, false), - ParamsMetadata(:lf, true, false, true, false), - ParamsMetadata(:cf, true, false, true, false), - ParamsMetadata(:rg, false, false, true, false), - ParamsMetadata(:lg, true, false, true, false), - ParamsMetadata(:kp_pll, false, false, false, false), - ParamsMetadata(:ki_pll, false, false, false, false), - ParamsMetadata(:kpv, false, false, false, false), - ParamsMetadata(:kiv, false, false, true, false), - ParamsMetadata(:kpc, false, false, false, false), - ParamsMetadata(:kic, false, false, true, false), - ParamsMetadata(:base_power, false, false, true, false), -] -=# +get_params(x::PSY.ActiveConstantPowerLoad) = ( + r_load = PSY.get_r_load(x), + c_dc = PSY.get_c_dc(x), + rf = PSY.get_rf(x), + lf = PSY.get_lf(x), + cf = PSY.get_cf(x), + rg = PSY.get_rg(x), + lg = PSY.get_lg(x), + kp_pll = PSY.get_kp_pll(x), + ki_pll = PSY.get_ki_pll(x), + kpv = PSY.get_kpv(x), + kiv = PSY.get_kiv(x), + kpc = PSY.get_kpc(x), + kic = PSY.get_kic(x), + base_power = PSY.get_base_power(x), +) +get_params_metadata(::PSY.ActiveConstantPowerLoad) = ( + r_load = ParamsMetadata(DEVICE_PARAM, false, true), + c_dc = ParamsMetadata(DEVICE_PARAM, false, false), + rf = ParamsMetadata(DEVICE_PARAM, false, true), + lf = ParamsMetadata(DEVICE_PARAM, true, true), + cf = ParamsMetadata(DEVICE_PARAM, true, true), + rg = ParamsMetadata(DEVICE_PARAM, false, true), + lg = ParamsMetadata(DEVICE_PARAM, true, true), + kp_pll = ParamsMetadata(DEVICE_PARAM, false, false), + ki_pll = ParamsMetadata(DEVICE_PARAM, false, false), + kpv = ParamsMetadata(DEVICE_PARAM, false, false), + kiv = ParamsMetadata(DEVICE_PARAM, false, true), + kpc = ParamsMetadata(DEVICE_PARAM, false, false), + kic = ParamsMetadata(DEVICE_PARAM, false, true), + base_power = ParamsMetadata(DEVICE_PARAM, false, false), +) get_params(x::PSY.SingleCageInductionMachine) = ( R_s = PSY.get_R_s(x), R_r = PSY.get_R_r(x), @@ -1200,36 +1296,33 @@ get_params_metadata(::PSY.AggregateDistributedGenerationA) = ( base_power = ParamsMetadata(DEVICE_PARAM, false, false), Pfa_ref = ParamsMetadata(DEVICE_PARAM, false, true), ) -#= -get_params(x::PSY.CSVGN1) = [ - PSY.get_K(x), - PSY.get_T1(x), - PSY.get_T2(x), - PSY.get_T3(x), - PSY.get_T4(x), - PSY.get_T5(x), - PSY.get_Rmin(x), - PSY.get_Vmax(x), - PSY.get_Vmin(x), - PSY.get_CBase(x), - PSY.get_base_power(x), - PSY.get_R_th(x), - PSY.get_X_th(x), -] -get_params_metadata(::PSY.CSVGN1) = [ - ParamsMetadata(:K, false, false, false, false), - ParamsMetadata(:T1, false, false, false, false), - ParamsMetadata(:T2, false, false, false, false), - ParamsMetadata(:T3, false, false, false, false), - ParamsMetadata(:T4, false, false, false, false), - ParamsMetadata(:T5, false, false, false, false), - ParamsMetadata(:Rmin, false, false, false, false), - ParamsMetadata(:Vmax, false, false, false, false), - ParamsMetadata(:Vmin, false, false, false, false), - ParamsMetadata(:CBase, false, false, false, false), - ParamsMetadata(:base_power, false, false, false, false), - ParamsMetadata(:R_th, false, false, false, false), - ParamsMetadata(:X_th, false, false, false, false), -] - - =# +get_params(x::PSY.CSVGN1) = ( + K = PSY.get_K(x), + T1 = PSY.get_T1(x), + T2 = PSY.get_T2(x), + T3 = PSY.get_T3(x), + T4 = PSY.get_T4(x), + T5 = PSY.get_T5(x), + Rmin = PSY.get_Rmin(x), + Vmax = PSY.get_Vmax(x), + Vmin = PSY.get_Vmin(x), + CBase = PSY.get_CBase(x), + base_power = PSY.get_base_power(x), + R_th = PSY.get_R_th(x), + X_th = PSY.get_X_th(x), +) +get_params_metadata(::PSY.CSVGN1) = ( + K = ParamsMetadata(DEVICE_PARAM, false, false), + T1 = ParamsMetadata(DEVICE_PARAM, false, false), + T2 = ParamsMetadata(DEVICE_PARAM, false, false), + T3 = ParamsMetadata(DEVICE_PARAM, false, false), + T4 = ParamsMetadata(DEVICE_PARAM, false, false), + T5 = ParamsMetadata(DEVICE_PARAM, false, false), + Rmin = ParamsMetadata(DEVICE_PARAM, false, false), + Vmax = ParamsMetadata(DEVICE_PARAM, false, false), + Vmin = ParamsMetadata(DEVICE_PARAM, false, false), + CBase = ParamsMetadata(DEVICE_PARAM, false, false), + base_power = ParamsMetadata(DEVICE_PARAM, false, false), + R_th = ParamsMetadata(DEVICE_PARAM, false, false), + X_th = ParamsMetadata(DEVICE_PARAM, false, false), +) From a3bc6827d5ee87221840d09d77adc481e6636cb3 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 10 Jul 2024 09:14:33 -0400 Subject: [PATCH 47/76] loosen types on common controls --- src/models/common_controls.jl | 737 +++++++++++++++++----------------- 1 file changed, 371 insertions(+), 366 deletions(-) diff --git a/src/models/common_controls.jl b/src/models/common_controls.jl index ff7525ea7..7e6a445ab 100644 --- a/src/models/common_controls.jl +++ b/src/models/common_controls.jl @@ -11,22 +11,22 @@ u -> │ ────────────│ -> y └─────────────┘ """ function low_pass_modified_mass_matrix( - u::Z, - y::V, + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, K::ACCEPTED_REAL_TYPES, - K_den::W, + K_den::ACCEPTED_REAL_TYPES, ::ACCEPTED_REAL_TYPES, -) where {V <: ACCEPTED_REAL_TYPES, W <: ACCEPTED_REAL_TYPES, Z <: ACCEPTED_REAL_TYPES} +) return y, K * u - K_den * y end function low_pass_modified( - u::Z, - y::V, + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, K::ACCEPTED_REAL_TYPES, - K_den::W, + K_den::ACCEPTED_REAL_TYPES, T::ACCEPTED_REAL_TYPES, -) where {V <: ACCEPTED_REAL_TYPES, W <: ACCEPTED_REAL_TYPES, Z <: ACCEPTED_REAL_TYPES} +) return y, (1.0 / T) * low_pass_modified_mass_matrix(u, y, K, K_den, T)[2] end @@ -41,20 +41,20 @@ u -> │ ────── │ -> y # Use this one if T = 0 is allowed, and let the mass matrix take care of it. function low_pass_mass_matrix( - u::Z, - y::V, - K::Float64, - T::Float64, -) where {V <: ACCEPTED_REAL_TYPES, Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, + K::ACCEPTED_REAL_TYPES, + T::ACCEPTED_REAL_TYPES, +) return low_pass_modified_mass_matrix(u, y, K, 1.0, T) end function low_pass( - u::Z, - y::V, + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, K::ACCEPTED_REAL_TYPES, T::ACCEPTED_REAL_TYPES, -) where {V <: ACCEPTED_REAL_TYPES, Z <: ACCEPTED_REAL_TYPES} +) return low_pass_modified(u, y, K, 1.0, T) end @@ -72,13 +72,13 @@ u -> │ ────── │ -> y """ function low_pass_nonwindup_mass_matrix( - u::Z, - y::V, - K::Float64, - ::Float64, - y_min::Float64, - y_max::Float64, -) where {V <: ACCEPTED_REAL_TYPES, Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, + K::ACCEPTED_REAL_TYPES, + ::ACCEPTED_REAL_TYPES, + y_min::ACCEPTED_REAL_TYPES, + y_max::ACCEPTED_REAL_TYPES, +) dydt = K * u - y y_sat = clamp(y, y_min, y_max) # Non Windup logic from IEEE Std 421.5 @@ -88,28 +88,28 @@ end # Does not accept T = 0 function low_pass_nonwindup( - u::Z, - y::V, - K::Float64, - T::Float64, - y_min::Float64, - y_max::Float64, -) where {V <: ACCEPTED_REAL_TYPES, Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, + K::ACCEPTED_REAL_TYPES, + T::ACCEPTED_REAL_TYPES, + y_min::ACCEPTED_REAL_TYPES, + y_max::ACCEPTED_REAL_TYPES, +) y_sat, dydt_scaled = low_pass_nonwindup_mass_matrix(u, y, K, T, y_min, y_max) return y_sat, (1.0 / T) * dydt_scaled end # Does not accept T = 0 function low_pass_nonwindup_ramp_limits( - u::Z, - y::V, - K::Float64, - T::Float64, - y_min::Float64, - y_max::Float64, - dy_min::Float64, - dy_max::Float64, -) where {V <: ACCEPTED_REAL_TYPES, Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, + K::ACCEPTED_REAL_TYPES, + T::ACCEPTED_REAL_TYPES, + y_min::ACCEPTED_REAL_TYPES, + y_max::ACCEPTED_REAL_TYPES, + dy_min::ACCEPTED_REAL_TYPES, + dy_max::ACCEPTED_REAL_TYPES, +) y, dydt = low_pass(u, y, K, T) y_sat = clamp(y, y_min, y_max) dydt_sat = clamp(dydt, dy_min, dy_max) @@ -131,21 +131,21 @@ Internal State: x """ function high_pass_mass_matrix( - u::Z, - x::Z, + u::ACCEPTED_REAL_TYPES, + x::ACCEPTED_REAL_TYPES, K::ACCEPTED_REAL_TYPES, T::ACCEPTED_REAL_TYPES, -) where {Z <: ACCEPTED_REAL_TYPES} +) K_T = T < eps() ? 0.0 : (K / T) return x + K_T * u, -(K_T * u + x) end function high_pass( - u::Z, - x::Z, + u::ACCEPTED_REAL_TYPES, + x::ACCEPTED_REAL_TYPES, K::ACCEPTED_REAL_TYPES, T::ACCEPTED_REAL_TYPES, -) where {Z <: ACCEPTED_REAL_TYPES} +) y, dxdt_scaled = high_pass_mass_matrix(u, x, K, T) return y, (1.0 / T) * dxdt_scaled end @@ -162,23 +162,23 @@ Internal State: x """ function lead_lag_mass_matrix( - u::Z, - x::Z, - K::Float64, - T1::Float64, - T2::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x::ACCEPTED_REAL_TYPES, + K::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, +) T1_T2 = T2 < eps() ? 0.0 : (T1 / T2) return x + (K * T1_T2) * u, K * (1 - T1_T2) * u - x end function lead_lag( - u::Z, - x::Z, - K::Float64, - T1::Float64, - T2::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x::ACCEPTED_REAL_TYPES, + K::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, +) y, dxdt_scaled = lead_lag_mass_matrix(u, x, K, T1, T2) return y, (1.0 / T2) * dxdt_scaled end @@ -195,26 +195,26 @@ Internal state: x """ function low_pass_2nd( - u::Z, - x::Z, - y::Z, - K::Float64, - T1::Float64, - T2::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, + K::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, +) dxdt = (1.0 / T2) * (K * u - T1 * x - y) dydt = x return y, dxdt, dydt end function low_pass_2nd_mass_matrix( - u::Z, - x::Z, - y::Z, - K::Float64, - T1::Float64, - T2::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, + K::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, +) dxdt = K * u - T1 * x - y dydt = x return y, dxdt, dydt @@ -232,14 +232,14 @@ Internal States: x1, x2 """ function lead_lag_2nd_mass_matrix( - u::Z, - x1::Z, - x2::Z, + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, T1::ACCEPTED_REAL_TYPES, T2::ACCEPTED_REAL_TYPES, T3::ACCEPTED_REAL_TYPES, T4::ACCEPTED_REAL_TYPES, -) where {Z <: ACCEPTED_REAL_TYPES} +) dx1dt = u - T1 * x1 - x2 dx2dt = x1 T4_T2 = T2 < eps() ? 0.0 : (T4 / T2) @@ -248,14 +248,14 @@ function lead_lag_2nd_mass_matrix( end function lead_lag_2nd( - u::Z, - x1::Z, - x2::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, +) y, dx1dt_scaled, dx2dt = lead_lag_2nd_mass_matrix(u, x1, x2, T1, T2, T3, T4) return y, (1.0 / T2) * dx1dt_scaled, dx2dt end @@ -276,16 +276,16 @@ Internal States: x1, x2 """ function lead_lag_2nd_mass_matrix_nonwindup( - u::Z, - x1::Z, - x2::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - y_min::Float64, - y_max::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + y_min::ACCEPTED_REAL_TYPES, + y_max::ACCEPTED_REAL_TYPES, +) dx1dt_scaled = u - T1 * x1 - x2 dx2dt = x1 T4_T2 = T2 < eps() ? 0.0 : (T4 / T2) @@ -296,16 +296,16 @@ function lead_lag_2nd_mass_matrix_nonwindup( end function lead_lag_2nd_nonwindup( - u::Z, - x1::Z, - x2::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - y_min::Float64, - y_max::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + y_min::ACCEPTED_REAL_TYPES, + y_max::ACCEPTED_REAL_TYPES, +) y, dx1dt_scaled, dx2dt = lead_lag_2nd_mass_matrix_nonwindup(u, x1, x2, T1, T2, T3, T4, y_min, y_max) return y, (1.0 / T2) * dx1dt_scaled, dx2dt @@ -323,17 +323,17 @@ Internal States: x1, x2, x3 """ function lead_lag_3rd_mass_matrix( - u::Z, - x1::Z, - x2::Z, - x3::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, +) dx1dt = u - T2 * x1 - T1 * x2 - x3 dx2dt = x1 dx3dt = x2 @@ -343,17 +343,17 @@ function lead_lag_3rd_mass_matrix( end function lead_lag_3rd( - u::Z, - x1::Z, - x2::Z, - x3::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, +) y, dx1dt_scaled, dx2dt, dx3dt = lead_lag_3rd_mass_matrix(u, x1, x2, x3, T1, T2, T3, T4, T5, T6) return y, (1.0 / T3) * dx1dt_scaled, dx2dt, dx3dt @@ -371,20 +371,20 @@ Internal States: x1, x2, x3, x4 """ function lead_lag_4th_mass_matrix( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, - T7::Float64, - T8::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, + T7::ACCEPTED_REAL_TYPES, + T8::ACCEPTED_REAL_TYPES, +) dx1dt = u - T3 * x1 - T2 * x2 - T1 * x3 - x4 dx2dt = x1 dx3dt = x2 @@ -400,20 +400,20 @@ function lead_lag_4th_mass_matrix( end function lead_lag_4th( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, - T7::Float64, - T8::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, + T7::ACCEPTED_REAL_TYPES, + T8::ACCEPTED_REAL_TYPES, +) y, dx1dt_scaled, dx2dt, dx3dt, dx4dt = lead_lag_4th_mass_matrix(u, x1, x2, x3, x4, T1, T2, T3, T4, T5, T6, T7, T8) return y, (1.0 / T4) * dx1dt_scaled, dx2dt, dx3dt, dx4dt @@ -431,23 +431,23 @@ Internal States: x1, x2, x3, x4, x5 """ function lead_lag_5th_mass_matrix( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - x5::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, - T7::Float64, - T8::Float64, - T9::Float64, - T10::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + x5::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, + T7::ACCEPTED_REAL_TYPES, + T8::ACCEPTED_REAL_TYPES, + T9::ACCEPTED_REAL_TYPES, + T10::ACCEPTED_REAL_TYPES, +) dx1dt = u - T4 * x1 - T3 * x2 - T2 * x3 - T1 * x4 - x5 dx2dt = x1 dx3dt = x2 @@ -465,23 +465,23 @@ function lead_lag_5th_mass_matrix( end function lead_lag_5th( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - x5::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, - T7::Float64, - T8::Float64, - T9::Float64, - T10::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + x5::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, + T7::ACCEPTED_REAL_TYPES, + T8::ACCEPTED_REAL_TYPES, + T9::ACCEPTED_REAL_TYPES, + T10::ACCEPTED_REAL_TYPES, +) y, dx1dt_scaled, dx2dt, dx3dt, dx4dt, dx5dt = lead_lag_5th_mass_matrix( u, x1, @@ -515,26 +515,26 @@ Internal States: x1, x2, x3, x4, x5, x6 """ function lead_lag_6th_mass_matrix( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - x5::Z, - x6::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, - T7::Float64, - T8::Float64, - T9::Float64, - T10::Float64, - T11::Float64, - T12::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + x5::ACCEPTED_REAL_TYPES, + x6::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, + T7::ACCEPTED_REAL_TYPES, + T8::ACCEPTED_REAL_TYPES, + T9::ACCEPTED_REAL_TYPES, + T10::ACCEPTED_REAL_TYPES, + T11::ACCEPTED_REAL_TYPES, + T12::ACCEPTED_REAL_TYPES, +) dx1dt = u - T5 * x1 - T4 * x2 - T3 * x3 - T2 * x4 - T1 * x5 - x6 dx2dt = x1 dx3dt = x2 @@ -554,26 +554,26 @@ function lead_lag_6th_mass_matrix( end function lead_lag_6th( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - x5::Z, - x6::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, - T7::Float64, - T8::Float64, - T9::Float64, - T10::Float64, - T11::Float64, - T12::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + x5::ACCEPTED_REAL_TYPES, + x6::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, + T7::ACCEPTED_REAL_TYPES, + T8::ACCEPTED_REAL_TYPES, + T9::ACCEPTED_REAL_TYPES, + T10::ACCEPTED_REAL_TYPES, + T11::ACCEPTED_REAL_TYPES, + T12::ACCEPTED_REAL_TYPES, +) y, dx1dt_scaled, dx2dt, dx3dt, dx4dt, dx5dt, dx6dt = lead_lag_6th_mass_matrix( u, x1, @@ -610,29 +610,29 @@ Internal States: x1, x2, x3, x4, x5, x6, x7 """ function lead_lag_7th_mass_matrix( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - x5::Z, - x6::Z, - x7::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, - T7::Float64, - T8::Float64, - T9::Float64, - T10::Float64, - T11::Float64, - T12::Float64, - T13::Float64, - T14::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + x5::ACCEPTED_REAL_TYPES, + x6::ACCEPTED_REAL_TYPES, + x7::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, + T7::ACCEPTED_REAL_TYPES, + T8::ACCEPTED_REAL_TYPES, + T9::ACCEPTED_REAL_TYPES, + T10::ACCEPTED_REAL_TYPES, + T11::ACCEPTED_REAL_TYPES, + T12::ACCEPTED_REAL_TYPES, + T13::ACCEPTED_REAL_TYPES, + T14::ACCEPTED_REAL_TYPES, +) dx1dt = u - T6 * x1 - T5 * x2 - T4 * x3 - T3 * x4 - T2 * x5 - T1 * x6 - x7 dx2dt = x1 dx3dt = x2 @@ -654,29 +654,29 @@ function lead_lag_7th_mass_matrix( end function lead_lag_7th( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - x5::Z, - x6::Z, - x7::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, - T7::Float64, - T8::Float64, - T9::Float64, - T10::Float64, - T11::Float64, - T12::Float64, - T13::Float64, - T14::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + x5::ACCEPTED_REAL_TYPES, + x6::ACCEPTED_REAL_TYPES, + x7::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, + T7::ACCEPTED_REAL_TYPES, + T8::ACCEPTED_REAL_TYPES, + T9::ACCEPTED_REAL_TYPES, + T10::ACCEPTED_REAL_TYPES, + T11::ACCEPTED_REAL_TYPES, + T12::ACCEPTED_REAL_TYPES, + T13::ACCEPTED_REAL_TYPES, + T14::ACCEPTED_REAL_TYPES, +) y, dx1dt_scaled, dx2dt, dx3dt, dx4dt, dx5dt, dx6dt, dx7dt = lead_lag_7th_mass_matrix( u, x1, @@ -716,32 +716,32 @@ Internal States: x1, x2, x3, x4, x5, x6, x7, x8 """ function lead_lag_8th_mass_matrix( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - x5::Z, - x6::Z, - x7::Z, - x8::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, - T7::Float64, - T8::Float64, - T9::Float64, - T10::Float64, - T11::Float64, - T12::Float64, - T13::Float64, - T14::Float64, - T15::Float64, - T16::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + x5::ACCEPTED_REAL_TYPES, + x6::ACCEPTED_REAL_TYPES, + x7::ACCEPTED_REAL_TYPES, + x8::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, + T7::ACCEPTED_REAL_TYPES, + T8::ACCEPTED_REAL_TYPES, + T9::ACCEPTED_REAL_TYPES, + T10::ACCEPTED_REAL_TYPES, + T11::ACCEPTED_REAL_TYPES, + T12::ACCEPTED_REAL_TYPES, + T13::ACCEPTED_REAL_TYPES, + T14::ACCEPTED_REAL_TYPES, + T15::ACCEPTED_REAL_TYPES, + T16::ACCEPTED_REAL_TYPES, +) dx1dt = u - T7 * x1 - T6 * x2 - T5 * x3 - T4 * x4 - T3 * x5 - T2 * x6 - T1 * x7 - x8 dx2dt = x1 dx3dt = x2 @@ -765,32 +765,32 @@ function lead_lag_8th_mass_matrix( end function lead_lag_8th( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - x5::Z, - x6::Z, - x7::Z, - x8::Z, - T1::Float64, - T2::Float64, - T3::Float64, - T4::Float64, - T5::Float64, - T6::Float64, - T7::Float64, - T8::Float64, - T9::Float64, - T10::Float64, - T11::Float64, - T12::Float64, - T13::Float64, - T14::Float64, - T15::Float64, - T16::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + x5::ACCEPTED_REAL_TYPES, + x6::ACCEPTED_REAL_TYPES, + x7::ACCEPTED_REAL_TYPES, + x8::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, + T3::ACCEPTED_REAL_TYPES, + T4::ACCEPTED_REAL_TYPES, + T5::ACCEPTED_REAL_TYPES, + T6::ACCEPTED_REAL_TYPES, + T7::ACCEPTED_REAL_TYPES, + T8::ACCEPTED_REAL_TYPES, + T9::ACCEPTED_REAL_TYPES, + T10::ACCEPTED_REAL_TYPES, + T11::ACCEPTED_REAL_TYPES, + T12::ACCEPTED_REAL_TYPES, + T13::ACCEPTED_REAL_TYPES, + T14::ACCEPTED_REAL_TYPES, + T15::ACCEPTED_REAL_TYPES, + T16::ACCEPTED_REAL_TYPES, +) y, dx1dt_scaled, dx2dt, dx3dt, dx4dt, dx5dt, dx6dt, dx7dt, dx8dt = lead_lag_8th_mass_matrix( u, @@ -847,20 +847,20 @@ Internal States: x1, x2, x3, x4, x5, x6, x7, x8 """ function ramp_tracking_filter( - u::Z, - x1::Z, - x2::Z, - x3::Z, - x4::Z, - x5::Z, - x6::Z, - x7::Z, - x8::Z, - T1::Float64, - T2::Float64, + u::ACCEPTED_REAL_TYPES, + x1::ACCEPTED_REAL_TYPES, + x2::ACCEPTED_REAL_TYPES, + x3::ACCEPTED_REAL_TYPES, + x4::ACCEPTED_REAL_TYPES, + x5::ACCEPTED_REAL_TYPES, + x6::ACCEPTED_REAL_TYPES, + x7::ACCEPTED_REAL_TYPES, + x8::ACCEPTED_REAL_TYPES, + T1::ACCEPTED_REAL_TYPES, + T2::ACCEPTED_REAL_TYPES, M::Int64, N::Int64, -) where {Z <: ACCEPTED_REAL_TYPES} +) dx1dt = 0.0 dx2dt = 0.0 dx3dt = 0.0 @@ -1499,18 +1499,23 @@ u -> │kp + ─── │ -> y Internal State: x """ -function pi_block(u::Z, x::Z, kp::Float64, ki::Float64) where {Z <: ACCEPTED_REAL_TYPES} +function pi_block( + u::ACCEPTED_REAL_TYPES, + x::ACCEPTED_REAL_TYPES, + kp::ACCEPTED_REAL_TYPES, + ki::ACCEPTED_REAL_TYPES, +) return kp * u + ki * x, u end function pi_block_nonwindup( - u::Z, - x::Z, - kp::Float64, - ki::Float64, - y_min::Float64, - y_max::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + x::ACCEPTED_REAL_TYPES, + kp::ACCEPTED_REAL_TYPES, + ki::ACCEPTED_REAL_TYPES, + y_min::ACCEPTED_REAL_TYPES, + y_max::ACCEPTED_REAL_TYPES, +) y, _ = pi_block(u, x, kp, ki) y_sat = clamp(y, y_min, y_max) binary_logic = y_min < y < y_max ? 1.0 : 0.0 @@ -1530,13 +1535,13 @@ Integrator with windup limits """ function integrator_windup_mass_matrix( - u::Z, - y::Z, + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, K::ACCEPTED_REAL_TYPES, - ::Float64, + ::ACCEPTED_REAL_TYPES, y_min::ACCEPTED_REAL_TYPES, y_max::ACCEPTED_REAL_TYPES, -) where {Z <: ACCEPTED_REAL_TYPES} +) dydt_scaled = K * u y_sat = clamp(y, y_min, y_max) return y_sat, dydt_scaled @@ -1544,13 +1549,13 @@ end # Does not accept T = 0 function integrator_windup( - u::Z, - y::Z, + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, K::ACCEPTED_REAL_TYPES, T::ACCEPTED_REAL_TYPES, y_min::ACCEPTED_REAL_TYPES, y_max::ACCEPTED_REAL_TYPES, -) where {Z <: ACCEPTED_REAL_TYPES} +) y_sat = clamp(y, y_min, y_max) return y_sat, (1.0 / T) * integrator_windup_mass_matrix(u, y, K, T, y_min, y_max)[2] end @@ -1569,13 +1574,13 @@ u -> │ ────── │ -> y """ function integrator_nonwindup_mass_matrix( - u::Z, - y::Z, - K::Float64, - ::Float64, - y_min::Float64, - y_max::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, + K::ACCEPTED_REAL_TYPES, + ::ACCEPTED_REAL_TYPES, + y_min::ACCEPTED_REAL_TYPES, + y_max::ACCEPTED_REAL_TYPES, +) dydt_scaled = K * u y_sat = clamp(y, y_min, y_max) upper_lim = (y >= y_max) && (dydt_scaled > 0) @@ -1586,13 +1591,13 @@ end # Does not accept T = 0 function integrator_nonwindup( - u::Z, - y::Z, - K::Float64, - T::Float64, - y_min::Float64, - y_max::Float64, -) where {Z <: ACCEPTED_REAL_TYPES} + u::ACCEPTED_REAL_TYPES, + y::ACCEPTED_REAL_TYPES, + K::ACCEPTED_REAL_TYPES, + T::ACCEPTED_REAL_TYPES, + y_min::ACCEPTED_REAL_TYPES, + y_max::ACCEPTED_REAL_TYPES, +) y_sat, dydt_scaled = integrator_nonwindup_mass_matrix(u, y, K, T, y_min, y_max) return y_sat, (1.0 / T) * dydt_scaled end From a29834066611b62590949b401ac9b8ae6d158762 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 10 Jul 2024 11:22:20 -0400 Subject: [PATCH 48/76] add unique_timestamps --- src/base/simulation_results.jl | 214 ++++++++++++------ src/post_processing/post_proc_generator.jl | 239 +++++++++++---------- src/post_processing/post_proc_inverter.jl | 66 +++--- src/post_processing/post_proc_loads.jl | 22 +- src/post_processing/post_proc_source.jl | 26 ++- test/test_case_OMIB.jl | 4 + 6 files changed, 337 insertions(+), 234 deletions(-) diff --git a/src/base/simulation_results.jl b/src/base/simulation_results.jl index 38bf4b5f9..0d036a0b0 100644 --- a/src/base/simulation_results.jl +++ b/src/base/simulation_results.jl @@ -36,20 +36,24 @@ Internal function to obtain as a Vector of Float64 of a specific state. It recei global index for a state. """ -function _post_proc_state_series(solution, ix::Int, dt::Nothing) - ix_t = unique(i -> solution.t[i], eachindex(solution.t)) +function _post_proc_state_series(solution, ix::Int, dt::Nothing, unique_timestamps::Bool) + if unique_timestamps + ix_t = unique(i -> solution.t[i], eachindex(solution.t)) + else + ix_t = eachindex(solution.t) + end ts = solution.t[ix_t] state = solution[ix, ix_t] return ts, state end -function _post_proc_state_series(solution, ix::Int, dt::Float64) +function _post_proc_state_series(solution, ix::Int, dt::Float64, ::Bool) ts = collect(range(0; stop = solution.t[end], step = dt)) state = solution(ts; idxs = ix) return ts, state.u end -function _post_proc_state_series(solution, ix::Int, dt::Vector{Float64}) +function _post_proc_state_series(solution, ix::Int, dt::Vector{Float64}, ::Bool) state = solution(dt; idxs = ix) return dt, state.u end @@ -61,7 +65,7 @@ containing the name of the Dynamic Device and the symbol of the state. function post_proc_state_series( res::SimulationResults, ref::Tuple{String, Symbol}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) global_state_index = get_global_index(res) if !haskey(global_state_index, ref[1]) @@ -69,7 +73,7 @@ function post_proc_state_series( error("State $(ref[2]) device $(ref[1]) not found in the system. ") end ix = get(global_state_index[ref[1]], ref[2], 0) - return _post_proc_state_series(get_solution(res), ix, dt) + return _post_proc_state_series(get_solution(res), ix, dt, unique_timestamps) end """ @@ -79,7 +83,7 @@ of the Dynamic Device. function post_proc_voltage_current_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, )::NTuple{5, Vector{Float64}} #Note: Type annotation since get_dynamic_injector is type unstable and solution is Union{Nothing, DAESol} system = get_system(res) @@ -91,12 +95,14 @@ function post_proc_voltage_current_series( error("Device $(name) not found in the system") end bus_ix = get(bus_lookup, PSY.get_number(PSY.get_bus(device)), -1) - ts, V_R, V_I = post_proc_voltage_series(solution, bus_ix, n_buses, dt) + ts, V_R, V_I = + post_proc_voltage_series(solution, bus_ix, n_buses, dt, unique_timestamps) dyn_device = PSY.get_dynamic_injector(device) if isnothing(dyn_device) - _, I_R, I_I = compute_output_current(res, device, V_R, V_I, dt) + _, I_R, I_I = compute_output_current(res, device, V_R, V_I, dt, unique_timestamps) else - _, I_R, I_I = compute_output_current(res, dyn_device, V_R, V_I, dt) + _, I_R, I_I = + compute_output_current(res, dyn_device, V_R, V_I, dt, unique_timestamps) end return ts, V_R, V_I, I_R, I_I end @@ -110,11 +116,11 @@ function post_proc_voltage_series( solution, bus_ix::Int, n_buses::Int, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) bus_ix < 0 && error("Bus number $(bus_number) not found.") - ts, V_R = _post_proc_state_series(solution, bus_ix, dt) - _, V_I = _post_proc_state_series(solution, bus_ix + n_buses, dt) + ts, V_R = _post_proc_state_series(solution, bus_ix, dt, unique_timestamps) + _, V_I = _post_proc_state_series(solution, bus_ix + n_buses, dt, unique_timestamps) return collect(ts), collect(V_R), collect(V_I) end @@ -126,9 +132,9 @@ string name of the Dynamic Injection device. function post_proc_real_current_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, _, _, I_R, _ = post_proc_voltage_current_series(res, name, dt) + ts, _, _, I_R, _ = post_proc_voltage_current_series(res, name, dt, unique_timestamps) return ts, I_R end """ @@ -139,9 +145,9 @@ string name of the Dynamic Injection device. function post_proc_imaginary_current_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, _, _, _, I_I = post_proc_voltage_current_series(res, name, dt) + ts, _, _, _, I_I = post_proc_voltage_current_series(res, name, dt, unique_timestamps) return ts, I_I end @@ -153,9 +159,10 @@ string name of the Dynamic Injection device. function post_proc_activepower_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, V_R, V_I, I_R, I_I = post_proc_voltage_current_series(res, name, dt) + ts, V_R, V_I, I_R, I_I = + post_proc_voltage_current_series(res, name, dt, unique_timestamps) return ts, V_R .* I_R + V_I .* I_I end @@ -167,9 +174,10 @@ string name of the Dynamic Injection device. function post_proc_reactivepower_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, V_R, V_I, I_R, I_I = post_proc_voltage_current_series(res, name, dt) + ts, V_R, V_I, I_R, I_I = + post_proc_voltage_current_series(res, name, dt, unique_timestamps) return ts, V_I .* I_R - V_R .* I_I end @@ -181,7 +189,7 @@ string name of the Dynamic Injection device. function post_proc_field_current_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) system = get_system(res) bus_lookup = get_bus_lookup(res) @@ -189,9 +197,10 @@ function post_proc_field_current_series( solution = res.solution device = PSY.get_component(PSY.StaticInjection, system, name) bus_ix = get(bus_lookup, PSY.get_number(PSY.get_bus(device)), -1) - ts, V_R, V_I = post_proc_voltage_series(solution, bus_ix, n_buses, dt) + ts, V_R, V_I = + post_proc_voltage_series(solution, bus_ix, n_buses, dt, unique_timestamps) dyn_device = PSY.get_dynamic_injector(device) - _, I_fd = compute_field_current(res, dyn_device, V_R, V_I, dt) + _, I_fd = compute_field_current(res, dyn_device, V_R, V_I, dt, unique_timestamps) return ts, I_fd end @@ -203,12 +212,12 @@ string name of the Dynamic Injection device. function post_proc_field_voltage_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) system = get_system(res) device = PSY.get_component(PSY.StaticInjection, system, name) dyn_device = PSY.get_dynamic_injector(device) - ts, Vf = compute_field_voltage(res, dyn_device, dt) + ts, Vf = compute_field_voltage(res, dyn_device, dt, unique_timestamps) return ts, Vf end @@ -220,12 +229,12 @@ name of the Dynamic Injection device. function post_proc_pss_output_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) system = get_system(res) device = PSY.get_component(PSY.StaticInjection, system, name) dyn_device = PSY.get_dynamic_injector(device) - ts, Vs = compute_pss_output(res, dyn_device, dt) + ts, Vs = compute_pss_output(res, dyn_device, dt, unique_timestamps) return ts, Vs end @@ -237,12 +246,12 @@ string name of the Dynamic Injection device. function post_proc_mechanical_torque_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) system = get_system(res) device = PSY.get_component(PSY.StaticInjection, system, name) dyn_device = PSY.get_dynamic_injector(device) - ts, τm = compute_mechanical_torque(res, dyn_device, dt) + ts, τm = compute_mechanical_torque(res, dyn_device, dt, unique_timestamps) return ts, τm end @@ -253,7 +262,7 @@ The current is computed through the `from` bus into the `to` bus. function post_proc_branch_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) system = get_system(res) bus_lookup = get_bus_lookup(res) @@ -267,8 +276,10 @@ function post_proc_branch_series( bus_to_number = PSY.get_number(PSY.get_to(PSY.get_arc(branch))) bus_from_ix = get(bus_lookup, bus_from_number, -1) bus_to_ix = get(bus_lookup, bus_to_number, -1) - ts, V_R_from, V_I_from = post_proc_voltage_series(solution, bus_from_ix, n_buses, dt) - _, V_R_to, V_I_to = post_proc_voltage_series(solution, bus_to_ix, n_buses, dt) + ts, V_R_from, V_I_from = + post_proc_voltage_series(solution, bus_from_ix, n_buses, dt, unique_timestamps) + _, V_R_to, V_I_to = + post_proc_voltage_series(solution, bus_to_ix, n_buses, dt, unique_timestamps) r = PSY.get_r(branch) x = PSY.get_x(branch) I_flow = ((V_R_from + V_I_from * 1im) - (V_R_to + V_I_to * 1im)) ./ (r + x * 1im) @@ -281,7 +292,7 @@ Function to compute the frequency of a Dynamic Injection component. function post_proc_frequency_series( res::SimulationResults, name::String, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) system = get_system(res) device = PSY.get_component(PSY.StaticInjection, system, name) @@ -289,7 +300,7 @@ function post_proc_frequency_series( if isnothing(dyn_device) error("Dynamic Injection $(name) not found in the system") end - ts, ω = compute_frequency(res, dyn_device, dt) + ts, ω = compute_frequency(res, dyn_device, dt, unique_timestamps) end """ @@ -307,8 +318,13 @@ Function to obtain series of states out of DAE Solution. - `res::SimulationResults` : Simulation Results object that contains the solution - `ref:Tuple{String, Symbol}` : Tuple used to identify the dynamic device, via its name, as a `String`, and the associated state as a `Symbol`. """ -function get_state_series(res::SimulationResults, ref::Tuple{String, Symbol}; dt = nothing) - return post_proc_state_series(res, ref, dt) +function get_state_series( + res::SimulationResults, + ref::Tuple{String, Symbol}; + dt = nothing, + unique_timestamps = true, +) + return post_proc_state_series(res, ref, dt, unique_timestamps) end """ @@ -324,10 +340,16 @@ Function to obtain the voltage magnitude series out of the DAE Solution. - `res::SimulationResults` : Simulation Results object that contains the solution - `bus_number::Int` : Bus number identifier """ -function get_voltage_magnitude_series(res::SimulationResults, bus_number::Int; dt = nothing) +function get_voltage_magnitude_series( + res::SimulationResults, + bus_number::Int; + dt = nothing, + unique_timestamps = true, +) n_buses = get_bus_count(res) bus_ix = get(get_bus_lookup(res), bus_number, 0) - ts, V_R, V_I = post_proc_voltage_series(res.solution, bus_ix, n_buses, dt) + ts, V_R, V_I = + post_proc_voltage_series(res.solution, bus_ix, n_buses, dt, unique_timestamps) return ts, sqrt.(V_R .^ 2 .+ V_I .^ 2) end @@ -344,10 +366,16 @@ Function to obtain the voltage angle series out of the DAE Solution. - `res::SimulationResults` : Simulation Results object that contains the solution - `bus_number::Int` : Bus number identifier """ -function get_voltage_angle_series(res::SimulationResults, bus_number::Int; dt = nothing) +function get_voltage_angle_series( + res::SimulationResults, + bus_number::Int; + dt = nothing, + unique_timestamps = true, +) n_buses = get_bus_count(res) bus_ix = get(get_bus_lookup(res), bus_number, 0) - ts, V_R, V_I = post_proc_voltage_series(res.solution, bus_ix, n_buses, dt) + ts, V_R, V_I = + post_proc_voltage_series(res.solution, bus_ix, n_buses, dt, unique_timestamps) return ts, atan.(V_I, V_R) end @@ -364,8 +392,13 @@ Function to obtain the real current time series of a Dynamic Injection series ou - `res::SimulationResults` : Simulation Results object that contains the solution - `name::String` : Name to identify the specified device """ -function get_real_current_series(res::SimulationResults, name::String; dt = nothing) - return post_proc_real_current_series(res, name, dt) +function get_real_current_series( + res::SimulationResults, + name::String; + dt = nothing, + unique_timestamps = true, +) + return post_proc_real_current_series(res, name, dt, unique_timestamps) end """ @@ -381,8 +414,13 @@ Function to obtain the imaginary current time series of a Dynamic Injection seri - `res::SimulationResults` : Simulation Results object that contains the solution - `name::String` : Name to identify the specified device """ -function get_imaginary_current_series(res::SimulationResults, name::String; dt = nothing) - return post_proc_imaginary_current_series(res, name, dt) +function get_imaginary_current_series( + res::SimulationResults, + name::String; + dt = nothing, + unique_timestamps = true, +) + return post_proc_imaginary_current_series(res, name, dt, unique_timestamps) end """ @@ -398,8 +436,13 @@ Function to obtain the active power output time series of a Dynamic Injection se - `res::SimulationResults` : Simulation Results object that contains the solution - `name::String` : Name to identify the specified device """ -function get_activepower_series(res::SimulationResults, name::String; dt = nothing) - return post_proc_activepower_series(res, name, dt) +function get_activepower_series( + res::SimulationResults, + name::String; + dt = nothing, + unique_timestamps = true, +) + return post_proc_activepower_series(res, name, dt, unique_timestamps) end """ @@ -415,8 +458,13 @@ Function to obtain the reactive power output time series of a Dynamic Injection - `res::SimulationResults` : Simulation Results object that contains the solution - `name::String` : Name to identify the specified device """ -function get_reactivepower_series(res::SimulationResults, name::String; dt = nothing) - return post_proc_reactivepower_series(res, name, dt) +function get_reactivepower_series( + res::SimulationResults, + name::String; + dt = nothing, + unique_timestamps = true, +) + return post_proc_reactivepower_series(res, name, dt, unique_timestamps) end """ @@ -432,8 +480,13 @@ Function to obtain the field current time series of a Dynamic Generator out of t - `res::SimulationResults` : Simulation Results object that contains the solution - `name::String` : Name to identify the specified device """ -function get_field_current_series(res::SimulationResults, name::String; dt = nothing) - return post_proc_field_current_series(res, name, dt) +function get_field_current_series( + res::SimulationResults, + name::String; + dt = nothing, + unique_timestamps = true, +) + return post_proc_field_current_series(res, name, dt, unique_timestamps) end """ @@ -449,8 +502,13 @@ Function to obtain the field voltage time series of a Dynamic Generator out of t - `res::SimulationResults` : Simulation Results object that contains the solution - `name::String` : Name to identify the specified device """ -function get_field_voltage_series(res::SimulationResults, name::String; dt = nothing) - return post_proc_field_voltage_series(res, name, dt) +function get_field_voltage_series( + res::SimulationResults, + name::String; + dt = nothing, + unique_timestamps = true, +) + return post_proc_field_voltage_series(res, name, dt, unique_timestamps) end """ @@ -466,8 +524,13 @@ Function to obtain the pss output time series of a Dynamic Generator out of the - `res::SimulationResults` : Simulation Results object that contains the solution - `name::String` : Name to identify the specified device """ -function get_pss_output_series(res::SimulationResults, name::String; dt = nothing) - return post_proc_pss_output_series(res, name, dt) +function get_pss_output_series( + res::SimulationResults, + name::String; + dt = nothing, + unique_timestamps = true, +) + return post_proc_pss_output_series(res, name, dt, unique_timestamps) end """ @@ -483,8 +546,13 @@ Function to obtain the mechanical torque time series of the mechanical torque ou - `res::SimulationResults` : Simulation Results object that contains the solution - `name::String` : Name to identify the specified device """ -function get_mechanical_torque_series(res::SimulationResults, name::String; dt = nothing) - return post_proc_mechanical_torque_series(res, name, dt) +function get_mechanical_torque_series( + res::SimulationResults, + name::String; + dt = nothing, + unique_timestamps = true, +) + return post_proc_mechanical_torque_series(res, name, dt, unique_timestamps) end """ @@ -499,8 +567,13 @@ Function to obtain the real current flowing through the series element of a Bran - `res::SimulationResults` : Simulation Results object that contains the solution - `name::String` : Name to identify the specified line """ -function get_real_current_branch_flow(res::SimulationResults, name::String; dt = nothing) - ts, _, _, _, _, Ir, _ = post_proc_branch_series(res, name, dt) +function get_real_current_branch_flow( + res::SimulationResults, + name::String; + dt = nothing, + unique_timestamps = true, +) + ts, _, _, _, _, Ir, _ = post_proc_branch_series(res, name, dt, unique_timestamps) return ts, Ir end @@ -519,9 +592,9 @@ Function to obtain the imaginary current flowing through the series element of a function get_imaginary_current_branch_flow( res::SimulationResults, name::String; - dt = nothing, + dt = nothing, unique_timestamps = true, ) - ts, _, _, _, _, _, Ii = post_proc_branch_series(res, name, dt) + ts, _, _, _, _, _, Ii = post_proc_branch_series(res, name, dt, unique_timestamps) return ts, Ii end @@ -548,9 +621,10 @@ function get_activepower_branch_flow( res::SimulationResults, name::String, location::Symbol; - dt = nothing, + dt = nothing, unique_timestamps = true, ) - ts, V_R_from, V_I_from, V_R_to, V_I_to, Ir, Ii = post_proc_branch_series(res, name, dt) + ts, V_R_from, V_I_from, V_R_to, V_I_to, Ir, Ii = + post_proc_branch_series(res, name, dt, unique_timestamps) if location == :from return ts, V_R_from .* Ir + V_I_from .* Ii elseif location == :to @@ -584,9 +658,10 @@ function get_reactivepower_branch_flow( res::SimulationResults, name::String, location::Symbol; - dt = nothing, + dt = nothing, unique_timestamps = true, ) - ts, V_R_from, V_I_from, V_R_to, V_I_to, Ir, Ii = post_proc_branch_series(res, name, dt) + ts, V_R_from, V_I_from, V_R_to, V_I_to, Ir, Ii = + post_proc_branch_series(res, name, dt, unique_timestamps) if location == :from return ts, V_I_from .* Ir - V_R_from .* Ii elseif location == :to @@ -610,8 +685,13 @@ Function to obtain the frequency time series of a Dynamic Injection out of the D - `res::SimulationResults` : Simulation Results object that contains the solution - `name::String` : Name to identify the specified device """ -function get_frequency_series(res::SimulationResults, name::String; dt = nothing) - return post_proc_frequency_series(res, name, dt) +function get_frequency_series( + res::SimulationResults, + name::String; + dt = nothing, + unique_timestamps = true, +) + return post_proc_frequency_series(res, name, dt, unique_timestamps) end """ diff --git a/src/post_processing/post_proc_generator.jl b/src/post_processing/post_proc_generator.jl index ceba942e2..3d9a6b119 100644 --- a/src/post_processing/post_proc_generator.jl +++ b/src/post_processing/post_proc_generator.jl @@ -27,7 +27,7 @@ function compute_output_current( dynamic_device::G, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicGenerator} #Obtain Data @@ -46,6 +46,7 @@ function compute_output_current( base_power_ratio, res, dt, + unique_timestamps, ) end @@ -59,7 +60,7 @@ function compute_output_current( dynamic_device::PSY.AggregateDistributedGenerationA, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) #Obtain Data @@ -70,18 +71,18 @@ function compute_output_current( Freq_Flag = PSY.get_Freq_Flag(dynamic_device) name = PSY.get_name(dynamic_device) if Freq_Flag == 1 - _, Pord = post_proc_state_series(res, (name, :Pord), dt) - _, dPord = post_proc_state_series(res, (name, :dPord), dt) + _, Pord = post_proc_state_series(res, (name, :Pord), dt, unique_timestamps) + _, dPord = post_proc_state_series(res, (name, :dPord), dt, unique_timestamps) Tpord = PSY.get_Tpord(dynamic_device) P_lim = PSY.get_P_lim(dynamic_device) end # Get states θ = atan.(V_I ./ V_R) - ts, Ip = post_proc_state_series(res, (name, :Ip), dt) - ts, Iq = post_proc_state_series(res, (name, :Iq), dt) - _, Mult = post_proc_state_series(res, (name, :Mult), dt) - _, Vmeas = post_proc_state_series(res, (name, :Vmeas), dt) + ts, Ip = post_proc_state_series(res, (name, :Ip), dt, unique_timestamps) + ts, Iq = post_proc_state_series(res, (name, :Iq), dt, unique_timestamps) + _, Mult = post_proc_state_series(res, (name, :Mult), dt, unique_timestamps) + _, Vmeas = post_proc_state_series(res, (name, :Vmeas), dt, unique_timestamps) Iq_neg = -Iq Ip_cmd = Ip Iq_cmd = Iq @@ -152,7 +153,7 @@ function compute_field_current( dynamic_device::G, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicGenerator} #Obtain Data @@ -160,7 +161,15 @@ function compute_field_current( #Get machine machine = PSY.get_machine(dynamic_device) - return _field_current(machine, PSY.get_name(dynamic_device), V_R, V_I, res, dt) + return _field_current( + machine, + PSY.get_name(dynamic_device), + V_R, + V_I, + res, + dt, + unique_timestamps, + ) end """ @@ -171,12 +180,12 @@ the dynamic device and bus voltage. It is dispatched for device type to compute function compute_field_voltage( res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicGenerator} #Get AVR avr = PSY.get_avr(dynamic_device) - return _field_voltage(avr, PSY.get_name(dynamic_device), res, dt) + return _field_voltage(avr, PSY.get_name(dynamic_device), res, dt, unique_timestamps) end """ @@ -187,12 +196,12 @@ the dynamic device and bus voltage. It is dispatched for device type to compute function compute_pss_output( res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicGenerator} #Get PSS pss = PSY.get_pss(dynamic_device) - return _pss_output(pss, PSY.get_name(dynamic_device), res, dt) + return _pss_output(pss, PSY.get_name(dynamic_device), res, dt, unique_timestamps) end """ @@ -203,12 +212,12 @@ the dynamic device and bus voltage. It is dispatched for device type to compute function compute_mechanical_torque( res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicGenerator} #Get TG tg = PSY.get_prime_mover(dynamic_device) - return _mechanical_torque(tg, PSY.get_name(dynamic_device), res, dt) + return _mechanical_torque(tg, PSY.get_name(dynamic_device), res, dt, unique_timestamps) end """ @@ -218,10 +227,10 @@ Function to obtain the output frequency time series of a DynamicGenerator function compute_frequency( res::SimulationResults, dyn_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicGenerator} name = PSY.get_name(dyn_device) - ts, ω = post_proc_state_series(res, (name, :ω), dt) + ts, ω = post_proc_state_series(res, (name, :ω), dt, unique_timestamps) return ts, ω end @@ -236,9 +245,9 @@ function _machine_current( V_I::Vector{Float64}, base_power_ratio::Float64, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, δ = post_proc_state_series(res, (name, :δ), dt) + ts, δ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) R = PSY.get_R(machine) Xd_p = PSY.get_Xd_p(machine) @@ -270,11 +279,11 @@ function _machine_current( V_I::Vector{Float64}, base_power_ratio::Float64, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, δ = post_proc_state_series(res, (name, :δ), dt) - _, eq_p = post_proc_state_series(res, (name, :eq_p), dt) - _, ed_p = post_proc_state_series(res, (name, :ed_p), dt) + ts, δ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) + _, eq_p = post_proc_state_series(res, (name, :eq_p), dt, unique_timestamps) + _, ed_p = post_proc_state_series(res, (name, :ed_p), dt, unique_timestamps) R = PSY.get_R(machine) Xd_p = PSY.get_Xd_p(machine) @@ -308,11 +317,11 @@ function _machine_current( V_I::Vector{Float64}, base_power_ratio::Float64, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, δ = post_proc_state_series(res, (name, :δ), dt) - _, eq_pp = post_proc_state_series(res, (name, :eq_pp), dt) - _, ed_pp = post_proc_state_series(res, (name, :ed_pp), dt) + ts, δ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) + _, eq_pp = post_proc_state_series(res, (name, :eq_pp), dt, unique_timestamps) + _, ed_pp = post_proc_state_series(res, (name, :ed_pp), dt, unique_timestamps) #Get parameters R = PSY.get_R(machine) @@ -349,13 +358,13 @@ function _machine_current( ::Vector{Float64}, base_power_ratio::Float64, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, δ = post_proc_state_series(res, (name, :δ), dt) - _, eq_pp = post_proc_state_series(res, (name, :eq_pp), dt) - _, ed_pp = post_proc_state_series(res, (name, :ed_pp), dt) - _, ψd = post_proc_state_series(res, (name, :ψd), dt) - _, ψq = post_proc_state_series(res, (name, :ψq), dt) + ts, δ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) + _, eq_pp = post_proc_state_series(res, (name, :eq_pp), dt, unique_timestamps) + _, ed_pp = post_proc_state_series(res, (name, :ed_pp), dt, unique_timestamps) + _, ψd = post_proc_state_series(res, (name, :ψd), dt, unique_timestamps) + _, ψq = post_proc_state_series(res, (name, :ψq), dt, unique_timestamps) #Get parameters Xd_pp = PSY.get_Xd_pp(machine) @@ -387,15 +396,15 @@ function _machine_current( ::Vector{Float64}, base_power_ratio::Float64, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, δ = post_proc_state_series(res, (name, :δ), dt) - _, eq_p = post_proc_state_series(res, (name, :eq_p), dt) - _, ed_p = post_proc_state_series(res, (name, :ed_p), dt) - _, ψd = post_proc_state_series(res, (name, :ψd), dt) - _, ψq = post_proc_state_series(res, (name, :ψq), dt) - _, ψd_pp = post_proc_state_series(res, (name, :ψd_pp), dt) - _, ψq_pp = post_proc_state_series(res, (name, :ψq_pp), dt) + ts, δ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) + _, eq_p = post_proc_state_series(res, (name, :eq_p), dt, unique_timestamps) + _, ed_p = post_proc_state_series(res, (name, :ed_p), dt, unique_timestamps) + _, ψd = post_proc_state_series(res, (name, :ψd), dt, unique_timestamps) + _, ψq = post_proc_state_series(res, (name, :ψq), dt, unique_timestamps) + _, ψd_pp = post_proc_state_series(res, (name, :ψd_pp), dt, unique_timestamps) + _, ψq_pp = post_proc_state_series(res, (name, :ψq_pp), dt, unique_timestamps) #Get parameters Xd_pp = PSY.get_Xd_pp(machine) @@ -429,13 +438,13 @@ function _machine_current( V_I::Vector{Float64}, base_power_ratio::Float64, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, δ = post_proc_state_series(res, (name, :δ), dt) - _, eq_p = post_proc_state_series(res, (name, :eq_p), dt) - _, ed_p = post_proc_state_series(res, (name, :ed_p), dt) - _, ψ_kd = post_proc_state_series(res, (name, :ψ_kd), dt) - _, ψ_kq = post_proc_state_series(res, (name, :ψ_kq), dt) + ts, δ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) + _, eq_p = post_proc_state_series(res, (name, :eq_p), dt, unique_timestamps) + _, ed_p = post_proc_state_series(res, (name, :ed_p), dt, unique_timestamps) + _, ψ_kd = post_proc_state_series(res, (name, :ψ_kd), dt, unique_timestamps) + _, ψ_kq = post_proc_state_series(res, (name, :ψ_kq), dt, unique_timestamps) #Get parameters R = PSY.get_R(machine) @@ -481,12 +490,12 @@ function _machine_current( V_I::Vector{Float64}, base_power_ratio::Float64, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, δ = post_proc_state_series(res, (name, :δ), dt) - _, eq_p = post_proc_state_series(res, (name, :eq_p), dt) - _, ψ_kd = post_proc_state_series(res, (name, :ψ_kd), dt) - _, ψq_pp = post_proc_state_series(res, (name, :ψq_pp), dt) + ts, δ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) + _, eq_p = post_proc_state_series(res, (name, :eq_p), dt, unique_timestamps) + _, ψ_kd = post_proc_state_series(res, (name, :ψ_kd), dt, unique_timestamps) + _, ψq_pp = post_proc_state_series(res, (name, :ψq_pp), dt, unique_timestamps) #Get parameters R = PSY.get_R(machine) @@ -526,12 +535,12 @@ function _field_current( V_R::Vector{Float64}, V_I::Vector{Float64}, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {M <: PSY.Machine} @warn( "Field current is not supported in the machine type $(M). Returning zeros." ) - ts, _ = post_proc_state_series(res, (name, :δ), dt) + ts, _ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) I_fd = zeros(length(ts)) return ts, I_fd end @@ -546,13 +555,13 @@ function _field_current( V_R::Vector{Float64}, V_I::Vector{Float64}, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {M <: Union{PSY.RoundRotorQuadratic, PSY.RoundRotorExponential}} - ts, δ = post_proc_state_series(res, (name, :δ), dt) - _, eq_p = post_proc_state_series(res, (name, :eq_p), dt) - _, ed_p = post_proc_state_series(res, (name, :ed_p), dt) - _, ψ_kd = post_proc_state_series(res, (name, :ψ_kd), dt) - _, ψ_kq = post_proc_state_series(res, (name, :ψ_kd), dt) + ts, δ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) + _, eq_p = post_proc_state_series(res, (name, :eq_p), dt, unique_timestamps) + _, ed_p = post_proc_state_series(res, (name, :ed_p), dt, unique_timestamps) + _, ψ_kd = post_proc_state_series(res, (name, :ψ_kd), dt, unique_timestamps) + _, ψ_kq = post_proc_state_series(res, (name, :ψ_kd), dt, unique_timestamps) #Get parameters R = PSY.get_R(machine) @@ -600,12 +609,12 @@ function _field_current( V_R::Vector{Float64}, V_I::Vector{Float64}, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, δ = post_proc_state_series(res, (name, :δ), dt) - _, eq_p = post_proc_state_series(res, (name, :eq_p), dt) - _, ψ_kd = post_proc_state_series(res, (name, :ψ_kd), dt) - _, ψq_pp = post_proc_state_series(res, (name, :ψq_pp), dt) + ts, δ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) + _, eq_p = post_proc_state_series(res, (name, :eq_p), dt, unique_timestamps) + _, ψ_kd = post_proc_state_series(res, (name, :ψ_kd), dt, unique_timestamps) + _, ψq_pp = post_proc_state_series(res, (name, :ψq_pp), dt, unique_timestamps) #Get parameters R = PSY.get_R(machine) @@ -647,12 +656,12 @@ function _field_current( V_R::Vector{Float64}, V_I::Vector{Float64}, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, δ = post_proc_state_series(res, (name, :δ), dt) - _, eq_p = post_proc_state_series(res, (name, :eq_p), dt) - _, ψ_kd = post_proc_state_series(res, (name, :ψ_kd), dt) - _, ψq_pp = post_proc_state_series(res, (name, :ψq_pp), dt) + ts, δ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) + _, eq_p = post_proc_state_series(res, (name, :eq_p), dt, unique_timestamps) + _, ψ_kd = post_proc_state_series(res, (name, :ψ_kd), dt, unique_timestamps) + _, ψq_pp = post_proc_state_series(res, (name, :ψq_pp), dt, unique_timestamps) #Get parameters R = PSY.get_R(machine) @@ -696,9 +705,9 @@ function _field_voltage( ::A, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {A <: PSY.AVR} - return post_proc_state_series(res, (name, :Vf), dt) + return post_proc_state_series(res, (name, :Vf), dt, unique_timestamps) end """ @@ -709,10 +718,10 @@ function _field_voltage( avr::PSY.AVRFixed, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) Vf0 = PSY.get_Vf(avr) - ts, _ = post_proc_state_series(res, (name, :δ), dt) + ts, _ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) Vf = Vf0 * ones(length(ts)) return ts, Vf end @@ -725,10 +734,10 @@ function _field_voltage( avr::Union{PSY.ESAC1A, PSY.EXAC1}, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, Ve = post_proc_state_series(res, (name, :Ve), dt) - _, Xad_Ifd = post_proc_field_current_series(res, name, dt) + ts, Ve = post_proc_state_series(res, (name, :Ve), dt, unique_timestamps) + _, Xad_Ifd = post_proc_field_current_series(res, name, dt, unique_timestamps) Kc = PSY.get_Kc(avr) I_N = Kc * Xad_Ifd ./ Ve Vf = Ve .* rectifier_function.(I_N) @@ -743,10 +752,10 @@ function _field_voltage( avr::PSY.SCRX, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, Vr2 = post_proc_state_series(res, (name, :Vr2), dt) - _, Ifd = post_proc_field_current_series(res, name, dt) + ts, Vr2 = post_proc_state_series(res, (name, :Vr2), dt, unique_timestamps) + _, Ifd = post_proc_field_current_series(res, name, dt, unique_timestamps) V_min, V_max = PSY.get_Efd_lim(avr) bus_str = split(name, "-")[2] bus_num = parse(Int, bus_str) @@ -779,16 +788,16 @@ function _field_voltage( avr::PSY.ESST1A, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) # Obtain state Va - ts, Va = post_proc_state_series(res, (name, :Va), dt) + ts, Va = post_proc_state_series(res, (name, :Va), dt, unique_timestamps) # Obtain field current - _, Ifd = post_proc_field_current_series(res, name, dt) + _, Ifd = post_proc_field_current_series(res, name, dt, unique_timestamps) # Obtain PSS output - _, Vs = post_proc_pss_output_series(res, name, dt) + _, Vs = post_proc_pss_output_series(res, name, dt, unique_timestamps) # Get parameters VOS = PSY.get_PSS_flags(avr) @@ -841,9 +850,9 @@ function _pss_output( pss::PSY.PSSFixed, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) - ts, _ = post_proc_state_series(res, (name, :δ), dt) + ts, _ = post_proc_state_series(res, (name, :δ), dt, unique_timestamps) return ts, zeros(length(ts)) end @@ -855,15 +864,15 @@ function _pss_output( pss::PSY.IEEEST, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) # Obtain states - ts, x_p2 = post_proc_state_series(res, (name, :x_p2), dt) - _, x_p3 = post_proc_state_series(res, (name, :x_p3), dt) - _, x_p4 = post_proc_state_series(res, (name, :x_p4), dt) - _, x_p5 = post_proc_state_series(res, (name, :x_p5), dt) - _, x_p6 = post_proc_state_series(res, (name, :x_p6), dt) - _, x_p7 = post_proc_state_series(res, (name, :x_p7), dt) + ts, x_p2 = post_proc_state_series(res, (name, :x_p2), dt, unique_timestamps) + _, x_p3 = post_proc_state_series(res, (name, :x_p3), dt, unique_timestamps) + _, x_p4 = post_proc_state_series(res, (name, :x_p4), dt, unique_timestamps) + _, x_p5 = post_proc_state_series(res, (name, :x_p5), dt, unique_timestamps) + _, x_p6 = post_proc_state_series(res, (name, :x_p6), dt, unique_timestamps) + _, x_p7 = post_proc_state_series(res, (name, :x_p7), dt, unique_timestamps) # Get Parameters A1 = PSY.get_A1(pss) @@ -922,10 +931,10 @@ function _mechanical_torque( tg::PSY.TGFixed, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) # TODO: This will not plot correctly when changing P_ref in a callback - ts, _ = _post_proc_state_series(res.solution, 1, dt) + ts, _ = _post_proc_state_series(res.solution, 1, dt, unique_timestamps) setpoints = get_setpoints(res) P_ref = setpoints[name]["P_ref"] efficiency = PSY.get_efficiency(tg) @@ -941,7 +950,7 @@ function _mechanical_torque( tg::PSY.TGTypeI, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) # Get params Tc = PSY.get_Tc(tg) @@ -949,9 +958,9 @@ function _mechanical_torque( T4 = PSY.get_T4(tg) T5 = PSY.get_T5(tg) # Get state results - ts, x_g1 = post_proc_state_series(res, (name, :x_g1), dt) - _, x_g2 = post_proc_state_series(res, (name, :x_g2), dt) - _, x_g3 = post_proc_state_series(res, (name, :x_g3), dt) + ts, x_g1 = post_proc_state_series(res, (name, :x_g1), dt, unique_timestamps) + _, x_g2 = post_proc_state_series(res, (name, :x_g2), dt, unique_timestamps) + _, x_g3 = post_proc_state_series(res, (name, :x_g3), dt, unique_timestamps) τm = zeros(length(ts)) for ix in 1:length(ts) y_ll, _ = lead_lag(x_g1[ix], x_g2[ix], 1.0, T3, Tc) @@ -969,7 +978,7 @@ function _mechanical_torque( tg::PSY.TGTypeII, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) # TODO: This will not plot correctly when changing P_ref in a callback # Get params @@ -980,8 +989,8 @@ function _mechanical_torque( T1 = PSY.get_T1(tg) T2 = PSY.get_T2(tg) # Get state results - ts, xg = post_proc_state_series(res, (name, :xg), dt) - _, ω = post_proc_state_series(res, (name, :ω), dt) + ts, xg = post_proc_state_series(res, (name, :xg), dt, unique_timestamps) + _, ω = post_proc_state_series(res, (name, :ω), dt, unique_timestamps) τm = zeros(length(ts)) for ix in 1:length(ts) y_ll, _ = lead_lag(inv_R * (ω_ref - ω[ix]), xg[ix], 1.0, T1, T2) @@ -998,7 +1007,7 @@ function _mechanical_torque( tg::PSY.SteamTurbineGov1, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) # TODO: This will not plot correctly when changing P_ref in a callback # Get params @@ -1011,9 +1020,9 @@ function _mechanical_torque( T3 = PSY.get_T3(tg) D_T = PSY.get_D_T(tg) # Get state results - ts, x_g1 = post_proc_state_series(res, (name, :x_g1), dt) - _, x_g2 = post_proc_state_series(res, (name, :x_g2), dt) - _, ω = post_proc_state_series(res, (name, :ω), dt) + ts, x_g1 = post_proc_state_series(res, (name, :x_g1), dt, unique_timestamps) + _, x_g2 = post_proc_state_series(res, (name, :x_g2), dt, unique_timestamps) + _, ω = post_proc_state_series(res, (name, :ω), dt, unique_timestamps) ref_in = inv_R * (P_ref .- (ω .- 1.0)) τm = zeros(length(ts)) for ix in 1:length(ts) @@ -1033,13 +1042,13 @@ function _mechanical_torque( tg::PSY.GasTG, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) # Get params D_turb = PSY.get_D_turb(tg) # Get state results - ts, x_g2 = post_proc_state_series(res, (name, :x_g2), dt) - _, ω = post_proc_state_series(res, (name, :ω), dt) + ts, x_g2 = post_proc_state_series(res, (name, :x_g2), dt, unique_timestamps) + _, ω = post_proc_state_series(res, (name, :ω), dt, unique_timestamps) P_m = x_g2 - D_turb * (ω .- 1.0) τm = P_m ./ ω return ts, τm @@ -1055,7 +1064,7 @@ function _mechanical_torque( res::SimulationResults, dt::Union{Nothing, Float64}, ) - ts, x_a3 = post_proc_state_series(res, (name, :x_a3), dt) + ts, x_a3 = post_proc_state_series(res, (name, :x_a3), dt, unique_timestamps) return ts, x_a3 end """ @@ -1066,7 +1075,7 @@ function _mechanical_torque( tg::PSY.HydroTurbineGov, name::String, res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) # Get params q_nl = PSY.get_q_nl(tg) @@ -1075,9 +1084,9 @@ function _mechanical_torque( setpoints = get_setpoints(res) ω_ref = setpoints[name]["ω_ref"] # Get state results - ts, x_g3 = post_proc_state_series(res, (name, :x_g3), dt) - _, x_g4 = post_proc_state_series(res, (name, :x_g4), dt) - _, ω = post_proc_state_series(res, (name, :ω), dt) + ts, x_g3 = post_proc_state_series(res, (name, :x_g3), dt, unique_timestamps) + _, x_g4 = post_proc_state_series(res, (name, :x_g4), dt, unique_timestamps) + _, ω = post_proc_state_series(res, (name, :ω), dt, unique_timestamps) Δω = ω .- ω_ref h = (x_g4 ./ x_g3) .^ 2 τm = ((x_g4 .- q_nl) .* h * At - D_T * Δω .* x_g3) ./ ω diff --git a/src/post_processing/post_proc_inverter.jl b/src/post_processing/post_proc_inverter.jl index e1d517417..3897e4138 100644 --- a/src/post_processing/post_proc_inverter.jl +++ b/src/post_processing/post_proc_inverter.jl @@ -8,7 +8,7 @@ function compute_output_current( dynamic_device::G, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicInverter} #Obtain Data @@ -30,6 +30,7 @@ function compute_output_current( res, dynamic_device, dt, + unique_timestamps, ) end @@ -43,7 +44,7 @@ function compute_field_current( dynamic_device::G, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicInverter} @warn( "Field current does not exist in inverters. Returning zeros." @@ -59,12 +60,12 @@ the dynamic device and bus voltage. It must return nothing since field voltage d function compute_field_voltage( res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicInverter} @warn( "Field voltage does not exist in inverters. Returning zeros." ) - _, state = _post_proc_state_series(res.solution, 1, dt) + _, state = _post_proc_state_series(res.solution, 1, dt, unique_timestamps) return (nothing, zeros(length(state))) end @@ -76,19 +77,19 @@ the dynamic device and bus voltage. It must return nothing since mechanical torq function compute_mechanical_torque( res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicInverter} @warn( "Mechanical torque is not used in inverters. Returning zeros." ) - _, state = _post_proc_state_series(res.solution, 1, dt) + _, state = _post_proc_state_series(res.solution, 1, dt, unique_timestamps) return (nothing, zeros(length(state))) end function compute_frequency( res::SimulationResults, dyn_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicInverter} outer_control = PSY.get_outer_control(dyn_device) frequency_estimator = PSY.get_freq_estimator(dyn_device) @@ -99,6 +100,7 @@ function compute_frequency( res, dyn_device, dt, + unique_timestamps, ) end @@ -112,9 +114,9 @@ function _frequency( name::String, res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {F <: PSY.FrequencyEstimator, G <: PSY.DynamicInverter} - ts, ω = post_proc_state_series(res, (name, :ω_oc), dt) + ts, ω = post_proc_state_series(res, (name, :ω_oc), dt, unique_timestamps) return ts, ω end @@ -128,11 +130,11 @@ function _frequency( name::String, res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {F <: PSY.FrequencyEstimator, G <: PSY.DynamicInverter} P_ref = PSY.get_P_ref(PSY.get_active_power_control(outer_control)) ω_ref = PSY.get_ω_ref(dynamic_device) - ts, p_oc = post_proc_state_series(res, (name, :p_oc), dt) + ts, p_oc = post_proc_state_series(res, (name, :p_oc), dt, unique_timestamps) Rp = PSY.get_Rp(outer_control.active_power_control) ω_oc = ω_ref .+ Rp .* (P_ref .- p_oc) return ts, ω_oc @@ -151,7 +153,7 @@ function _frequency( name::String, res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {F <: PSY.FrequencyEstimator, G <: PSY.DynamicInverter} p_ref = PSY.get_P_ref(PSY.get_active_power_control(outer_control)) q_ref = PSY.get_Q_ref(PSY.get_reactive_power_control(outer_control)) @@ -159,10 +161,10 @@ function _frequency( k1 = PSY.get_k1(active_power_control) ψ = PSY.get_ψ(active_power_control) γ = ψ - pi / 2 - ts, E_oc = post_proc_state_series(res, (name, :E_oc), dt) - _, p_elec_out = post_proc_activepower_series(res, name, dt) - _, q_elec_out = post_proc_reactivepower_series(res, name, dt) - ω_sys = _system_frequency_series(res, dt) + ts, E_oc = post_proc_state_series(res, (name, :E_oc), dt, unique_timestamps) + _, p_elec_out = post_proc_activepower_series(res, name, dt, unique_timestamps) + _, q_elec_out = post_proc_reactivepower_series(res, name, dt, unique_timestamps) + ω_sys = _system_frequency_series(res, dt, unique_timestamps) ω_oc = ω_sys .+ (k1 ./ E_oc .^ 2) .* @@ -180,12 +182,12 @@ function _frequency( name::String, res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicInverter} kp_pll = PSY.get_kp_pll(freq_estimator) ki_pll = PSY.get_ki_pll(freq_estimator) - ts, vpll_q = post_proc_state_series(res, (name, :vq_pll), dt) - _, ε_pll = post_proc_state_series(res, (name, :ε_pll), dt) + ts, vpll_q = post_proc_state_series(res, (name, :vq_pll), dt, unique_timestamps) + _, ε_pll = post_proc_state_series(res, (name, :ε_pll), dt, unique_timestamps) pi_output = [pi_block(x, y, kp_pll, ki_pll)[1] for (x, y) in zip(vpll_q, ε_pll)] ω_pll = pi_output .+ 1.0 #See Hug ISGT-EUROPE2018 eqn. 9 return ts, ω_pll @@ -201,13 +203,13 @@ function _frequency( name::String, res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicInverter} kp_pll = PSY.get_kp_pll(freq_estimator) ki_pll = PSY.get_ki_pll(freq_estimator) - ts, vpll_q = post_proc_state_series(res, (name, :vq_pll), dt) - _, vpll_d = post_proc_state_series(res, (name, :vd_pll), dt) - _, ε_pll = post_proc_state_series(res, (name, :ε_pll), dt) + ts, vpll_q = post_proc_state_series(res, (name, :vq_pll), dt, unique_timestamps) + _, vpll_d = post_proc_state_series(res, (name, :vd_pll), dt, unique_timestamps) + _, ε_pll = post_proc_state_series(res, (name, :ε_pll), dt, unique_timestamps) pi_output = [pi_block(x, y, kp_pll, ki_pll)[1] for (x, y) in zip(atan.(vpll_q, vpll_d), ε_pll)] ω_pll = pi_output .+ 1.0 #See Hug ISGT-EUROPE2018 eqn. 9 @@ -216,7 +218,7 @@ end function _system_frequency_series( res::SimulationResults, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) if get_global_vars_update_pointers(res)[GLOBAL_VAR_SYS_FREQ_INDEX] == 0 ω_sys = 1.0 @@ -225,7 +227,7 @@ function _system_frequency_series( get_global_index(res), get_global_vars_update_pointers(res)[GLOBAL_VAR_SYS_FREQ_INDEX], ) - ω_sys = post_proc_state_series(res, ω_sys_state, dt)[2] + ω_sys = post_proc_state_series(res, ω_sys_state, dt, unique_timestamps)[2] end return ω_sys end @@ -243,10 +245,10 @@ function _output_current( base_power_ratio::Float64, res::SimulationResults, dynamic_device::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {C <: PSY.Converter, G <: PSY.DynamicInverter} - ts, ir_filter = post_proc_state_series(res, (name, :ir_filter), dt) - ts, ii_filter = post_proc_state_series(res, (name, :ii_filter), dt) + ts, ir_filter = post_proc_state_series(res, (name, :ir_filter), dt, unique_timestamps) + ts, ii_filter = post_proc_state_series(res, (name, :ii_filter), dt, unique_timestamps) return ts, base_power_ratio * ir_filter, base_power_ratio * ii_filter end @@ -264,7 +266,7 @@ function _output_current( base_power_ratio::Float64, res::SimulationResults, ::G, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) where {G <: PSY.DynamicInverter} #Get Converter parameters @@ -287,9 +289,9 @@ function _output_current( Iq_extra = max.(K_hv * (V_t .- Vo_lim), 0.0) #Compute current - ts, Ip = post_proc_state_series(res, (name, :Ip), dt) - _, Iq = post_proc_state_series(res, (name, :Iq), dt) - _, Vmeas = post_proc_state_series(res, (name, :Vmeas), dt) + ts, Ip = post_proc_state_series(res, (name, :Ip), dt, unique_timestamps) + _, Iq = post_proc_state_series(res, (name, :Iq), dt, unique_timestamps) + _, Vmeas = post_proc_state_series(res, (name, :Vmeas), dt, unique_timestamps) Ip_sat = Ip if Lvpl_sw == 1 LVPL = get_LVPL_gain.(Vmeas, Zerox, Brkpt, Lvpl1) diff --git a/src/post_processing/post_proc_loads.jl b/src/post_processing/post_proc_loads.jl index 18b8431db..bbe6f4cb5 100644 --- a/src/post_processing/post_proc_loads.jl +++ b/src/post_processing/post_proc_loads.jl @@ -8,7 +8,7 @@ function compute_output_current( dynamic_device::PSY.SingleCageInductionMachine, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) #Obtain Data sys = get_system(res) @@ -29,10 +29,10 @@ function compute_output_current( v_ds = V_R # Read states - ts, ψ_qs = post_proc_state_series(res, (name, :ψ_qs), dt) - _, ψ_ds = post_proc_state_series(res, (name, :ψ_ds), dt) - _, ψ_qr = post_proc_state_series(res, (name, :ψ_qr), dt) - _, ψ_dr = post_proc_state_series(res, (name, :ψ_dr), dt) + ts, ψ_qs = post_proc_state_series(res, (name, :ψ_qs), dt, unique_timestamps) + _, ψ_ds = post_proc_state_series(res, (name, :ψ_ds), dt, unique_timestamps) + _, ψ_qr = post_proc_state_series(res, (name, :ψ_qr), dt, unique_timestamps) + _, ψ_dr = post_proc_state_series(res, (name, :ψ_dr), dt, unique_timestamps) #Additional Fluxes ψ_mq = X_aq * (ψ_qs / X_ls + ψ_qr / X_lr) # (4.14-15) in Krause @@ -58,7 +58,7 @@ function compute_output_current( dynamic_device::PSY.SimplifiedSingleCageInductionMachine, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) #Obtain Data sys = get_system(res) @@ -75,8 +75,8 @@ function compute_output_current( X_p = PSY.get_X_p(dynamic_device) # Read states - ts, ψ_qr = post_proc_state_series(res, (name, :ψ_qr), dt) - _, ψ_dr = post_proc_state_series(res, (name, :ψ_dr), dt) + ts, ψ_qr = post_proc_state_series(res, (name, :ψ_qr), dt, unique_timestamps) + _, ψ_dr = post_proc_state_series(res, (name, :ψ_dr), dt, unique_timestamps) # voltages in QD v_qs = V_I @@ -112,7 +112,7 @@ function compute_output_current( device::PSY.PowerLoad, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) #TODO: We should dispatch this using the ZipLoad model that we have, but that would # require to properly have access to it in the SimResults. @@ -152,7 +152,7 @@ function compute_output_current( device::PSY.ExponentialLoad, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) #TODO: We should dispatch this using the ZipLoad model that we have, but that would # require to properly have access to it in the SimResults. @@ -193,7 +193,7 @@ function compute_output_current( device::PSY.StandardLoad, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) #TODO: We should dispatch this using the ZipLoad model that we have, but that would # require to properly have access to it in the SimResults. diff --git a/src/post_processing/post_proc_source.jl b/src/post_processing/post_proc_source.jl index 7ee34d2ce..d242b8e0e 100644 --- a/src/post_processing/post_proc_source.jl +++ b/src/post_processing/post_proc_source.jl @@ -5,7 +5,7 @@ Function to obtain voltage and output currents for a source. It receives the sim function post_proc_source_voltage_current_series( res::SimulationResults, name::String, - dt = nothing, + dt = nothing, unique_timestamps = true, ) system = get_system(res) bus_lookup = get_bus_lookup(res) @@ -31,7 +31,8 @@ function post_proc_source_voltage_current_series( bus_ix = get(bus_lookup, PSY.get_number(PSY.get_bus(device)), -1) - ts, Vb_R, Vb_I = post_proc_voltage_series(solution, bus_ix, n_buses, dt) + ts, Vb_R, Vb_I = + post_proc_voltage_series(solution, bus_ix, n_buses, dt, unique_timestamps) I_R = R_th * (Vs_R .- Vb_R) / Z_sq + X_th * (Vs_I .- Vb_I) / Z_sq I_I = R_th * (Vs_I .- Vb_I) / Z_sq - X_th * (Vs_R .- Vb_R) / Z_sq @@ -44,8 +45,14 @@ Function to obtain output real current for a source. It receives the simulation the Source name and an optional argument of the time step of the results. """ -function get_source_real_current_series(res::SimulationResults, name::String, dt = nothing) - ts, _, _, I_R, _ = post_proc_source_voltage_current_series(res, name, dt) +function get_source_real_current_series( + res::SimulationResults, + name::String, + dt = nothing, + unique_timestamps = true, +) + ts, _, _, I_R, _ = + post_proc_source_voltage_current_series(res, name, dt, unique_timestamps) return ts, I_R end @@ -57,9 +64,10 @@ the Source name and an optional argument of the time step of the results. function get_source_imaginary_current_series( res::SimulationResults, name::String, - dt = nothing, + dt = nothing, unique_timestamps = true, ) - ts, _, _, _, I_I = post_proc_source_voltage_current_series(res, name, dt) + ts, _, _, _, I_I = + post_proc_source_voltage_current_series(res, name, dt, unique_timestamps) return ts, I_I end @@ -73,11 +81,11 @@ function compute_output_current( dynamic_device::PSY.PeriodicVariableSource, V_R::Vector{Float64}, V_I::Vector{Float64}, - dt::Union{Nothing, Float64, Vector{Float64}}, + dt::Union{Nothing, Float64, Vector{Float64}}, unique_timestamps::Bool, ) name = PSY.get_name(dynamic_device) - ts, Vt_internal = post_proc_state_series(res, (name, :Vt), dt) - _, θt_internal = post_proc_state_series(res, (name, :θt), dt) + ts, Vt_internal = post_proc_state_series(res, (name, :Vt), dt, unique_timestamps) + _, θt_internal = post_proc_state_series(res, (name, :θt), dt, unique_timestamps) Vr_internal = Vt_internal .* cos.(θt_internal) Vi_internal = Vt_internal .* sin.(θt_internal) diff --git a/test/test_case_OMIB.jl b/test/test_case_OMIB.jl index 8cd2c90f7..9d8582e2a 100644 --- a/test/test_case_OMIB.jl +++ b/test/test_case_OMIB.jl @@ -87,6 +87,10 @@ Ybus_change = NetworkSwitch( @test isa(power, Tuple{Vector{Float64}, Vector{Float64}}) @test isa(rpower, Tuple{Vector{Float64}, Vector{Float64}}) + series_repeat_timestamps = + get_state_series(results, ("generator-102-1", :δ); unique_timestamps = false) + @test length(δ) + 1 == length(series_repeat_timestamps[2]) + finally @info("removing test files") rm(path; force = true, recursive = true) From 8c7028f823515100e6efbab00238ec9655001948 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 11 Jul 2024 12:38:06 -0400 Subject: [PATCH 49/76] add back Zygote option with simple test --- Project.toml | 2 + src/PowerSimulationsDynamics.jl | 1 + src/base/sensitivity_analysis.jl | 65 ++++++++++-- test/test_case_enzyme.jl | 169 +++++++++++++++++++++++++++++-- 4 files changed, 220 insertions(+), 17 deletions(-) diff --git a/Project.toml b/Project.toml index ba673252f..f5936d77c 100644 --- a/Project.toml +++ b/Project.toml @@ -25,6 +25,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" +Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [compat] ChainRulesCore = "1.23" @@ -48,4 +49,5 @@ Random = "1" SciMLBase = "2" SparseArrays = "1" TimerOutputs = "~0.5" +Zygote = "0.6" julia = "^1.6" diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index ede48b2bd..a4753be18 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -90,6 +90,7 @@ Enzyme.API.runtimeActivity!(true) #Needed for "activity unstable" code: https:/ Enzyme.API.looseTypeAnalysis!(true) #Required for using component arrays with Enzyme import ChainRulesCore import ComponentArrays +import Zygote const PSY = PowerSystems const IS = InfrastructureSystems diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index c3458d543..55cdbf379 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -98,6 +98,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; f_new = SciMLBase.ODEFunction{true}( f_old.f; mass_matrix = f_old.mass_matrix, + tgrad = (dT, u, p, t) -> dT .= false, ) elseif typeof(prob_old) <: SciMLBase.DDEProblem f_new = SciMLBase.DDEFunction{true}( @@ -134,17 +135,58 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; elseif init_level == INITIALIZED @info "I.C.s not impacted by parameter change" end - h(p, t; idxs = nothing) = begin - typeof(idxs) <: Number ? x0[idxs] : x0 + if typeof(prob) <: SciMLBase.AbstractODEProblem + prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) + elseif typeof(prob) <: SciMLBase.AbstractDDEProblem + h(p, t; idxs = nothing) = begin + typeof(idxs) <: Number ? x0[idxs] : x0 + end + prob_new = SciMLBase.remake(prob; h = h, p = p_new, u0 = x0) end - prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) # TODO - Need to add h here for delays - sol = SciMLBase.solve(prob_new, solver) # TODO - wrap = Val(false) gets a different enzyme error, but ruins ODE - + sol = SciMLBase.solve(prob_new, solver) @assert length(state_ixs) == 1 #Hardcode for single state for now ix = state_ixs[1] ix_t = unique(i -> sol.t[i], eachindex(sol.t)) state = sol[ix, ix_t] + return f_loss(state, data) + end + function f_Zygote(p, x0, sys, sim_inputs, prob, data, init_level) #Make separate f_enzymes depending on init_level? + p_new = sim_inputs.parameters + p_new_buff = Zygote.Buffer(p_new) + for ix in eachindex(p_new) + p_new_buff[ix] = p_new[ix] + end + for (i, ix) in enumerate(param_ixs) + p_new_buff[ix] = p[i] + end + p_new = copy(p_new_buff) + if init_level == POWERFLOW_AND_DEVICES + @error "POWERFLOW AND DEVICES -- not yet supported" + #_initialize_powerflow_and_devices!(x0, inputs, sys) + elseif init_level == DEVICES_ONLY + @error "Reinitializing not supported with Zygote" + #_initialize_devices_only!(x0, sim_inputs) #Mutation + #_refine_initial_condition!(x0, p_new, prob) #Mutation + elseif init_level == INITIALIZED + @info "I.C.s not impacted by parameter change" + end + if typeof(prob) <: SciMLBase.AbstractODEProblem + prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) + elseif typeof(prob) <: SciMLBase.AbstractDDEProblem + h(p, t; idxs = nothing) = begin + typeof(idxs) <: Number ? x0[idxs] : x0 + end + prob_new = SciMLBase.remake(prob; h = h, p = p_new, u0 = x0) + end + sol = SciMLBase.solve(prob_new, solver) + @assert length(state_ixs) == 1 #Hardcode for single state for now + #Hack to avoid unique(i -> sol.t[i], eachindex(sol.t)) which mutates and is incompatible with Zygote: + ix_first = findfirst(x -> x == 1.0, sol.t) + ix_last = findlast(x -> x == 1.0, sol.t) + ix_t = vcat(1:ix_first, (ix_last + 1):(length(sol.t))) + ix = state_ixs[1] + state = sol[ix, ix_t] return f_loss(state, data) end function f_forward(p, data) @@ -180,7 +222,18 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; ) return dp end - f_forward, f_grad + function f_forward_zygote(p, data) + f_Zygote( + p, + x0, + sys, + deepcopy(sim.inputs_init), + prob_new, + data, + init_level, + ) + end + f_forward, f_grad, f_forward_zygote end end diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index ae3ec10d3..b69cc3a87 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -20,7 +20,7 @@ using PlotlyJS #ReverseDiffVJP and EnzymeVJP only options compatible with Hybrid DEs (DEs with callbacks) #BacksolveAdjoint prone to instabilities whenever the Lipschitz constant is sufficiently large (stiff equations, PDE discretizations, and many other contexts) #For ForwardDiffSensitivity, convert_tspan=true is needed for hybrid equations. -@testset "Test Gradients - OMIB; H" begin +@testset "Test Gradients - OMIB; H; SourceBusVoltageChange" begin path = mktempdir() try omib_sys = build_system(PSIDTestSystems, "psid_test_omib") @@ -38,7 +38,6 @@ using PlotlyJS execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) res = read_results(sim) t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) - #GET PARAMETER VALUES p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) @@ -52,7 +51,7 @@ using PlotlyJS end #GET SENSITIVITY FUNCTIONS - f_forward, f_grad = get_sensitivity_functions( + f_forward, f_grad, _ = get_sensitivity_functions( sim, [("generator-102-1", :Shaft, :H)], [("generator-102-1", :δ)], @@ -83,6 +82,87 @@ using PlotlyJS end end +@testset "Test Gradients - OMIB; H; PerturbState" begin + path = mktempdir() + try + omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + s_device = get_component(Source, omib_sys, "InfBus") + #p_branch = BranchImpedanceChange(1.0, Line, "BUS 1-BUS 2-i_1", 2) BranchPerturbations not supported + p_state = PerturbState(1.0, 5, 0.18) + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + p_state, + ) + #GET GROUND TRUTH DATA + execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ); unique_timestamps = true) #Avoid filtering of repeated timesteps + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) + + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing + function f_loss(δ, δ_gt) + #plot_traces(δ, δ_gt) + return sum(abs.(δ - δ_gt)) + end + + f_forward, f_grad, f_zygote_forward = get_sensitivity_functions( + sim, + [("generator-102-1", :Shaft, :H)], + [("generator-102-1", :δ)], + Rodas4(), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + @test f_forward(p, δ_gt) == f_zygote_forward(p, δ_gt) + @test f_forward([3.14], δ_gt) == f_zygote_forward([3.14], δ_gt) + @test f_forward([3.15], δ_gt) == f_zygote_forward([3.15], δ_gt) + + @test f_grad(p, δ_gt) == Zygote.gradient(p -> f_zygote_forward(p, δ_gt), p)[1] + + _, _, f_zygote_forward = get_sensitivity_functions( + sim, + [("generator-102-1", :Shaft, :H)], + [("generator-102-1", :δ)], + Rodas4(), + f_loss; + sensealg = ReverseDiffAdjoint(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + @test isapprox( + Zygote.gradient(p -> f_zygote_forward(p, δ_gt), p)[1][1], + 78.6312919795057, + atol = 1e-6, + ) + @test isapprox( + Zygote.gradient(p -> f_zygote_forward(p, δ_gt), [3.14])[1][1], + 53.94277234225185, + atol = 1e-6, + ) + @test isapprox( + Zygote.gradient(p -> f_zygote_forward(p, δ_gt), [3.15])[1][1], + 78.48879776368774, + atol = 1e-6, + ) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + @testset "Test Optimization - OMIB; H" begin path = mktempdir() try @@ -114,7 +194,7 @@ end end #GET SENSITIVITY FUNCTIONS - f_forward, f_grad = get_sensitivity_functions( + f_forward, f_grad, _ = get_sensitivity_functions( sim, [("generator-102-1", :Shaft, :H)], [("generator-102-1", :δ)], @@ -183,7 +263,7 @@ end end #GET SENSITIVITY FUNCTIONS - f_forward, f_grad = get_sensitivity_functions( + f_forward, f_grad, _ = get_sensitivity_functions( sim, [("generator-102-1", :Machine, :Xd_p)], [("generator-102-1", :δ)], @@ -242,9 +322,9 @@ end ) remove_component!(omib_sys, dyn_gen) add_component!(omib_sys, dyn_gen_new, gen) -end +end =# -@testset "Test Gradients - OMIB; H; Delays" begin +#= @testset "Test Gradients - OMIB; H; Delays" begin path = mktempdir() try #EnzymeRules.inactive(::typeof(Base.hasproperty), args...) = nothing # To allow wrap_sol to work? --> causes gradient to b zero; bad idea to go marking functions invalid without clear reason. @@ -299,7 +379,7 @@ end dtmax = 0.005, saveat = 0.005, ) - + # @error length(δ_gt) loss_zero = f_forward(p, δ_gt) loss_non_zero_1 = f_forward([5.2], δ_gt) loss_non_zero_2 = f_forward(p, δ_gt .* 2) @@ -309,15 +389,82 @@ end grad_zero = f_grad(p, δ_gt) grad_nonzero_1 = f_grad([3.14], δ_gt) grad_nonzero_2 = f_grad([3.15], δ_gt) - @test isapprox(grad_zero[1], 0.0, atol = 1.0) - @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) #-10 and 10 in Zygote... if the timespan and all settings are identical... - @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) + @error grad_zero + @error grad_nonzero_1 + #@test isapprox(grad_zero[1], 0.0, atol = 1.0) + #@test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) #-10 and 10 in Zygote... if the timespan and all settings are identical... + #@test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) finally @info("removing test files") rm(path; force = true, recursive = true) end end +#@testset "Test Gradients - OMIB; H; Delays, scratch implementation" begin + path = mktempdir() + #try + #EnzymeRules.inactive(::typeof(Base.hasproperty), args...) = nothing # To allow wrap_sol to work? --> causes gradient to b zero; bad idea to go marking functions invalid without clear reason. + omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + s_device = get_component(Source, omib_sys, "InfBus") + s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) + add_degov_to_omib!(omib_sys) + sim = Simulation!( + MassMatrixModel, + omib_sys, + pwd(), + (0.0, 0.4), #Inside of the delay time... + s_change, + ) + + #GET GROUND TRUTH DATA + execute!( + sim, + MethodOfSteps(Rodas5(;autodiff=false)); + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + prob_old = sim.problem + f_old = prob_old.f + f_new = SciMLBase.DDEFunction{true}( + f_old.f; + mass_matrix = f_old.mass_matrix, + ) + +#= prob_new = SciMLBase.remake( + prob_old; + f = f_new, + #tstops = [0.5], + #advance_to_tstop =true, + #initializealg = SciMLBase.NoInit(), + #callback = callbacks, + #kwargs..., + ) =# + #construct from scratch instead of remake? + prob_new = DDEProblem{true}(f_new, prob_old.u0, prob_old.h, (0.0,0.2), prob_old.p) + function f_enzyme(p, prob) + p_new = copy(prob.p) + p_new[1] = p[1] + prob_new = remake(prob; p = p_new) + sol = solve(prob_new, MethodOfSteps(Rodas5(;autodiff=false))) + return sum(sol) + end + p = [0.01] + f_enzyme(p, prob_new) + f_enzyme([0.2], prob_new) + dp = make_zero(p) + dprob_new = make_zero(prob_new) + Enzyme.autodiff(Reverse, f_enzyme, Active, Duplicated(p, dp), Duplicated(prob_new, dprob_new)) + dp + #finally + # @info("removing test files") + # rm(path; force = true, recursive = true) + #end +#end + +2+2 =# +#= #Can we get the gradient based on the I.Cs when we have a delay differential equation? #@testset "Test Gradients - OMIB; Xd_p; delays" begin path = mktempdir() From 2fca627f5a0d0919edb268f0b2ad91c0a3d2c13f Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sun, 14 Jul 2024 08:04:20 -0400 Subject: [PATCH 50/76] remove single state restriction --- src/base/sensitivity_analysis.jl | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 55cdbf379..0c6be183c 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -144,11 +144,9 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; prob_new = SciMLBase.remake(prob; h = h, p = p_new, u0 = x0) end sol = SciMLBase.solve(prob_new, solver) - @assert length(state_ixs) == 1 #Hardcode for single state for now - ix = state_ixs[1] ix_t = unique(i -> sol.t[i], eachindex(sol.t)) - state = sol[ix, ix_t] - return f_loss(state, data) + states = [sol[ix, ix_t] for ix in state_ixs] + return f_loss(states, data) end function f_Zygote(p, x0, sys, sim_inputs, prob, data, init_level) #Make separate f_enzymes depending on init_level? p_new = sim_inputs.parameters @@ -179,15 +177,12 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; prob_new = SciMLBase.remake(prob; h = h, p = p_new, u0 = x0) end sol = SciMLBase.solve(prob_new, solver) - @assert length(state_ixs) == 1 #Hardcode for single state for now #Hack to avoid unique(i -> sol.t[i], eachindex(sol.t)) which mutates and is incompatible with Zygote: ix_first = findfirst(x -> x == 1.0, sol.t) ix_last = findlast(x -> x == 1.0, sol.t) ix_t = vcat(1:ix_first, (ix_last + 1):(length(sol.t))) - - ix = state_ixs[1] - state = sol[ix, ix_t] - return f_loss(state, data) + states = [sol[ix, ix_t] for ix in state_ixs] + return f_loss(states, data) end function f_forward(p, data) f_enzyme( From f7d464aad57ced905e3ee6bb5adeca052b9810fc Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 16 Jul 2024 08:39:58 -0400 Subject: [PATCH 51/76] allow for voltage of bus in addition to device state --- src/base/sensitivity_analysis.jl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 0c6be183c..f4a07bc1c 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -49,11 +49,20 @@ function get_indices_in_state_vector(sim, state_data) global_state_index = get_global_index(res) state_ixs = Vector{Int64}(undef, length(state_data)) for (ix, ref) in enumerate(state_data) - if !haskey(global_state_index, ref[1]) - @error "$(keys(global_state_index))" + if haskey(global_state_index, ref[1]) + state_ixs[ix] = get(global_state_index[ref[1]], ref[2], 0) + elseif ref[2] ∈ [:Vr, :Vi] + bus_ix = get_lookup(get_simulation_inputs(sim))[ref[1]] + if ref[2] == :Vr + state_ixs[ix] = bus_ix + else + state_ixs[ix] = bus_ix + length(get_lookup(get_simulation_inputs(sim))) + end + else + @error "Available devices: $(keys(global_state_index))" error("State $(ref[2]) device $(ref[1]) not found in the system. ") end - state_ixs[ix] = get(global_state_index[ref[1]], ref[2], 0) + end return state_ixs end From 70592eed7a28230fc401602d770221ad1481318f Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 16 Jul 2024 08:42:36 -0400 Subject: [PATCH 52/76] extend tests for multiple states --- test/test_case_enzyme.jl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index b69cc3a87..c68a3f3d2 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -45,9 +45,9 @@ using PlotlyJS display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(δ, δ_gt) - #plot_traces(δ, δ_gt) - return sum(abs.(δ - δ_gt)) + function f_loss(states, δ_gt) + #plot_traces(states[1], δ_gt) + return sum(abs.(states[1] - δ_gt)) end #GET SENSITIVITY FUNCTIONS @@ -107,9 +107,9 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(δ, δ_gt) - #plot_traces(δ, δ_gt) - return sum(abs.(δ - δ_gt)) + function f_loss(states, δ_gt) + #plot_traces(states[1], δ_gt) + return sum(abs.(states[1] - δ_gt)) end f_forward, f_grad, f_zygote_forward = get_sensitivity_functions( @@ -188,9 +188,9 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(δ, δ_gt) - #plot_traces(δ, δ_gt) - return sum(abs.(δ - δ_gt)) + function f_loss(states, δ_gt) + #plot_traces(states[1], δ_gt) + return sum(abs.(states[1] - δ_gt)) end #GET SENSITIVITY FUNCTIONS @@ -257,9 +257,9 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(δ, δ_gt) - #plot_traces(δ, δ_gt) - return sum(abs.(δ - δ_gt)) + function f_loss(states, δ_gt) + #plot_traces(states[1], δ_gt) + return sum(abs.(states[1] - δ_gt)) end #GET SENSITIVITY FUNCTIONS From 0426bcf4387c05126cbdc0b77b7c6a95b51fa071 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 16 Jul 2024 10:13:16 -0400 Subject: [PATCH 53/76] add option for All parameters at once --- src/base/sensitivity_analysis.jl | 41 +++-- test/test_case_enzyme.jl | 264 +++++++++++++++---------------- 2 files changed, 158 insertions(+), 147 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index f4a07bc1c..9bca08674 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -23,7 +23,7 @@ function get_required_initialization_level(p_metadata, param_ixs) @error "The parameter given is unsupported because it is a device setpoint." return nothing end - if metadata_entry.in_mass_matrix === DEVICE_SETPOINT + if metadata_entry.in_mass_matrix === true @error "The parameter given is not yet supported because it appears in the mass matrix" return nothing end @@ -55,21 +55,21 @@ function get_indices_in_state_vector(sim, state_data) bus_ix = get_lookup(get_simulation_inputs(sim))[ref[1]] if ref[2] == :Vr state_ixs[ix] = bus_ix - else + else state_ixs[ix] = bus_ix + length(get_lookup(get_simulation_inputs(sim))) - end - else + end + else @error "Available devices: $(keys(global_state_index))" error("State $(ref[2]) device $(ref[1]) not found in the system. ") end - end return state_ixs end function get_parameter_values(sim, device_param_pairs) p = sim.inputs.parameters - ixs = get_indices_in_parameter_vector(p, device_param_pairs) + p_metadata = sim.inputs.parameters_metadata + ixs, _ = get_ix_and_level(p, p_metadata, device_param_pairs) if ixs === nothing return nothing else @@ -77,12 +77,35 @@ function get_parameter_values(sim, device_param_pairs) end end -function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; kwargs...) - p_metadata = sim.inputs.parameters_metadata - p = sim.inputs.parameters +function get_ix_and_level(p, p_metadata, param_data) param_ixs = get_indices_in_parameter_vector(p, param_data) metadata_ixs = get_indices_in_parameter_vector(p_metadata, param_data) init_level = get_required_initialization_level(p_metadata, metadata_ixs) + return param_ixs, init_level +end + +function get_ix_and_level(p, p_metadata, param_data::Symbol) + @assert param_data == :All + @warn "Device setpoints and network parameters not yet supported; returning all supported parameters." + param_ixs = Int64[] + @assert ComponentArrays.labels(p) == ComponentArrays.labels(p_metadata) + for label in ComponentArrays.labels(p) + ix_metadata = ComponentArrays.label2index(p_metadata, label) + ix_param = ComponentArrays.label2index(p_metadata, label)[1] + metadata_entry = p_metadata[ix_metadata][1] + + if (metadata_entry.type === DEVICE_PARAM) && + (metadata_entry.in_mass_matrix === false) + push!(param_ixs, ix_param) + end + end + return param_ixs, DEVICES_ONLY +end + +function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; kwargs...) + p_metadata = sim.inputs.parameters_metadata + p = sim.inputs.parameters + param_ixs, init_level = get_ix_and_level(p, p_metadata, param_data) if init_level === nothing return nothing end diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index c68a3f3d2..b5663b836 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -82,6 +82,64 @@ using PlotlyJS end end +@testset "Test Gradients - OMIB; All; SourceBusVoltageChange" begin + path = mktempdir() + try + omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + s_device = get_component(Source, omib_sys, "InfBus") + s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + + #GET GROUND TRUTH DATA + execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + #GET PARAMETER VALUES + p = get_parameter_values(sim, :All) + + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing + function f_loss(states, δ_gt) + #plot_traces(states[1], δ_gt) + return sum(abs.(states[1] - δ_gt)) + end + + #GET SENSITIVITY FUNCTIONS + f_forward, f_grad, _ = get_sensitivity_functions( + sim, + :All, + [("generator-102-1", :δ)], + Rodas4(), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + + loss_zero = f_forward(p, δ_gt) + loss_non_zero_1 = f_forward(p .* 1.01, δ_gt) + + @test isapprox(loss_zero, 0.0, atol = 1e-9) + @test isapprox(loss_non_zero_1, 1.49, atol = 1e-3) + + grad_zero = f_grad(p, δ_gt) + @test isapprox(sum(grad_zero), -2.915264e6, atol = 1.0) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + @testset "Test Gradients - OMIB; H; PerturbState" begin path = mktempdir() try @@ -293,10 +351,10 @@ end rm(path; force = true, recursive = true) end end - +#= #BELOW HERE: TESTS FOR SENSITIVITY OF DDES -#= function add_degov_to_omib!(omib_sys) +function add_degov_to_omib!(omib_sys) gen = get_component(ThermalStandard, omib_sys, "generator-102-1") dyn_gen = get_component(DynamicGenerator, omib_sys, "generator-102-1") new_gov = PSY.DEGOV(; @@ -322,9 +380,9 @@ end ) remove_component!(omib_sys, dyn_gen) add_component!(omib_sys, dyn_gen_new, gen) -end =# +end -#= @testset "Test Gradients - OMIB; H; Delays" begin + @testset "Test Gradients - OMIB; H; Delays" begin path = mktempdir() try #EnzymeRules.inactive(::typeof(Base.hasproperty), args...) = nothing # To allow wrap_sol to work? --> causes gradient to b zero; bad idea to go marking functions invalid without clear reason. @@ -336,7 +394,7 @@ end =# MassMatrixModel, omib_sys, pwd(), - (0.0, 0.4), #Inside of the delay time... + (0.0, 5.0), #Inside of the delay time... s_change, ) @@ -359,181 +417,111 @@ end =# display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(δ, δ_gt) - plot_traces(δ, δ_gt) - return sum(abs.(δ - δ_gt)) + function f_loss(states, δ_gt) + #plot_traces(δ, δ_gt) + return sum(abs.(states[1] - δ_gt)) end #GET SENSITIVITY FUNCTIONS - f_forward, f_grad = get_sensitivity_functions( + f_forward, f_grad, _ = get_sensitivity_functions( sim, [("generator-102-1", :Shaft, :H)], [("generator-102-1", :δ)], - MethodOfSteps(Rodas5(; autodiff = false)), + MethodOfSteps(Rodas4()), #; autodiff = false #MethodOfSteps(QNDF(;autodiff=true)), f_loss; - # wrap = Val(false), #error related to wrapping of solution? sensealg = ForwardDiffSensitivity(), - abstol = 1e-2, # 1e-6 - reltol = 1e-2, # 1e-6 - dtmax = 0.005, - saveat = 0.005, + abstol = 1e-6, # 1e-6 + reltol = 1e-6, # 1e-6 + # dtmax = 0.005, + saveat = 0.005, ) # @error length(δ_gt) loss_zero = f_forward(p, δ_gt) loss_non_zero_1 = f_forward([5.2], δ_gt) loss_non_zero_2 = f_forward(p, δ_gt .* 2) - @test isapprox(loss_zero, 0.0, atol = 3e-9) + @test isapprox(loss_zero, 0.0, atol = 3e-3) @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 grad_zero = f_grad(p, δ_gt) - grad_nonzero_1 = f_grad([3.14], δ_gt) - grad_nonzero_2 = f_grad([3.15], δ_gt) @error grad_zero - @error grad_nonzero_1 - #@test isapprox(grad_zero[1], 0.0, atol = 1.0) - #@test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) #-10 and 10 in Zygote... if the timespan and all settings are identical... - #@test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) + @test isapprox(grad_zero[1], 0.0, atol = 1e-12) finally @info("removing test files") rm(path; force = true, recursive = true) end end -#@testset "Test Gradients - OMIB; H; Delays, scratch implementation" begin +#Potential Rank Deficient Matrix Detected: Erorrs... +@testset "Test Gradients - OMIB; Xd_p; delays" begin path = mktempdir() - #try - #EnzymeRules.inactive(::typeof(Base.hasproperty), args...) = nothing # To allow wrap_sol to work? --> causes gradient to b zero; bad idea to go marking functions invalid without clear reason. + try omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + add_degov_to_omib!(omib_sys) s_device = get_component(Source, omib_sys, "InfBus") s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) - add_degov_to_omib!(omib_sys) sim = Simulation!( MassMatrixModel, omib_sys, - pwd(), - (0.0, 0.4), #Inside of the delay time... - s_change, + path, + (0.0, 0.05), + #s_change, ) #GET GROUND TRUTH DATA execute!( sim, - MethodOfSteps(Rodas5(;autodiff=false)); + MethodOfSteps(Rodas4()); abstol = 1e-9, reltol = 1e-9, - dtmax = 0.005, + #dtmax = 0.005, saveat = 0.005, ) - prob_old = sim.problem - f_old = prob_old.f - f_new = SciMLBase.DDEFunction{true}( - f_old.f; - mass_matrix = f_old.mass_matrix, + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-102-1", :Machine, :Xd_p)]) + + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing + function f_loss(states, δ_gt) + #plot_traces(δ, δ_gt) + return sum(abs.(states[1] - δ_gt)) + end + + #GET SENSITIVITY FUNCTIONS + f_forward, f_grad = get_sensitivity_functions( + sim, + [("generator-102-1", :Machine, :Xd_p)], + [("generator-102-1", :δ)], + MethodOfSteps(Rodas4()), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-6, + reltol = 1e-6, + # dtmax = 0.005, + saveat = 0.005, ) -#= prob_new = SciMLBase.remake( - prob_old; - f = f_new, - #tstops = [0.5], - #advance_to_tstop =true, - #initializealg = SciMLBase.NoInit(), - #callback = callbacks, - #kwargs..., - ) =# - #construct from scratch instead of remake? - prob_new = DDEProblem{true}(f_new, prob_old.u0, prob_old.h, (0.0,0.2), prob_old.p) - function f_enzyme(p, prob) - p_new = copy(prob.p) - p_new[1] = p[1] - prob_new = remake(prob; p = p_new) - sol = solve(prob_new, MethodOfSteps(Rodas5(;autodiff=false))) - return sum(sol) - end - p = [0.01] - f_enzyme(p, prob_new) - f_enzyme([0.2], prob_new) - dp = make_zero(p) - dprob_new = make_zero(prob_new) - Enzyme.autodiff(Reverse, f_enzyme, Active, Duplicated(p, dp), Duplicated(prob_new, dprob_new)) - dp - #finally - # @info("removing test files") - # rm(path; force = true, recursive = true) - #end -#end - -2+2 =# -#= -#Can we get the gradient based on the I.Cs when we have a delay differential equation? -#@testset "Test Gradients - OMIB; Xd_p; delays" begin -path = mktempdir() -#try -omib_sys = build_system(PSIDTestSystems, "psid_test_omib") -add_degov_to_omib!(omib_sys) -s_device = get_component(Source, omib_sys, "InfBus") -s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) -sim = Simulation!( - MassMatrixModel, - omib_sys, - path, - (0.0, 5.0), - #s_change, -) - -#GET GROUND TRUTH DATA -execute!( - sim, - MethodOfSteps(Rodas4()); - abstol = 1e-9, - reltol = 1e-9, - dtmax = 0.005, - saveat = 0.005, -) -res = read_results(sim) -t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) - -#GET PARAMETER VALUES -p = get_parameter_values(sim, [("generator-102-1", :Machine, :Xd_p)]) - -function plot_traces(δ, δ_gt) - display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) -end -EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing -function f_loss(δ, δ_gt) - plot_traces(δ, δ_gt) - return sum(abs.(δ - δ_gt)) + loss_zero = f_forward(p, δ_gt) + #loss_non_zero_1 = f_forward(p * 1.01, δ_gt) + #loss_non_zero_2 = f_forward(p * 0.99, δ_gt) + #@test isapprox(loss_zero, 0.0, atol = 1e-9) + #@test loss_non_zero_1 != 0.0 + #@test loss_non_zero_2 != 0.0 + #grad_zero = f_grad(p, δ_gt) + #grad_nonzero_1 = f_grad(p * 1.01, δ_gt) + #grad_nonzero_2 = f_grad(p * 0.99, δ_gt) + #@test isapprox(grad_zero[1], 497, atol = 1.0) + #@test isapprox(grad_nonzero_1[1], 499.0, atol = 1.0) + #@test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end end -#GET SENSITIVITY FUNCTIONS -f_forward, f_grad = get_sensitivity_functions( - sim, - [("generator-102-1", :Machine, :Xd_p)], - [("generator-102-1", :δ)], - MethodOfSteps(Rodas4()), - f_loss; - sensealg = ForwardDiffSensitivity(), - abstol = 1e-6, - reltol = 1e-6, - dtmax = 0.005, - saveat = 0.005, -) - -loss_zero = f_forward(p, δ_gt) -loss_non_zero_1 = f_forward(p * 1.01, δ_gt) -loss_non_zero_2 = f_forward(p * 0.99, δ_gt) -@test isapprox(loss_zero, 0.0, atol = 1e-9) -@test loss_non_zero_1 != 0.0 -@test loss_non_zero_2 != 0.0 -grad_zero = f_grad(p, δ_gt) -grad_nonzero_1 = f_grad(p * 1.01, δ_gt) -grad_nonzero_2 = f_grad(p * 0.99, δ_gt) -@test isapprox(grad_zero[1], 497, atol = 1.0) -@test isapprox(grad_nonzero_1[1], 499.0, atol = 1.0) -@test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) -#finally -# @info("removing test files") -# rm(path; force = true, recursive = true) -#end -#end =# From b1bd1331dbf22c517dd9aa261a4972f2bf74d4bb Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 17 Jul 2024 18:27:44 -0400 Subject: [PATCH 54/76] add SciMLSensitivity and sensealg for nl problem --- Project.toml | 2 ++ src/PowerSimulationsDynamics.jl | 1 + src/base/nlsolve_wrapper.jl | 2 ++ src/initialization/generator_components/init_avr.jl | 7 +++++++ src/initialization/generator_components/init_machine.jl | 9 +++++++++ src/initialization/generator_components/init_shaft.jl | 1 + src/initialization/generator_components/init_tg.jl | 5 +++++ src/initialization/init_device.jl | 5 +++++ src/initialization/inverter_components/init_filter.jl | 1 + .../inverter_components/init_frequency_estimator.jl | 2 ++ src/initialization/inverter_components/init_inner.jl | 2 ++ 11 files changed, 37 insertions(+) diff --git a/Project.toml b/Project.toml index f5936d77c..52fd8289f 100644 --- a/Project.toml +++ b/Project.toml @@ -23,6 +23,7 @@ PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd" PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" @@ -47,6 +48,7 @@ PowerSystems = "^3.1.2" PrettyTables = "1, 2" Random = "1" SciMLBase = "2" +SciMLSensitivity = "7.0" SparseArrays = "1" TimerOutputs = "~0.5" Zygote = "0.6" diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index a4753be18..892111190 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -68,6 +68,7 @@ export get_sensitivity_functions import Logging import InfrastructureSystems import SciMLBase +import SciMLSensitivity import DataStructures: OrderedDict import DataFrames: DataFrame import Random diff --git a/src/base/nlsolve_wrapper.jl b/src/base/nlsolve_wrapper.jl index 437280468..b5dafddfc 100644 --- a/src/base/nlsolve_wrapper.jl +++ b/src/base/nlsolve_wrapper.jl @@ -48,6 +48,7 @@ function _nlsolve_call( sol = NonlinearSolve.solve( prob, solver; + sensealg = SciMLSensitivity.SteadyStateAdjoint(), abstol = f_tolerance, reltol = f_tolerance, maxiters = MAX_NLSOLVE_INTERATIONS, @@ -147,6 +148,7 @@ function _refine_initial_condition!(x0, p, prob) sol = NonlinearSolve.solve( probnl, solver; + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, maxiters = MAX_NLSOLVE_INTERATIONS, diff --git a/src/initialization/generator_components/init_avr.jl b/src/initialization/generator_components/init_avr.jl index 9b784e6f0..93901a3ca 100644 --- a/src/initialization/generator_components/init_avr.jl +++ b/src/initialization/generator_components/init_avr.jl @@ -79,6 +79,7 @@ function initialize_avr!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -157,6 +158,7 @@ function initialize_avr!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -230,6 +232,7 @@ function initialize_avr!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -290,6 +293,7 @@ function initialize_avr!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -350,6 +354,7 @@ function initialize_avr!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -444,6 +449,7 @@ function initialize_avr!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -564,6 +570,7 @@ function initialize_avr!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index 6c2d51fdd..2465a81fc 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -50,6 +50,7 @@ function initialize_mach_shaft!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -141,6 +142,7 @@ function initialize_mach_shaft!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -253,6 +255,7 @@ function initialize_mach_shaft!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -369,6 +372,7 @@ function initialize_mach_shaft!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -586,6 +590,7 @@ function initialize_mach_shaft!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -696,6 +701,7 @@ function initialize_mach_shaft!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -868,6 +874,7 @@ function initialize_mach_shaft!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -1016,6 +1023,7 @@ function initialize_mach_shaft!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -1170,6 +1178,7 @@ function initialize_mach_shaft!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) diff --git a/src/initialization/generator_components/init_shaft.jl b/src/initialization/generator_components/init_shaft.jl index 3b00beca5..4ae1fafc0 100644 --- a/src/initialization/generator_components/init_shaft.jl +++ b/src/initialization/generator_components/init_shaft.jl @@ -78,6 +78,7 @@ function initialize_shaft!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index df3140b12..443bb152c 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -71,6 +71,7 @@ function initialize_tg!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -129,6 +130,7 @@ function initialize_tg!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -189,6 +191,7 @@ function initialize_tg!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -279,6 +282,7 @@ function initialize_tg!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -356,6 +360,7 @@ function initialize_tg!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) diff --git a/src/initialization/init_device.jl b/src/initialization/init_device.jl index 1ed9b896b..8c3729d5e 100644 --- a/src/initialization/init_device.jl +++ b/src/initialization/init_device.jl @@ -89,6 +89,7 @@ function initialize_static_device!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -143,6 +144,7 @@ function initialize_dynamic_device!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -296,6 +298,7 @@ function initialize_dynamic_device!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -410,6 +413,7 @@ function initialize_dynamic_device!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -564,6 +568,7 @@ function initialize_dynamic_device!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) diff --git a/src/initialization/inverter_components/init_filter.jl b/src/initialization/inverter_components/init_filter.jl index 0976ca5eb..c50d8cc9e 100644 --- a/src/initialization/inverter_components/init_filter.jl +++ b/src/initialization/inverter_components/init_filter.jl @@ -62,6 +62,7 @@ function initialize_filter!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) diff --git a/src/initialization/inverter_components/init_frequency_estimator.jl b/src/initialization/inverter_components/init_frequency_estimator.jl index ffc712f42..1f53109a7 100644 --- a/src/initialization/inverter_components/init_frequency_estimator.jl +++ b/src/initialization/inverter_components/init_frequency_estimator.jl @@ -47,6 +47,7 @@ function initialize_frequency_estimator!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -117,6 +118,7 @@ function initialize_frequency_estimator!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) diff --git a/src/initialization/inverter_components/init_inner.jl b/src/initialization/inverter_components/init_inner.jl index 9310f8004..4bcad80c4 100644 --- a/src/initialization/inverter_components/init_inner.jl +++ b/src/initialization/inverter_components/init_inner.jl @@ -104,6 +104,7 @@ function initialize_inner!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) @@ -216,6 +217,7 @@ function initialize_inner!( sol = NonlinearSolve.solve( prob, NonlinearSolve.TrustRegion(); + sensealg = SciMLSensitivity.SteadyStateAdjoint(), reltol = STRICT_NLSOLVE_F_TOLERANCE, abstol = STRICT_NLSOLVE_F_TOLERANCE, ) From d01b094e86577d5224aed7df1dfd28c315bdff44 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 18 Jul 2024 11:16:21 -0400 Subject: [PATCH 55/76] remove sneaky closures in init --- src/initialization/generator_components/init_machine.jl | 4 +++- src/initialization/generator_components/init_tg.jl | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/initialization/generator_components/init_machine.jl b/src/initialization/generator_components/init_machine.jl index 2465a81fc..b580447be 100644 --- a/src/initialization/generator_components/init_machine.jl +++ b/src/initialization/generator_components/init_machine.jl @@ -231,6 +231,7 @@ function initialize_mach_shaft!( γ_q1 = params[:γ_q1] γ_d2 = params[:γ_d2] γ_q2 = params[:γ_q2] + ω0 = 1.0 V_dq = ri_dq(δ) * [V_R; V_I] i_d = (1.0 / Xd_pp) * (γ_d1 * eq_p - ψd + (1 - γ_d1) * ψd_pp) #15.15 @@ -350,7 +351,7 @@ function initialize_mach_shaft!( T_AA = params[:T_AA] γd = params[:γd] γq = params[:γq] - + ω0 = 1.0 V_dq = ri_dq(δ) * [V_R; V_I] i_d = (1.0 / Xd_pp) * (eq_pp - ψd) #15.18 i_q = (1.0 / Xq_pp) * (-ed_pp - ψq) #15.18 @@ -568,6 +569,7 @@ function initialize_mach_shaft!( Xq_p = params[:Xq_p] Xd_pp = params[:Xd_pp] Xq_pp = params[:Xq_pp] + ω0 = 1.0 V_dq = ri_dq(δ) * [V_R; V_I] i_d = (1.0 / Xd_pp) * (eq_pp - ψd) #15.18 diff --git a/src/initialization/generator_components/init_tg.jl b/src/initialization/generator_components/init_tg.jl index 443bb152c..a671ede4b 100644 --- a/src/initialization/generator_components/init_tg.jl +++ b/src/initialization/generator_components/init_tg.jl @@ -52,6 +52,7 @@ function initialize_tg!( T3 = params[:T3] T4 = params[:T4] T5 = params[:T5] + ω0 = 1.0 #Compute auxiliary parameters inv_R = R < eps() ? 0.0 : (1.0 / R) P_in = P_ref + inv_R * (ω_ref - ω0) From 38046e520d0569c3349be99058edee928794625c Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 18 Jul 2024 11:16:39 -0400 Subject: [PATCH 56/76] don't do full system nl solve --- src/base/sensitivity_analysis.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 9bca08674..f4cd64496 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -163,7 +163,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; elseif init_level == DEVICES_ONLY @info "Reinitializing devices only" _initialize_devices_only!(x0, sim_inputs) - _refine_initial_condition!(x0, p_new, prob) + #_refine_initial_condition!(x0, p_new, prob) #Only re-initialize devices; not full system refinement elseif init_level == INITIALIZED @info "I.C.s not impacted by parameter change" end @@ -195,8 +195,8 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; #_initialize_powerflow_and_devices!(x0, inputs, sys) elseif init_level == DEVICES_ONLY @error "Reinitializing not supported with Zygote" - #_initialize_devices_only!(x0, sim_inputs) #Mutation - #_refine_initial_condition!(x0, p_new, prob) #Mutation + _initialize_devices_only!(x0, sim_inputs) #Mutation + #_refine_initial_condition!(x0, p_new, prob) #Only re-initialize devices; not full system refinement elseif init_level == INITIALIZED @info "I.C.s not impacted by parameter change" end @@ -264,6 +264,6 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; end end -#Inactive Rules +#Inactive Rules; potential path to improving API #Enzyme.EnzymeRules.inactive(::typeof(SimulationResults), args...) = nothing #Enzyme.EnzymeRules.inactive(::typeof(get_activepower_branch_flow), args...) = nothing From d02f6db8a9c5347c68737dfbaf13fec698d30bb7 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 18 Jul 2024 11:17:02 -0400 Subject: [PATCH 57/76] add test for 9 bus and change values due to removing full system init --- test/test_case_enzyme.jl | 97 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index b5663b836..c25c98269 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -133,7 +133,7 @@ end @test isapprox(loss_non_zero_1, 1.49, atol = 1e-3) grad_zero = f_grad(p, δ_gt) - @test isapprox(sum(grad_zero), -2.915264e6, atol = 1.0) + @test isapprox(sum(grad_zero), 523.5340704294135, atol = 1.0) finally @info("removing test files") rm(path; force = true, recursive = true) @@ -343,7 +343,7 @@ end grad_zero = f_grad(p, δ_gt) grad_nonzero_1 = f_grad(p * 1.01, δ_gt) grad_nonzero_2 = f_grad(p * 0.99, δ_gt) - @test isapprox(grad_zero[1], -4.0, atol = 1.0) + @test isapprox(grad_zero[1], 498.0, atol = 1.0) @test isapprox(grad_nonzero_1[1], 499.0, atol = 1.0) @test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) finally @@ -351,6 +351,99 @@ end rm(path; force = true, recursive = true) end end + +function transform_power_load_to_constant_impedance(x::PowerLoad) + l = StandardLoad(; + name = get_name(x), + available = get_available(x), + bus = get_bus(x), + base_power = get_base_power(x), + constant_active_power = 0.0, + constant_reactive_power = 0.0, + impedance_active_power = get_active_power(x), + impedance_reactive_power = get_reactive_power(x), + current_active_power = 0.0, + current_reactive_power = 0.0, + max_constant_active_power = 0.0, + max_constant_reactive_power = 0.0, + max_impedance_active_power = get_max_active_power(x), + max_impedance_reactive_power = get_max_reactive_power(x), + max_current_active_power = 0.0, + max_current_reactive_power = 0.0, + services = get_services(x), + dynamic_injector = get_dynamic_injector(x), + ) + return l +end +using PlotlyJS +@time @testset "Test Gradients - 9 bus; Xd_p" begin + path = mktempdir() + try + sys = build_system(PSIDTestSystems, "psid_test_ieee_9bus") + for l in get_components(PowerLoad, sys) + l_new = transform_power_load_to_constant_impedance(l) + remove_component!(sys, l) + add_component!(sys, l_new) + end + dyn_gen = get_component(DynamicGenerator, sys, "generator-3-1") + get_machine(dyn_gen) + sim = Simulation!( + MassMatrixModel, + sys, + path, + (0.0, 5.0), + ControlReferenceChange(1.0, dyn_gen, :P_ref, 0.5), + ) + + #GET GROUND TRUTH DATA + execute!(sim, Rodas4(); abstol = 1e-6, reltol = 1e-6, dtmax = 0.05, saveat = 0.05) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-3-1", :δ)) + + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-3-1", :Machine, :Xd_p)]) + + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing + function f_loss(states, δ_gt) + #plot_traces(states[1], δ_gt) + return sum(abs.(states[1] - δ_gt)) + end + + #GET SENSITIVITY FUNCTIONS + f_forward, f_grad, _ = get_sensitivity_functions( + sim, + [("generator-3-1", :Machine, :Xd_p)], + [("generator-3-1", :δ)], + Rodas4(), + f_loss; + sensealg = InterpolatingAdjoint(; autojacvec = ReverseDiffVJP()), + abstol = 1e-6, + reltol = 1e-6, + dtmax = 0.05, + saveat = 0.05, + ) + + loss_zero = f_forward(p, δ_gt) + loss_non_zero_1 = f_forward(p * 1.01, δ_gt) + loss_non_zero_2 = f_forward(p * 0.99, δ_gt) + @test isapprox(loss_zero, 0.0, atol = 2e-9) + @test loss_non_zero_1 != 0.0 + @test loss_non_zero_2 != 0.0 + grad_zero = f_grad(p, δ_gt) + grad_nonzero_1 = f_grad(p * 1.01, δ_gt) + grad_nonzero_2 = f_grad(p * 0.99, δ_gt) + @test isapprox(grad_zero[1], 0.8876855633591412, atol = 1e-6) + @test isapprox(grad_nonzero_1[1], 0.5946989856464833, atol = 1.0) + @test isapprox(grad_nonzero_2[1], -0.9432527319604077; atol = 1.0) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + #= #BELOW HERE: TESTS FOR SENSITIVITY OF DDES From 4dd4dc0e38f0a92c75054d312deb4a46a2258785 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 18 Jul 2024 11:51:01 -0400 Subject: [PATCH 58/76] add test that should pass with new cb api --- test/test_case_enzyme.jl | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index c25c98269..cae746533 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -82,6 +82,68 @@ using PlotlyJS end end +@testset "Test Gradients - OMIB; H; SourceBusVoltageChange; InterpolatingAdjoint" begin + path = mktempdir() + try + omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + s_device = get_component(Source, omib_sys, "InfBus") + s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + + #GET GROUND TRUTH DATA + execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) + + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing + function f_loss(states, δ_gt) + #plot_traces(states[1], δ_gt) + return sum(abs.(states[1] - δ_gt)) + end + + #GET SENSITIVITY FUNCTIONS + f_forward, f_grad, _ = get_sensitivity_functions( + sim, + [("generator-102-1", :Shaft, :H)], + [("generator-102-1", :δ)], + Rodas4(), + f_loss; + sensealg = InterpolatingAdjoint(; autojacvec = ReverseDiffVJP()), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + + loss_zero = f_forward(p, δ_gt) + loss_non_zero_1 = f_forward([3.2], δ_gt) + loss_non_zero_2 = f_forward(p, δ_gt .* 2) + @test loss_zero == 0.0 + @test loss_non_zero_1 != 0.0 + @test loss_non_zero_2 != 0.0 + grad_zero = f_grad(p, δ_gt) + grad_nonzero_1 = f_grad([3.14], δ_gt) + grad_nonzero_2 = f_grad([3.15], δ_gt) + @test isapprox(grad_zero[1], -1.0, atol = 1.0) + @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) + @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + @testset "Test Gradients - OMIB; All; SourceBusVoltageChange" begin path = mktempdir() try From 04e9d9e0f7a99ebe61f416fb0b7205f61643773b Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 18 Jul 2024 11:57:31 -0400 Subject: [PATCH 59/76] test actual forward values --- test/test_case_enzyme.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index cae746533..17f326f71 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -130,8 +130,8 @@ end loss_non_zero_1 = f_forward([3.2], δ_gt) loss_non_zero_2 = f_forward(p, δ_gt .* 2) @test loss_zero == 0.0 - @test loss_non_zero_1 != 0.0 - @test loss_non_zero_2 != 0.0 + @test loss_non_zero_1 == 0.36199910927656687 + @test loss_non_zero_2 == 172.66293171283323 grad_zero = f_grad(p, δ_gt) grad_nonzero_1 = f_grad([3.14], δ_gt) grad_nonzero_2 = f_grad([3.15], δ_gt) From 41a5f24c66574b000b4902d679affc66aefa07bc Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Fri, 19 Jul 2024 17:49:19 -0400 Subject: [PATCH 60/76] take cb as input; fix bug from callbacks in problem with custom Enzyme rule --- Project.toml | 2 + src/PowerSimulationsDynamics.jl | 2 + src/base/sensitivity_analysis.jl | 73 +++++++----- src/base/sensitivity_rule.jl | 105 +++++++++++++++++ test/test_case_enzyme.jl | 193 ++++++++++++++++++++++--------- 5 files changed, 296 insertions(+), 79 deletions(-) create mode 100644 src/base/sensitivity_rule.jl diff --git a/Project.toml b/Project.toml index 52fd8289f..f43979415 100644 --- a/Project.toml +++ b/Project.toml @@ -8,6 +8,7 @@ ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" FastClosures = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" @@ -33,6 +34,7 @@ ChainRulesCore = "1.23" ComponentArrays = "0.15" DataFrames = "1" DataStructures = "~0.18" +DiffEqBase = "6.151" DocStringExtensions = "~0.9" Enzyme = "0.12" FastClosures = "^0.3" diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index 892111190..22a95179a 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -71,6 +71,7 @@ import SciMLBase import SciMLSensitivity import DataStructures: OrderedDict import DataFrames: DataFrame +import DiffEqBase import Random import ForwardDiff import SparseArrays @@ -192,6 +193,7 @@ include("post_processing/post_proc_loads.jl") include("post_processing/post_proc_source.jl") #Sensitivity Analysis +include("base/sensitivity_rule.jl") #Custom rule to support duplicated kwargs for callbacks. See: https://github.com/EnzymeAD/Enzyme.jl/issues/1491 include("base/sensitivity_analysis.jl") #Utils diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index f4cd64496..e608bcde3 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -102,6 +102,20 @@ function get_ix_and_level(p, p_metadata, param_data::Symbol) return param_ixs, DEVICES_ONLY end +function convert_perturbations_to_callbacks(sys, sim_inputs, perturbations) + perturbations_count = length(perturbations) + cb = Vector{SciMLBase.DiscreteCallback}(undef, perturbations_count) + tstops = Float64[] + for (ix, pert) in enumerate(perturbations) + condition = (x, t, integrator) -> t in [pert.time] + affect = get_affect(sim_inputs, sys, pert) + cb[ix] = SciMLBase.DiscreteCallback(condition, affect) + push!(tstops, pert.time) + end + callbacks = SciMLBase.CallbackSet((), tuple(cb...)) + return callbacks, tstops +end + function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; kwargs...) p_metadata = sim.inputs.parameters_metadata p = sim.inputs.parameters @@ -111,18 +125,6 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; end state_ixs = get_indices_in_state_vector(sim, state_data) sim_inputs = deepcopy(sim.inputs_init) - if get(kwargs, :auto_abstol, false) - cb = AutoAbstol(true, get(kwargs, :abstol, 1e-9)) - callbacks = - SciMLBase.CallbackSet((), tuple(push!(sim.callbacks, cb)...)) - else - callbacks = SciMLBase.CallbackSet((), tuple(sim.callbacks...)) - end - tstops = if !isempty(sim.tstops) - [sim.tstops[1] ÷ 2, sim.tstops...] #Note: Don't need to make a tuple because it is in ODEproblem. not a kwarg - else - [] - end prob_old = sim.problem f_old = prob_old.f @@ -143,10 +145,8 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; prob_new = SciMLBase.remake( prob_old; f = f_new, - tstops = tstops, - advance_to_tstop = !isempty(tstops), + advance_to_tstop = true, initializealg = SciMLBase.NoInit(), - callback = callbacks, kwargs..., ) if param_ixs === nothing @@ -154,9 +154,10 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; else x0 = deepcopy(sim.x0_init) sys = deepcopy(sim.sys) - function f_enzyme(p, x0, sys, sim_inputs, prob, data, init_level) #Make separate f_enzymes depending on init_level? + function f_enzyme(p, x0, sys, sim_inputs, prob, data, init_level, callbacks, tstops) p_new = sim_inputs.parameters p_new[param_ixs] .= p + #callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) #Restore after: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 if init_level == POWERFLOW_AND_DEVICES @error "POWERFLOW AND DEVICES -- not yet supported" #_initialize_powerflow_and_devices!(x0, inputs, sys) @@ -168,19 +169,20 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; @info "I.C.s not impacted by parameter change" end if typeof(prob) <: SciMLBase.AbstractODEProblem - prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) + prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0, tstops = tstops) elseif typeof(prob) <: SciMLBase.AbstractDDEProblem h(p, t; idxs = nothing) = begin typeof(idxs) <: Number ? x0[idxs] : x0 end - prob_new = SciMLBase.remake(prob; h = h, p = p_new, u0 = x0) + prob_new = + SciMLBase.remake(prob; h = h, p = p_new, u0 = x0, tstops = tstops) end - sol = SciMLBase.solve(prob_new, solver) + sol = solve_with_callback(prob_new, callbacks, solver) ix_t = unique(i -> sol.t[i], eachindex(sol.t)) states = [sol[ix, ix_t] for ix in state_ixs] return f_loss(states, data) end - function f_Zygote(p, x0, sys, sim_inputs, prob, data, init_level) #Make separate f_enzymes depending on init_level? + function f_Zygote(p, x0, sys, sim_inputs, prob, data, init_level, callbacks, tstops) p_new = sim_inputs.parameters p_new_buff = Zygote.Buffer(p_new) for ix in eachindex(p_new) @@ -190,6 +192,16 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; p_new_buff[ix] = p[i] end p_new = copy(p_new_buff) + #Converting perturbations to callbacks, restore after : https://github.com/EnzymeAD/Enzyme.jl/issues/1650 + #@error "Zygote assumes single perturbation" + #cb = Vector{SciMLBase.DiscreteCallback}(undef, 1) + #pert = perts[1] + #condition = (x, t, integrator) -> t in [pert.time] + #affect = get_affect(sim_inputs, sys, pert) + #cb = [SciMLBase.DiscreteCallback(condition, affect)] + #callbacks = SciMLBase.CallbackSet((), tuple(cb...)) + #tstops = [pert.time] + if init_level == POWERFLOW_AND_DEVICES @error "POWERFLOW AND DEVICES -- not yet supported" #_initialize_powerflow_and_devices!(x0, inputs, sys) @@ -201,14 +213,15 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; @info "I.C.s not impacted by parameter change" end if typeof(prob) <: SciMLBase.AbstractODEProblem - prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0) + prob_new = SciMLBase.remake(prob; p = p_new, u0 = x0, tstops = tstops) elseif typeof(prob) <: SciMLBase.AbstractDDEProblem h(p, t; idxs = nothing) = begin typeof(idxs) <: Number ? x0[idxs] : x0 end - prob_new = SciMLBase.remake(prob; h = h, p = p_new, u0 = x0) + prob_new = + SciMLBase.remake(prob; h = h, p = p_new, u0 = x0, tstops = tstops) end - sol = SciMLBase.solve(prob_new, solver) + sol = SciMLBase.solve(prob_new, solver; callback = callbacks) #Hack to avoid unique(i -> sol.t[i], eachindex(sol.t)) which mutates and is incompatible with Zygote: ix_first = findfirst(x -> x == 1.0, sol.t) ix_last = findlast(x -> x == 1.0, sol.t) @@ -216,7 +229,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; states = [sol[ix, ix_t] for ix in state_ixs] return f_loss(states, data) end - function f_forward(p, data) + function f_forward(p, callbacks, tstops, data) f_enzyme( p, x0, @@ -225,9 +238,11 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; prob_new, data, init_level, + callbacks, + tstops, ) end - function f_grad(p, data) + function f_grad(p, callbacks, tstops, data) dp = Enzyme.make_zero(p) dx0 = Enzyme.make_zero(x0) dsys = Enzyme.make_zero(sys) @@ -235,6 +250,8 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; dsim_inputs = Enzyme.make_zero(sim_inputs) dprob_new = Enzyme.make_zero(prob_new) ddata = Enzyme.make_zero(data) + dcallbacks = Enzyme.make_zero(callbacks) + dtstops = Enzyme.make_zero(tstops) Enzyme.autodiff( Enzyme.Reverse, f_enzyme, @@ -246,10 +263,12 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; Enzyme.Duplicated(prob_new, dprob_new), Enzyme.Duplicated(data, ddata), Enzyme.Const(init_level), + Enzyme.Duplicated(callbacks, dcallbacks), + Enzyme.Duplicated(tstops, dtstops), ) return dp end - function f_forward_zygote(p, data) + function f_forward_zygote(p, callbacks, tstops, data) f_Zygote( p, x0, @@ -258,6 +277,8 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; prob_new, data, init_level, + callbacks, + tstops, ) end f_forward, f_grad, f_forward_zygote diff --git a/src/base/sensitivity_rule.jl b/src/base/sensitivity_rule.jl new file mode 100644 index 000000000..28a475bc0 --- /dev/null +++ b/src/base/sensitivity_rule.jl @@ -0,0 +1,105 @@ +function solve_up_with_callback( + prob::Union{DiffEqBase.AbstractDEProblem, DiffEqBase.NonlinearProblem}, sensealg, u0, p, + cb, + args...; kwargs...) + alg = DiffEqBase.extract_alg( + args, + kwargs, + DiffEqBase.has_kwargs(prob) ? prob.kwargs : kwargs, + ) + if isnothing(alg) || !(alg isa DiffEqBase.AbstractDEAlgorithm) # Default algorithm handling + _prob = DiffEqBase.get_concrete_problem(prob, !(prob isa DiscreteProblem); u0 = u0, + p = p, callback = cb, kwargs...) + solve_call(_prob, args...; callback = cb, kwargs...) + else + _prob = DiffEqBase.get_concrete_problem( + prob, + DiffEqBase.isadaptive(alg); + u0 = u0, + p = p, + callback = cb, + kwargs..., + ) + _alg = DiffEqBase.prepare_alg(alg, _prob.u0, _prob.p, _prob) + DiffEqBase.check_prob_alg_pairing(_prob, alg) # use alg for improved inference + if length(args) > 1 + DiffEqBase.solve_call(_prob, _alg, Base.tail(args)...; callback = cb, kwargs...) + else + DiffEqBase.solve_call(_prob, _alg; callback = cb, kwargs...) + end + end +end + +function solve_with_callback(prob::DiffEqBase.AbstractDEProblem, cb, args...; + sensealg = nothing, #add cb as second argument. + u0 = nothing, p = nothing, wrap = Val(true), kwargs...) + if sensealg === nothing && haskey(prob.kwargs, :sensealg) + sensealg = prob.kwargs[:sensealg] + end + + u0 = u0 !== nothing ? u0 : prob.u0 + p = p !== nothing ? p : prob.p + + if wrap isa Val{true} + DiffEqBase.wrap_sol( + solve_up_with_callback(prob, sensealg, u0, p, cb, args...; kwargs...), + ) + else + solve_up_with_callback(prob, sensealg, u0, p, cb, args...; kwargs...) + end +end + +function Enzyme.EnzymeRules.augmented_primal(config::Enzyme.EnzymeRules.ConfigWidth{1}, + func::Enzyme.Const{typeof(solve_up_with_callback)}, ::Type{Enzyme.Duplicated{RT}}, prob, + sensealg::Union{ + Enzyme.Const{Nothing}, + Enzyme.Const{<:DiffEqBase.AbstractSensitivityAlgorithm}, + }, + u0, p, cb, args...; kwargs...) where {RT} + @inline function copy_or_reuse(val, idx) + if Enzyme.EnzymeRules.overwritten(config)[idx] && ismutable(val) + return deepcopy(val) + else + return val + end + end + + @inline function arg_copy(i) + copy_or_reuse(args[i].val, i + 5) + end + + res = DiffEqBase._solve_adjoint( + copy_or_reuse(prob.val, 2), copy_or_reuse(sensealg.val, 3), + copy_or_reuse(u0.val, 4), copy_or_reuse(p.val, 5), + SciMLBase.EnzymeOriginator(), ntuple(arg_copy, Val(length(args)))...; + callback = copy_or_reuse(cb.val, 6), + kwargs...) + + dres = Enzyme.make_zero(res[1])::RT + tup = (dres, res[2]) + return Enzyme.EnzymeRules.AugmentedReturn{RT, RT, Any}(res[1], dres, tup::Any) +end + +function Enzyme.EnzymeRules.reverse(config::Enzyme.EnzymeRules.ConfigWidth{1}, + func::Enzyme.Const{typeof(solve_up_with_callback)}, ::Type{Enzyme.Duplicated{RT}}, tape, + prob, + sensealg::Union{ + Enzyme.Const{Nothing}, + Enzyme.Const{<:DiffEqBase.AbstractSensitivityAlgorithm}, + }, + u0, p, cb, args...; kwargs...) where {RT} + dres, clos = tape + dres = dres::RT + dargs = clos(dres) + for (darg, ptr) in zip(dargs, (func, prob, sensealg, u0, p, cb, args...)) + if ptr isa Enzyme.Const + continue + end + if darg == ChainRulesCore.NoTangent() + continue + end + ptr.dval .+= darg + end + Enzyme.make_zero!(dres.u) + return ntuple(_ -> nothing, Val(length(args) + 5)) +end diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index 17f326f71..db6cd3b1b 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -49,6 +49,13 @@ using PlotlyJS #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + ) + execute!(sim, Rodas4()) #GET SENSITIVITY FUNCTIONS f_forward, f_grad, _ = get_sensitivity_functions( @@ -63,16 +70,20 @@ using PlotlyJS dtmax = 0.005, saveat = 0.005, ) - - loss_zero = f_forward(p, δ_gt) - loss_non_zero_1 = f_forward([3.2], δ_gt) - loss_non_zero_2 = f_forward(p, δ_gt .* 2) + callbacks, tstops = PSID.convert_perturbations_to_callbacks( + PSID.get_system(sim), + PSID.get_simulation_inputs(sim), + [s_change], + ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 + loss_zero = f_forward(p, callbacks, tstops, δ_gt) + loss_non_zero_1 = f_forward([3.2], callbacks, tstops, δ_gt) + loss_non_zero_2 = f_forward(p, callbacks, tstops, δ_gt .* 2) @test loss_zero == 0.0 @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, δ_gt) - grad_nonzero_1 = f_grad([3.14], δ_gt) - grad_nonzero_2 = f_grad([3.15], δ_gt) + grad_zero = f_grad(p, callbacks, tstops, δ_gt) + grad_nonzero_1 = f_grad([3.14], callbacks, tstops, δ_gt) + grad_nonzero_2 = f_grad([3.15], callbacks, tstops, δ_gt) @test isapprox(grad_zero[1], 0.0, atol = 1.0) @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) @@ -111,6 +122,13 @@ end #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + ) + execute!(sim, Rodas4()) #GET SENSITIVITY FUNCTIONS f_forward, f_grad, _ = get_sensitivity_functions( @@ -125,16 +143,21 @@ end dtmax = 0.005, saveat = 0.005, ) - - loss_zero = f_forward(p, δ_gt) - loss_non_zero_1 = f_forward([3.2], δ_gt) - loss_non_zero_2 = f_forward(p, δ_gt .* 2) + callbacks, tstops = PSID.convert_perturbations_to_callbacks( + PSID.get_system(sim), + PSID.get_simulation_inputs(sim), + [s_change], + ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 + + loss_zero = f_forward(p, callbacks, tstops, δ_gt) + loss_non_zero_1 = f_forward([3.2], callbacks, tstops, δ_gt) + loss_non_zero_2 = f_forward(p, callbacks, tstops, δ_gt .* 2) @test loss_zero == 0.0 @test loss_non_zero_1 == 0.36199910927656687 @test loss_non_zero_2 == 172.66293171283323 - grad_zero = f_grad(p, δ_gt) - grad_nonzero_1 = f_grad([3.14], δ_gt) - grad_nonzero_2 = f_grad([3.15], δ_gt) + grad_zero = f_grad(p, callbacks, tstops, δ_gt) + grad_nonzero_1 = f_grad([3.14], callbacks, tstops, δ_gt) + grad_nonzero_2 = f_grad([3.15], callbacks, tstops, δ_gt) @test isapprox(grad_zero[1], -1.0, atol = 1.0) @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) @@ -173,7 +196,13 @@ end #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end - + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + ) + execute!(sim, Rodas4()) #GET SENSITIVITY FUNCTIONS f_forward, f_grad, _ = get_sensitivity_functions( sim, @@ -187,15 +216,20 @@ end dtmax = 0.005, saveat = 0.005, ) + callbacks, tstops = PSID.convert_perturbations_to_callbacks( + PSID.get_system(sim), + PSID.get_simulation_inputs(sim), + [s_change], + ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 - loss_zero = f_forward(p, δ_gt) - loss_non_zero_1 = f_forward(p .* 1.01, δ_gt) + loss_zero = f_forward(p, callbacks, tstops, δ_gt) + loss_non_zero_1 = f_forward(p .* 1.01, callbacks, tstops, δ_gt) @test isapprox(loss_zero, 0.0, atol = 1e-9) @test isapprox(loss_non_zero_1, 1.49, atol = 1e-3) - grad_zero = f_grad(p, δ_gt) - @test isapprox(sum(grad_zero), 523.5340704294135, atol = 1.0) + grad_zero = f_grad(p, callbacks, tstops, δ_gt) + @test isapprox(sum(grad_zero), 524.5865384550988, atol = 1e-3) finally @info("removing test files") rm(path; force = true, recursive = true) @@ -231,7 +265,13 @@ end #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end - + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + ) + execute!(sim, Rodas4()) f_forward, f_grad, f_zygote_forward = get_sensitivity_functions( sim, [("generator-102-1", :Shaft, :H)], @@ -244,11 +284,20 @@ end dtmax = 0.005, saveat = 0.005, ) - @test f_forward(p, δ_gt) == f_zygote_forward(p, δ_gt) - @test f_forward([3.14], δ_gt) == f_zygote_forward([3.14], δ_gt) - @test f_forward([3.15], δ_gt) == f_zygote_forward([3.15], δ_gt) - - @test f_grad(p, δ_gt) == Zygote.gradient(p -> f_zygote_forward(p, δ_gt), p)[1] + callbacks, tstops = PSID.convert_perturbations_to_callbacks( + PSID.get_system(sim), + PSID.get_simulation_inputs(sim), + [p_state], + ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 + + @test f_forward(p, callbacks, tstops, δ_gt) == + f_zygote_forward(p, callbacks, tstops, δ_gt) + @test f_forward([3.14], callbacks, tstops, δ_gt) == + f_zygote_forward([3.14], callbacks, tstops, δ_gt) + @test f_forward([3.15], callbacks, tstops, δ_gt) == + f_zygote_forward([3.15], callbacks, tstops, δ_gt) + @test f_grad(p, callbacks, tstops, δ_gt) == + Zygote.gradient(p -> f_zygote_forward(p, callbacks, tstops, δ_gt), p)[1] _, _, f_zygote_forward = get_sensitivity_functions( sim, @@ -263,18 +312,18 @@ end saveat = 0.005, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, δ_gt), p)[1][1], - 78.6312919795057, + Zygote.gradient(p -> f_zygote_forward(p, callbacks, tstops, δ_gt), p)[1][1], + -223.7406308892161, atol = 1e-6, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, δ_gt), [3.14])[1][1], - 53.94277234225185, + Zygote.gradient(p -> f_zygote_forward(p, callbacks, tstops, δ_gt), [3.14])[1][1], + -256.88284936919246, atol = 1e-6, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, δ_gt), [3.15])[1][1], - 78.48879776368774, + Zygote.gradient(p -> f_zygote_forward(p, callbacks, tstops, δ_gt), [3.15])[1][1], + 256.36101155595964, atol = 1e-6, ) finally @@ -312,6 +361,13 @@ end #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + ) + execute!(sim, Rodas4()) #GET SENSITIVITY FUNCTIONS f_forward, f_grad, _ = get_sensitivity_functions( @@ -326,6 +382,12 @@ end dtmax = 0.005, saveat = 0.005, ) + callbacks, tstops = PSID.convert_perturbations_to_callbacks( + PSID.get_system(sim), + PSID.get_simulation_inputs(sim), + [s_change], + ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 + #H_values = [] #loss_values = [] function callback(u, l) @@ -334,8 +396,8 @@ end return false end optfun = OptimizationFunction{false}( - (u, p) -> f_forward(u, δ_gt); - grad = (res, u, p) -> res .= f_grad(u, δ_gt), + (u, p) -> f_forward(u, callbacks, tstops, δ_gt); + grad = (res, u, p) -> res .= f_grad(u, callbacks, tstops, δ_gt), ) optprob = OptimizationProblem{false}(optfun, [3.14]) sol = Optimization.solve( @@ -381,6 +443,13 @@ end #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + ) + execute!(sim, Rodas4()) #GET SENSITIVITY FUNCTIONS f_forward, f_grad, _ = get_sensitivity_functions( @@ -395,18 +464,23 @@ end dtmax = 0.005, saveat = 0.005, ) - - loss_zero = f_forward(p, δ_gt) - loss_non_zero_1 = f_forward(p * 1.01, δ_gt) - loss_non_zero_2 = f_forward(p * 0.99, δ_gt) + callbacks, tstops = PSID.convert_perturbations_to_callbacks( + PSID.get_system(sim), + PSID.get_simulation_inputs(sim), + [s_change], + ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 + + loss_zero = f_forward(p, callbacks, tstops, δ_gt) + loss_non_zero_1 = f_forward(p * 1.01, callbacks, tstops, δ_gt) + loss_non_zero_2 = f_forward(p * 0.99, callbacks, tstops, δ_gt) @test isapprox(loss_zero, 0.0, atol = 1e-9) @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, δ_gt) - grad_nonzero_1 = f_grad(p * 1.01, δ_gt) - grad_nonzero_2 = f_grad(p * 0.99, δ_gt) - @test isapprox(grad_zero[1], 498.0, atol = 1.0) - @test isapprox(grad_nonzero_1[1], 499.0, atol = 1.0) + grad_zero = f_grad(p, callbacks, tstops, δ_gt) + grad_nonzero_1 = f_grad(p * 1.01, callbacks, tstops, δ_gt) + grad_nonzero_2 = f_grad(p * 0.99, callbacks, tstops, δ_gt) + @test isapprox(grad_zero[1], 499.0, atol = 1.0) + @test isapprox(grad_nonzero_1[1], 500.0, atol = 1.0) @test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) finally @info("removing test files") @@ -437,8 +511,8 @@ function transform_power_load_to_constant_impedance(x::PowerLoad) ) return l end -using PlotlyJS -@time @testset "Test Gradients - 9 bus; Xd_p" begin + +@testset "Test Gradients - 9 bus; Xd_p" begin path = mktempdir() try sys = build_system(PSIDTestSystems, "psid_test_ieee_9bus") @@ -449,12 +523,13 @@ using PlotlyJS end dyn_gen = get_component(DynamicGenerator, sys, "generator-3-1") get_machine(dyn_gen) + p_ctrl = ControlReferenceChange(1.0, dyn_gen, :P_ref, 0.5) sim = Simulation!( MassMatrixModel, sys, path, (0.0, 5.0), - ControlReferenceChange(1.0, dyn_gen, :P_ref, 0.5), + p_ctrl, ) #GET GROUND TRUTH DATA @@ -473,6 +548,13 @@ using PlotlyJS #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end + sim = Simulation!( + MassMatrixModel, + sys, + path, + (0.0, 5.0), + ) + execute!(sim, Rodas4()) #GET SENSITIVITY FUNCTIONS f_forward, f_grad, _ = get_sensitivity_functions( @@ -487,17 +569,22 @@ using PlotlyJS dtmax = 0.05, saveat = 0.05, ) - - loss_zero = f_forward(p, δ_gt) - loss_non_zero_1 = f_forward(p * 1.01, δ_gt) - loss_non_zero_2 = f_forward(p * 0.99, δ_gt) + callbacks, tstops = PSID.convert_perturbations_to_callbacks( + PSID.get_system(sim), + PSID.get_simulation_inputs(sim), + [p_ctrl], + ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 + + loss_zero = f_forward(p, callbacks, tstops, δ_gt) + loss_non_zero_1 = f_forward(p * 1.01, callbacks, tstops, δ_gt) + loss_non_zero_2 = f_forward(p * 0.99, callbacks, tstops, δ_gt) @test isapprox(loss_zero, 0.0, atol = 2e-9) @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, δ_gt) - grad_nonzero_1 = f_grad(p * 1.01, δ_gt) - grad_nonzero_2 = f_grad(p * 0.99, δ_gt) - @test isapprox(grad_zero[1], 0.8876855633591412, atol = 1e-6) + grad_zero = f_grad(p, callbacks, tstops, δ_gt) + grad_nonzero_1 = f_grad(p * 1.01, callbacks, tstops, δ_gt) + grad_nonzero_2 = f_grad(p * 0.99, callbacks, tstops, δ_gt) + @test isapprox(grad_zero[1], 0.8876855633591412, atol = 1e-6) #should pass --> once we convert outside of the test. @test isapprox(grad_nonzero_1[1], 0.5946989856464833, atol = 1.0) @test isapprox(grad_nonzero_2[1], -0.9432527319604077; atol = 1.0) finally From b1a935040cd10801ceee1b7abfc4e8dfe298c57a Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sat, 20 Jul 2024 20:36:26 -0400 Subject: [PATCH 61/76] option for reinitializing system --- src/base/sensitivity_analysis.jl | 51 +++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index e608bcde3..304512b6c 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -116,7 +116,15 @@ function convert_perturbations_to_callbacks(sys, sim_inputs, perturbations) return callbacks, tstops end -function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; kwargs...) +function get_sensitivity_functions( + sim, + param_data, + state_data, + solver, + f_loss, + sys_reinit = false; + kwargs..., +) p_metadata = sim.inputs.parameters_metadata p = sim.inputs.parameters param_ixs, init_level = get_ix_and_level(p, p_metadata, param_data) @@ -154,7 +162,18 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; else x0 = deepcopy(sim.x0_init) sys = deepcopy(sim.sys) - function f_enzyme(p, x0, sys, sim_inputs, prob, data, init_level, callbacks, tstops) + function f_enzyme( + p, + x0, + sys, + sim_inputs, + prob, + data, + init_level, + sys_reinit, + callbacks, + tstops, + ) p_new = sim_inputs.parameters p_new[param_ixs] .= p #callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) #Restore after: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 @@ -162,9 +181,14 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; @error "POWERFLOW AND DEVICES -- not yet supported" #_initialize_powerflow_and_devices!(x0, inputs, sys) elseif init_level == DEVICES_ONLY - @info "Reinitializing devices only" - _initialize_devices_only!(x0, sim_inputs) - #_refine_initial_condition!(x0, p_new, prob) #Only re-initialize devices; not full system refinement + if sys_reinit + @info "Reinitializing inividual devices and full system" + _initialize_devices_only!(x0, sim_inputs) + _refine_initial_condition!(x0, p_new, prob) + else + @info "Reinitializing devices only" + _initialize_devices_only!(x0, sim_inputs) + end elseif init_level == INITIALIZED @info "I.C.s not impacted by parameter change" end @@ -182,7 +206,18 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; states = [sol[ix, ix_t] for ix in state_ixs] return f_loss(states, data) end - function f_Zygote(p, x0, sys, sim_inputs, prob, data, init_level, callbacks, tstops) + function f_Zygote( + p, + x0, + sys, + sim_inputs, + prob, + data, + init_level, + sys_reinit, + callbacks, + tstops, + ) p_new = sim_inputs.parameters p_new_buff = Zygote.Buffer(p_new) for ix in eachindex(p_new) @@ -208,7 +243,6 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; elseif init_level == DEVICES_ONLY @error "Reinitializing not supported with Zygote" _initialize_devices_only!(x0, sim_inputs) #Mutation - #_refine_initial_condition!(x0, p_new, prob) #Only re-initialize devices; not full system refinement elseif init_level == INITIALIZED @info "I.C.s not impacted by parameter change" end @@ -238,6 +272,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; prob_new, data, init_level, + sys_reinit, callbacks, tstops, ) @@ -263,6 +298,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; Enzyme.Duplicated(prob_new, dprob_new), Enzyme.Duplicated(data, ddata), Enzyme.Const(init_level), + Enzyme.Const(sys_reinit), Enzyme.Duplicated(callbacks, dcallbacks), Enzyme.Duplicated(tstops, dtstops), ) @@ -277,6 +313,7 @@ function get_sensitivity_functions(sim, param_data, state_data, solver, f_loss; prob_new, data, init_level, + sys_reinit, callbacks, tstops, ) From 8aa428fc57c94ddd5a0e168330784b44b1032de2 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sun, 21 Jul 2024 14:51:05 -0400 Subject: [PATCH 62/76] add DuplicatedNoNeed dispatch --- src/base/sensitivity_rule.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/base/sensitivity_rule.jl b/src/base/sensitivity_rule.jl index 28a475bc0..aa4c71efb 100644 --- a/src/base/sensitivity_rule.jl +++ b/src/base/sensitivity_rule.jl @@ -50,7 +50,8 @@ function solve_with_callback(prob::DiffEqBase.AbstractDEProblem, cb, args...; end function Enzyme.EnzymeRules.augmented_primal(config::Enzyme.EnzymeRules.ConfigWidth{1}, - func::Enzyme.Const{typeof(solve_up_with_callback)}, ::Type{Enzyme.Duplicated{RT}}, prob, + func::Enzyme.Const{typeof(solve_up_with_callback)}, + ::Type{<:Union{Enzyme.Duplicated{RT}, Enzyme.DuplicatedNoNeed{RT}}}, prob, sensealg::Union{ Enzyme.Const{Nothing}, Enzyme.Const{<:DiffEqBase.AbstractSensitivityAlgorithm}, @@ -81,7 +82,8 @@ function Enzyme.EnzymeRules.augmented_primal(config::Enzyme.EnzymeRules.ConfigWi end function Enzyme.EnzymeRules.reverse(config::Enzyme.EnzymeRules.ConfigWidth{1}, - func::Enzyme.Const{typeof(solve_up_with_callback)}, ::Type{Enzyme.Duplicated{RT}}, tape, + func::Enzyme.Const{typeof(solve_up_with_callback)}, + ::Type{<:Union{Enzyme.Duplicated{RT}, Enzyme.DuplicatedNoNeed{RT}}}, tape, prob, sensealg::Union{ Enzyme.Const{Nothing}, From 793d765131e8aa7bcaf45a5b09c425a22b278c64 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 22 Jul 2024 09:22:09 -0400 Subject: [PATCH 63/76] add get_parameter_labels --- src/PowerSimulationsDynamics.jl | 1 + src/base/sensitivity_analysis.jl | 12 ++++++++++++ test/test_case_enzyme.jl | 2 ++ 3 files changed, 15 insertions(+) diff --git a/src/PowerSimulationsDynamics.jl b/src/PowerSimulationsDynamics.jl index 22a95179a..3d6f6c7f9 100644 --- a/src/PowerSimulationsDynamics.jl +++ b/src/PowerSimulationsDynamics.jl @@ -62,6 +62,7 @@ export transform_load_to_constant_impedance export transform_load_to_constant_current export transform_load_to_constant_power export get_parameter_values +export get_parameter_labels export get_sensitivity_functions ####################################### Package Imports #################################### diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 304512b6c..6c11fc96f 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -77,6 +77,18 @@ function get_parameter_values(sim, device_param_pairs) end end +function get_parameter_labels(sim, device_param_pairs) + p = sim.inputs.parameters + p_metadata = sim.inputs.parameters_metadata + labels = ComponentArrays.labels(p) + ixs, _ = get_ix_and_level(p, p_metadata, device_param_pairs) + if ixs === nothing + return nothing + else + return labels[ixs] + end +end + function get_ix_and_level(p, p_metadata, param_data) param_ixs = get_indices_in_parameter_vector(p, param_data) metadata_ixs = get_indices_in_parameter_vector(p_metadata, param_data) diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index db6cd3b1b..895588674 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -81,6 +81,8 @@ using PlotlyJS @test loss_zero == 0.0 @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 + @test get_parameter_labels(sim, [("generator-102-1", :Shaft, :H)]) == + ["generator-102-1.params.Shaft.H"] grad_zero = f_grad(p, callbacks, tstops, δ_gt) grad_nonzero_1 = f_grad([3.14], callbacks, tstops, δ_gt) grad_nonzero_2 = f_grad([3.15], callbacks, tstops, δ_gt) From d78a3db41b9d5d7f2c8c15a5bbdc04e2d5736d02 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 22 Jul 2024 11:05:10 -0400 Subject: [PATCH 64/76] change api to take perturbations directly --- src/base/sensitivity_analysis.jl | 31 +++--- test/test_case_enzyme.jl | 177 +++++++++++++------------------ 2 files changed, 88 insertions(+), 120 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 6c11fc96f..cbb5cf841 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -188,7 +188,6 @@ function get_sensitivity_functions( ) p_new = sim_inputs.parameters p_new[param_ixs] .= p - #callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) #Restore after: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 if init_level == POWERFLOW_AND_DEVICES @error "POWERFLOW AND DEVICES -- not yet supported" #_initialize_powerflow_and_devices!(x0, inputs, sys) @@ -227,8 +226,7 @@ function get_sensitivity_functions( data, init_level, sys_reinit, - callbacks, - tstops, + perts, ) p_new = sim_inputs.parameters p_new_buff = Zygote.Buffer(p_new) @@ -240,14 +238,14 @@ function get_sensitivity_functions( end p_new = copy(p_new_buff) #Converting perturbations to callbacks, restore after : https://github.com/EnzymeAD/Enzyme.jl/issues/1650 - #@error "Zygote assumes single perturbation" - #cb = Vector{SciMLBase.DiscreteCallback}(undef, 1) - #pert = perts[1] - #condition = (x, t, integrator) -> t in [pert.time] - #affect = get_affect(sim_inputs, sys, pert) - #cb = [SciMLBase.DiscreteCallback(condition, affect)] - #callbacks = SciMLBase.CallbackSet((), tuple(cb...)) - #tstops = [pert.time] + @error "Zygote assumes single perturbation" + cb = Vector{SciMLBase.DiscreteCallback}(undef, 1) + pert = perts[1] + condition = (x, t, integrator) -> t in [pert.time] + affect = get_affect(sim_inputs, sys, pert) + cb = [SciMLBase.DiscreteCallback(condition, affect)] + callbacks = SciMLBase.CallbackSet((), tuple(cb...)) + tstops = [pert.time] if init_level == POWERFLOW_AND_DEVICES @error "POWERFLOW AND DEVICES -- not yet supported" @@ -275,7 +273,8 @@ function get_sensitivity_functions( states = [sol[ix, ix_t] for ix in state_ixs] return f_loss(states, data) end - function f_forward(p, callbacks, tstops, data) + function f_forward(p, perts, data) + callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) f_enzyme( p, x0, @@ -289,7 +288,8 @@ function get_sensitivity_functions( tstops, ) end - function f_grad(p, callbacks, tstops, data) + function f_grad(p, perts, data) + callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) dp = Enzyme.make_zero(p) dx0 = Enzyme.make_zero(x0) dsys = Enzyme.make_zero(sys) @@ -316,7 +316,7 @@ function get_sensitivity_functions( ) return dp end - function f_forward_zygote(p, callbacks, tstops, data) + function f_forward_zygote(p, perts, data) f_Zygote( p, x0, @@ -326,8 +326,7 @@ function get_sensitivity_functions( data, init_level, sys_reinit, - callbacks, - tstops, + perts, ) end f_forward, f_grad, f_forward_zygote diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index 895588674..f2cc6ccfb 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -70,22 +70,17 @@ using PlotlyJS dtmax = 0.005, saveat = 0.005, ) - callbacks, tstops = PSID.convert_perturbations_to_callbacks( - PSID.get_system(sim), - PSID.get_simulation_inputs(sim), - [s_change], - ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 - loss_zero = f_forward(p, callbacks, tstops, δ_gt) - loss_non_zero_1 = f_forward([3.2], callbacks, tstops, δ_gt) - loss_non_zero_2 = f_forward(p, callbacks, tstops, δ_gt .* 2) + loss_zero = f_forward(p, [s_change], δ_gt) + loss_non_zero_1 = f_forward([3.2], [s_change], δ_gt) + loss_non_zero_2 = f_forward(p, [s_change], δ_gt .* 2) @test loss_zero == 0.0 @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 @test get_parameter_labels(sim, [("generator-102-1", :Shaft, :H)]) == ["generator-102-1.params.Shaft.H"] - grad_zero = f_grad(p, callbacks, tstops, δ_gt) - grad_nonzero_1 = f_grad([3.14], callbacks, tstops, δ_gt) - grad_nonzero_2 = f_grad([3.15], callbacks, tstops, δ_gt) + grad_zero = f_grad(p, [s_change], δ_gt) + grad_nonzero_1 = f_grad([3.14], [s_change], δ_gt) + grad_nonzero_2 = f_grad([3.15], [s_change], δ_gt) @test isapprox(grad_zero[1], 0.0, atol = 1.0) @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) @@ -145,21 +140,15 @@ end dtmax = 0.005, saveat = 0.005, ) - callbacks, tstops = PSID.convert_perturbations_to_callbacks( - PSID.get_system(sim), - PSID.get_simulation_inputs(sim), - [s_change], - ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 - - loss_zero = f_forward(p, callbacks, tstops, δ_gt) - loss_non_zero_1 = f_forward([3.2], callbacks, tstops, δ_gt) - loss_non_zero_2 = f_forward(p, callbacks, tstops, δ_gt .* 2) + loss_zero = f_forward(p, [s_change], δ_gt) + loss_non_zero_1 = f_forward([3.2], [s_change], δ_gt) + loss_non_zero_2 = f_forward(p, [s_change], δ_gt .* 2) @test loss_zero == 0.0 @test loss_non_zero_1 == 0.36199910927656687 @test loss_non_zero_2 == 172.66293171283323 - grad_zero = f_grad(p, callbacks, tstops, δ_gt) - grad_nonzero_1 = f_grad([3.14], callbacks, tstops, δ_gt) - grad_nonzero_2 = f_grad([3.15], callbacks, tstops, δ_gt) + grad_zero = f_grad(p, [s_change], δ_gt) + grad_nonzero_1 = f_grad([3.14], [s_change], δ_gt) + grad_nonzero_2 = f_grad([3.15], [s_change], δ_gt) @test isapprox(grad_zero[1], -1.0, atol = 1.0) @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) @@ -218,19 +207,13 @@ end dtmax = 0.005, saveat = 0.005, ) - callbacks, tstops = PSID.convert_perturbations_to_callbacks( - PSID.get_system(sim), - PSID.get_simulation_inputs(sim), - [s_change], - ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 - - loss_zero = f_forward(p, callbacks, tstops, δ_gt) - loss_non_zero_1 = f_forward(p .* 1.01, callbacks, tstops, δ_gt) + loss_zero = f_forward(p, [s_change], δ_gt) + loss_non_zero_1 = f_forward(p .* 1.01, [s_change], δ_gt) @test isapprox(loss_zero, 0.0, atol = 1e-9) @test isapprox(loss_non_zero_1, 1.49, atol = 1e-3) - grad_zero = f_grad(p, callbacks, tstops, δ_gt) + grad_zero = f_grad(p, [s_change], δ_gt) @test isapprox(sum(grad_zero), 524.5865384550988, atol = 1e-3) finally @info("removing test files") @@ -286,20 +269,14 @@ end dtmax = 0.005, saveat = 0.005, ) - callbacks, tstops = PSID.convert_perturbations_to_callbacks( - PSID.get_system(sim), - PSID.get_simulation_inputs(sim), - [p_state], - ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 - - @test f_forward(p, callbacks, tstops, δ_gt) == - f_zygote_forward(p, callbacks, tstops, δ_gt) - @test f_forward([3.14], callbacks, tstops, δ_gt) == - f_zygote_forward([3.14], callbacks, tstops, δ_gt) - @test f_forward([3.15], callbacks, tstops, δ_gt) == - f_zygote_forward([3.15], callbacks, tstops, δ_gt) - @test f_grad(p, callbacks, tstops, δ_gt) == - Zygote.gradient(p -> f_zygote_forward(p, callbacks, tstops, δ_gt), p)[1] + @test f_forward(p, [p_state], δ_gt) == + f_zygote_forward(p, [p_state], δ_gt) + @test f_forward([3.14], [p_state], δ_gt) == + f_zygote_forward([3.14], [p_state], δ_gt) + @test f_forward([3.15], [p_state], δ_gt) == + f_zygote_forward([3.15], [p_state], δ_gt) + @test f_grad(p, [p_state], δ_gt) == + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), p)[1] _, _, f_zygote_forward = get_sensitivity_functions( sim, @@ -314,17 +291,17 @@ end saveat = 0.005, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, callbacks, tstops, δ_gt), p)[1][1], + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), p)[1][1], -223.7406308892161, atol = 1e-6, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, callbacks, tstops, δ_gt), [3.14])[1][1], + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), [3.14])[1][1], -256.88284936919246, atol = 1e-6, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, callbacks, tstops, δ_gt), [3.15])[1][1], + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), [3.15])[1][1], 256.36101155595964, atol = 1e-6, ) @@ -384,12 +361,6 @@ end dtmax = 0.005, saveat = 0.005, ) - callbacks, tstops = PSID.convert_perturbations_to_callbacks( - PSID.get_system(sim), - PSID.get_simulation_inputs(sim), - [s_change], - ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 - #H_values = [] #loss_values = [] function callback(u, l) @@ -398,8 +369,8 @@ end return false end optfun = OptimizationFunction{false}( - (u, p) -> f_forward(u, callbacks, tstops, δ_gt); - grad = (res, u, p) -> res .= f_grad(u, callbacks, tstops, δ_gt), + (u, p) -> f_forward(u, [s_change], δ_gt); + grad = (res, u, p) -> res .= f_grad(u, [s_change], δ_gt), ) optprob = OptimizationProblem{false}(optfun, [3.14]) sol = Optimization.solve( @@ -466,21 +437,15 @@ end dtmax = 0.005, saveat = 0.005, ) - callbacks, tstops = PSID.convert_perturbations_to_callbacks( - PSID.get_system(sim), - PSID.get_simulation_inputs(sim), - [s_change], - ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 - - loss_zero = f_forward(p, callbacks, tstops, δ_gt) - loss_non_zero_1 = f_forward(p * 1.01, callbacks, tstops, δ_gt) - loss_non_zero_2 = f_forward(p * 0.99, callbacks, tstops, δ_gt) + loss_zero = f_forward(p, [s_change], δ_gt) + loss_non_zero_1 = f_forward(p * 1.01, [s_change], δ_gt) + loss_non_zero_2 = f_forward(p * 0.99, [s_change], δ_gt) @test isapprox(loss_zero, 0.0, atol = 1e-9) @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, callbacks, tstops, δ_gt) - grad_nonzero_1 = f_grad(p * 1.01, callbacks, tstops, δ_gt) - grad_nonzero_2 = f_grad(p * 0.99, callbacks, tstops, δ_gt) + grad_zero = f_grad(p, [s_change], δ_gt) + grad_nonzero_1 = f_grad(p * 1.01, [s_change], δ_gt) + grad_nonzero_2 = f_grad(p * 0.99, [s_change], δ_gt) @test isapprox(grad_zero[1], 499.0, atol = 1.0) @test isapprox(grad_nonzero_1[1], 500.0, atol = 1.0) @test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) @@ -525,7 +490,9 @@ end end dyn_gen = get_component(DynamicGenerator, sys, "generator-3-1") get_machine(dyn_gen) - p_ctrl = ControlReferenceChange(1.0, dyn_gen, :P_ref, 0.5) + + #p_ctrl = ControlReferenceChange(1.0, dyn_gen, :P_ref, 0.5) + p_ctrl = PerturbState(1.0, 25, 0.4789) sim = Simulation!( MassMatrixModel, sys, @@ -533,12 +500,12 @@ end (0.0, 5.0), p_ctrl, ) - + #GET GROUND TRUTH DATA execute!(sim, Rodas4(); abstol = 1e-6, reltol = 1e-6, dtmax = 0.05, saveat = 0.05) res = read_results(sim) t, δ_gt = get_state_series(res, ("generator-3-1", :δ)) - + @error PSID.get_global_state_map(sim.inputs) #GET PARAMETER VALUES p = get_parameter_values(sim, [("generator-3-1", :Machine, :Xd_p)]) @@ -547,7 +514,7 @@ end end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing function f_loss(states, δ_gt) - #plot_traces(states[1], δ_gt) + plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end sim = Simulation!( @@ -557,6 +524,7 @@ end (0.0, 5.0), ) execute!(sim, Rodas4()) + @error PSID.get_global_state_map(sim.inputs) #GET SENSITIVITY FUNCTIONS f_forward, f_grad, _ = get_sensitivity_functions( @@ -571,33 +539,27 @@ end dtmax = 0.05, saveat = 0.05, ) - callbacks, tstops = PSID.convert_perturbations_to_callbacks( - PSID.get_system(sim), - PSID.get_simulation_inputs(sim), - [p_ctrl], - ) #Move this inside the forward/grad functions once this issue is resolved: https://github.com/EnzymeAD/Enzyme.jl/issues/1650 - - loss_zero = f_forward(p, callbacks, tstops, δ_gt) - loss_non_zero_1 = f_forward(p * 1.01, callbacks, tstops, δ_gt) - loss_non_zero_2 = f_forward(p * 0.99, callbacks, tstops, δ_gt) + loss_zero = f_forward(p, [p_ctrl], δ_gt) + loss_non_zero_1 = f_forward(p * 1.01, [p_ctrl], δ_gt) + loss_non_zero_2 = f_forward(p * 0.99, [p_ctrl], δ_gt) @test isapprox(loss_zero, 0.0, atol = 2e-9) @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, callbacks, tstops, δ_gt) - grad_nonzero_1 = f_grad(p * 1.01, callbacks, tstops, δ_gt) - grad_nonzero_2 = f_grad(p * 0.99, callbacks, tstops, δ_gt) - @test isapprox(grad_zero[1], 0.8876855633591412, atol = 1e-6) #should pass --> once we convert outside of the test. - @test isapprox(grad_nonzero_1[1], 0.5946989856464833, atol = 1.0) - @test isapprox(grad_nonzero_2[1], -0.9432527319604077; atol = 1.0) + grad_zero = f_grad(p, [p_ctrl], δ_gt) + #grad_nonzero_1 = f_grad(p * 1.01, [p_ctrl], δ_gt) + #grad_nonzero_2 = f_grad(p * 0.99, [p_ctrl], δ_gt) + #@test isapprox(grad_zero[1], 0.8876855633591412, atol = 1e-6) #should pass --> once we convert outside of the test. + #@test isapprox(grad_nonzero_1[1], 0.5946989856464833, atol = 1.0) + #@test isapprox(grad_nonzero_2[1], -0.9432527319604077; atol = 1.0) finally @info("removing test files") rm(path; force = true, recursive = true) end end - +2+2 #= #BELOW HERE: TESTS FOR SENSITIVITY OF DDES - +#NOTE: "Only the discretize-then-optimize methods are applicable to delay differential equations." function add_degov_to_omib!(omib_sys) gen = get_component(ThermalStandard, omib_sys, "generator-102-1") dyn_gen = get_component(DynamicGenerator, omib_sys, "generator-102-1") @@ -626,9 +588,9 @@ function add_degov_to_omib!(omib_sys) add_component!(omib_sys, dyn_gen_new, gen) end - @testset "Test Gradients - OMIB; H; Delays" begin + #@testset "Test Gradients - OMIB; H; Delays" begin path = mktempdir() - try + #try #EnzymeRules.inactive(::typeof(Base.hasproperty), args...) = nothing # To allow wrap_sol to work? --> causes gradient to b zero; bad idea to go marking functions invalid without clear reason. omib_sys = build_system(PSIDTestSystems, "psid_test_omib") s_device = get_component(Source, omib_sys, "InfBus") @@ -662,10 +624,16 @@ end end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing function f_loss(states, δ_gt) - #plot_traces(δ, δ_gt) + plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end - + sim = Simulation!( + MassMatrixModel, + omib_sys, + pwd(), + (0.0, 5.0), #Inside of the delay time... + ) + execute!(sim, MethodOfSteps(Rodas4()),) #GET SENSITIVITY FUNCTIONS f_forward, f_grad, _ = get_sensitivity_functions( sim, @@ -679,22 +647,23 @@ end reltol = 1e-6, # 1e-6 # dtmax = 0.005, saveat = 0.005, - ) + ); + # @error length(δ_gt) - loss_zero = f_forward(p, δ_gt) - loss_non_zero_1 = f_forward([5.2], δ_gt) - loss_non_zero_2 = f_forward(p, δ_gt .* 2) + loss_zero = f_forward(p, [s_change], δ_gt) + loss_non_zero_1 = f_forward([5.2], [s_change], δ_gt) + loss_non_zero_2 = f_forward(p, [s_change], δ_gt .* 2) @test isapprox(loss_zero, 0.0, atol = 3e-3) @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, δ_gt) + grad_zero = f_grad(p, [s_change],δ_gt) @error grad_zero @test isapprox(grad_zero[1], 0.0, atol = 1e-12) - finally - @info("removing test files") - rm(path; force = true, recursive = true) - end -end + #finally + # @info("removing test files") + # rm(path; force = true, recursive = true) + #end +#end #Potential Rank Deficient Matrix Detected: Erorrs... @testset "Test Gradients - OMIB; Xd_p; delays" begin From 2911b5f1af5b557ef5286272a296d5cea951cd99 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 22 Jul 2024 18:27:26 -0400 Subject: [PATCH 65/76] restore tests (pases without dev PowerSystems) --- test/test_case_enzyme.jl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index f2cc6ccfb..eaff6d9f4 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -491,8 +491,8 @@ end dyn_gen = get_component(DynamicGenerator, sys, "generator-3-1") get_machine(dyn_gen) - #p_ctrl = ControlReferenceChange(1.0, dyn_gen, :P_ref, 0.5) - p_ctrl = PerturbState(1.0, 25, 0.4789) + p_ctrl = ControlReferenceChange(1.0, dyn_gen, :P_ref, 0.5) + sim = Simulation!( MassMatrixModel, sys, @@ -505,7 +505,7 @@ end execute!(sim, Rodas4(); abstol = 1e-6, reltol = 1e-6, dtmax = 0.05, saveat = 0.05) res = read_results(sim) t, δ_gt = get_state_series(res, ("generator-3-1", :δ)) - @error PSID.get_global_state_map(sim.inputs) + #GET PARAMETER VALUES p = get_parameter_values(sim, [("generator-3-1", :Machine, :Xd_p)]) @@ -524,7 +524,6 @@ end (0.0, 5.0), ) execute!(sim, Rodas4()) - @error PSID.get_global_state_map(sim.inputs) #GET SENSITIVITY FUNCTIONS f_forward, f_grad, _ = get_sensitivity_functions( @@ -546,11 +545,11 @@ end @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 grad_zero = f_grad(p, [p_ctrl], δ_gt) - #grad_nonzero_1 = f_grad(p * 1.01, [p_ctrl], δ_gt) - #grad_nonzero_2 = f_grad(p * 0.99, [p_ctrl], δ_gt) - #@test isapprox(grad_zero[1], 0.8876855633591412, atol = 1e-6) #should pass --> once we convert outside of the test. - #@test isapprox(grad_nonzero_1[1], 0.5946989856464833, atol = 1.0) - #@test isapprox(grad_nonzero_2[1], -0.9432527319604077; atol = 1.0) + grad_nonzero_1 = f_grad(p * 1.01, [p_ctrl], δ_gt) + grad_nonzero_2 = f_grad(p * 0.99, [p_ctrl], δ_gt) + @test isapprox(grad_zero[1], 0.8876855633591412, atol = 1e-6) #should pass --> once we convert outside of the test. + @test isapprox(grad_nonzero_1[1], 0.5946989856464833, atol = 1.0) + @test isapprox(grad_nonzero_2[1], -0.9432527319604077; atol = 1.0) finally @info("removing test files") rm(path; force = true, recursive = true) From 6f3f0238b6f323047182f960304b15496c899ada Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 7 Aug 2024 11:03:50 -0400 Subject: [PATCH 66/76] pass p to loss function --- src/base/sensitivity_analysis.jl | 14 ++++----- test/test_case_enzyme.jl | 49 +++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index cbb5cf841..52827eaf5 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -215,7 +215,7 @@ function get_sensitivity_functions( sol = solve_with_callback(prob_new, callbacks, solver) ix_t = unique(i -> sol.t[i], eachindex(sol.t)) states = [sol[ix, ix_t] for ix in state_ixs] - return f_loss(states, data) + return f_loss(p, states, data) end function f_Zygote( p, @@ -226,7 +226,7 @@ function get_sensitivity_functions( data, init_level, sys_reinit, - perts, + perts, ) p_new = sim_inputs.parameters p_new_buff = Zygote.Buffer(p_new) @@ -267,14 +267,14 @@ function get_sensitivity_functions( end sol = SciMLBase.solve(prob_new, solver; callback = callbacks) #Hack to avoid unique(i -> sol.t[i], eachindex(sol.t)) which mutates and is incompatible with Zygote: - ix_first = findfirst(x -> x == 1.0, sol.t) - ix_last = findlast(x -> x == 1.0, sol.t) + ix_first = findfirst(x -> x == pert.time, sol.t) + ix_last = findlast(x -> x == pert.time, sol.t) ix_t = vcat(1:ix_first, (ix_last + 1):(length(sol.t))) states = [sol[ix, ix_t] for ix in state_ixs] - return f_loss(states, data) + return f_loss(p, states, data) end function f_forward(p, perts, data) - callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) + callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) f_enzyme( p, x0, @@ -289,7 +289,7 @@ function get_sensitivity_functions( ) end function f_grad(p, perts, data) - callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) + callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) dp = Enzyme.make_zero(p) dx0 = Enzyme.make_zero(x0) dsys = Enzyme.make_zero(sys) diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index eaff6d9f4..89eb256a6 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -45,7 +45,7 @@ using PlotlyJS display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(states, δ_gt) + function f_loss(p, states, δ_gt) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -78,12 +78,27 @@ using PlotlyJS @test loss_non_zero_2 != 0.0 @test get_parameter_labels(sim, [("generator-102-1", :Shaft, :H)]) == ["generator-102-1.params.Shaft.H"] - grad_zero = f_grad(p, [s_change], δ_gt) - grad_nonzero_1 = f_grad([3.14], [s_change], δ_gt) - grad_nonzero_2 = f_grad([3.15], [s_change], δ_gt) - @test isapprox(grad_zero[1], 0.0, atol = 1.0) - @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) - @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) + @test isapprox(f_grad(p, [s_change], δ_gt)[1], -0.299332838697076, atol = 1e-3) + @test isapprox(f_grad([3.14], [s_change], δ_gt)[1], -8.174549313199039, atol = 1e-3) + @test isapprox(f_grad([3.15], [s_change], δ_gt)[1], 8.044840967274856; atol = 1e-3) + + #Add in parameter regularization to loss + function f_loss(p, states, δ_gt) + return sum(abs.(states[1] - δ_gt)) + sum(abs.(p)) + end + f_forward, f_grad, _ = get_sensitivity_functions( + sim, + [("generator-102-1", :Shaft, :H)], + [("generator-102-1", :δ)], + Rodas4(), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + @test isapprox(f_grad(p, [s_change], δ_gt)[1], 0.7006671613029241, atol = 1e-3) finally @info("removing test files") rm(path; force = true, recursive = true) @@ -115,7 +130,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(states, δ_gt) + function f_loss(p, states, δ_gt) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -183,7 +198,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(states, δ_gt) + function f_loss(p, states, δ_gt) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -246,7 +261,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(states, δ_gt) + function f_loss(p, states, δ_gt) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -336,7 +351,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(states, δ_gt) + function f_loss(p, states, δ_gt) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -412,7 +427,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(states, δ_gt) + function f_loss(p, states, δ_gt) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -500,7 +515,7 @@ end (0.0, 5.0), p_ctrl, ) - + #GET GROUND TRUTH DATA execute!(sim, Rodas4(); abstol = 1e-6, reltol = 1e-6, dtmax = 0.05, saveat = 0.05) res = read_results(sim) @@ -513,7 +528,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(states, δ_gt) + function f_loss(p, states, δ_gt) plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -555,7 +570,7 @@ end rm(path; force = true, recursive = true) end end -2+2 + #= #BELOW HERE: TESTS FOR SENSITIVITY OF DDES #NOTE: "Only the discretize-then-optimize methods are applicable to delay differential equations." @@ -622,7 +637,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(states, δ_gt) + function f_loss(p, states, δ_gt) plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -699,7 +714,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(states, δ_gt) + function f_loss(p, states, δ_gt) #plot_traces(δ, δ_gt) return sum(abs.(states[1] - δ_gt)) end From 9b9514ee4a018fa880fc2d5f1e3b2a8ab1c1f42b Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 7 Aug 2024 19:13:40 -0400 Subject: [PATCH 67/76] add option to force device_level --- src/base/sensitivity_analysis.jl | 7 ++- test/test_case_enzyme.jl | 77 ++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 52827eaf5..216151a55 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -134,12 +134,17 @@ function get_sensitivity_functions( state_data, solver, f_loss, - sys_reinit = false; + sys_reinit = false, + force_device_level = nothing; kwargs..., ) p_metadata = sim.inputs.parameters_metadata p = sim.inputs.parameters param_ixs, init_level = get_ix_and_level(p, p_metadata, param_data) + if force_device_level !== nothing + init_level = force_device_level + @warn "Forcing initialization level of $init_level regardless of parameters." + end if init_level === nothing return nothing end diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index 89eb256a6..e65249453 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -461,9 +461,80 @@ end grad_zero = f_grad(p, [s_change], δ_gt) grad_nonzero_1 = f_grad(p * 1.01, [s_change], δ_gt) grad_nonzero_2 = f_grad(p * 0.99, [s_change], δ_gt) - @test isapprox(grad_zero[1], 499.0, atol = 1.0) - @test isapprox(grad_nonzero_1[1], 500.0, atol = 1.0) - @test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) + @test isapprox(grad_zero[1], 499.3490613579809, atol = 1e-3) + @test isapprox(grad_nonzero_1[1], 500.17141744869343, atol = 1e-3) + @test isapprox(grad_nonzero_2[1], -498.73349996053315; atol = 1e-3) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + +@testset "Test Gradients - OMIB; Xd_p - force no init" begin + path = mktempdir() + try + omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + s_device = get_component(Source, omib_sys, "InfBus") + s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + s_change, + ) + + #GET GROUND TRUTH DATA + execute!(sim, Rodas4(); abstol = 1e-9, reltol = 1e-9, dtmax = 0.005, saveat = 0.005) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) + + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-102-1", :Machine, :Xd_p)]) + + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing + function f_loss(p, states, δ_gt) + #plot_traces(states[1], δ_gt) + return sum(abs.(states[1] - δ_gt)) + end + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + ) + execute!(sim, Rodas4()) + + #GET SENSITIVITY FUNCTIONS + f_forward, f_grad, _ = get_sensitivity_functions( + sim, + [("generator-102-1", :Machine, :Xd_p)], + [("generator-102-1", :δ)], + Rodas4(), + f_loss, + false, + PSID.INITIALIZED; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-9, + reltol = 1e-9, + dtmax = 0.005, + saveat = 0.005, + ) + loss_zero = f_forward(p, [s_change], δ_gt) + loss_non_zero_1 = f_forward(p * 1.01, [s_change], δ_gt) + loss_non_zero_2 = f_forward(p * 0.99, [s_change], δ_gt) + @test isapprox(loss_zero, 0.0, atol = 1e-9) + @test loss_non_zero_1 != 0.0 + @test loss_non_zero_2 != 0.0 + grad_zero = f_grad(p, [s_change], δ_gt) + grad_nonzero_1 = f_grad(p * 1.01, [s_change], δ_gt) + grad_nonzero_2 = f_grad(p * 0.99, [s_change], δ_gt) + @test isapprox(grad_zero[1], 496.9588401248536, atol = 1e-3) + @test isapprox(grad_nonzero_1[1], 496.450046454591, atol = 1e-3) + @test isapprox(grad_nonzero_2[1], -498.19053389100594; atol = 1e-3) finally @info("removing test files") rm(path; force = true, recursive = true) From 9f2c38eab069f08dc4ebbc93ff6149d7304b688c Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sat, 10 Aug 2024 17:54:35 -0400 Subject: [PATCH 68/76] add dde tests --- test/test_case_enzyme.jl | 104 +++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 59 deletions(-) diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index e65249453..cb8edd369 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -642,15 +642,13 @@ end end end -#= -#BELOW HERE: TESTS FOR SENSITIVITY OF DDES #NOTE: "Only the discretize-then-optimize methods are applicable to delay differential equations." function add_degov_to_omib!(omib_sys) gen = get_component(ThermalStandard, omib_sys, "generator-102-1") dyn_gen = get_component(DynamicGenerator, omib_sys, "generator-102-1") new_gov = PSY.DEGOV(; - T1 = 0.0, - T2 = 0.0, + T1 = 1.0, + T2 = 0.5, T3 = 0.0, K = 18.0, T4 = 12.0, @@ -673,10 +671,9 @@ function add_degov_to_omib!(omib_sys) add_component!(omib_sys, dyn_gen_new, gen) end - #@testset "Test Gradients - OMIB; H; Delays" begin +@testset "Test Gradients - OMIB; H; Delays" begin path = mktempdir() - #try - #EnzymeRules.inactive(::typeof(Base.hasproperty), args...) = nothing # To allow wrap_sol to work? --> causes gradient to b zero; bad idea to go marking functions invalid without clear reason. + try omib_sys = build_system(PSIDTestSystems, "psid_test_omib") s_device = get_component(Source, omib_sys, "InfBus") s_change = SourceBusVoltageChange(1.0, s_device, :V_ref, 1.02) @@ -685,18 +682,17 @@ end MassMatrixModel, omib_sys, pwd(), - (0.0, 5.0), #Inside of the delay time... + (0.0, 5.0), s_change, ) #GET GROUND TRUTH DATA execute!( sim, - MethodOfSteps(Rodas5(; autodiff = false)); - abstol = 1e-9, - reltol = 1e-9, - dtmax = 0.005, - saveat = 0.005, + MethodOfSteps(Rodas5()); + abstol = 1e-6, + reltol = 1e-6, + saveat = 0.05, ) res = read_results(sim) t, δ_gt = get_state_series(res, ("generator-102-1", :δ)) @@ -716,41 +712,35 @@ end MassMatrixModel, omib_sys, pwd(), - (0.0, 5.0), #Inside of the delay time... + (0.0, 5.0), ) - execute!(sim, MethodOfSteps(Rodas4()),) + execute!(sim, MethodOfSteps(Rodas4())) #GET SENSITIVITY FUNCTIONS f_forward, f_grad, _ = get_sensitivity_functions( sim, [("generator-102-1", :Shaft, :H)], [("generator-102-1", :δ)], - MethodOfSteps(Rodas4()), #; autodiff = false - #MethodOfSteps(QNDF(;autodiff=true)), + MethodOfSteps(Rodas5()), f_loss; sensealg = ForwardDiffSensitivity(), - abstol = 1e-6, # 1e-6 - reltol = 1e-6, # 1e-6 - # dtmax = 0.005, - saveat = 0.005, - ); - - # @error length(δ_gt) - loss_zero = f_forward(p, [s_change], δ_gt) + abstol = 1e-6, + reltol = 1e-6, + saveat = 0.05, + ) + loss_zero = f_forward(p, [s_change], δ_gt) loss_non_zero_1 = f_forward([5.2], [s_change], δ_gt) loss_non_zero_2 = f_forward(p, [s_change], δ_gt .* 2) - @test isapprox(loss_zero, 0.0, atol = 3e-3) - @test loss_non_zero_1 != 0.0 - @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, [s_change],δ_gt) - @error grad_zero - @test isapprox(grad_zero[1], 0.0, atol = 1e-12) - #finally - # @info("removing test files") - # rm(path; force = true, recursive = true) - #end -#end - -#Potential Rank Deficient Matrix Detected: Erorrs... + @test isapprox(loss_zero, 0.0, atol = 1e-6) + @test isapprox(loss_non_zero_1, 0.266806977990823, atol = 1e-6) + @test isapprox(loss_non_zero_2, 17.41277928345796, atol = 1e-6) + grad_zero = f_grad(p, [s_change], δ_gt) + @test isapprox(grad_zero[1], -0.034893046793070925, atol = 1e-9) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + @testset "Test Gradients - OMIB; Xd_p; delays" begin path = mktempdir() try @@ -762,17 +752,16 @@ end MassMatrixModel, omib_sys, path, - (0.0, 0.05), - #s_change, + (0.0, 5.0), + s_change, ) #GET GROUND TRUTH DATA execute!( sim, - MethodOfSteps(Rodas4()); + MethodOfSteps(Rodas5()); abstol = 1e-9, reltol = 1e-9, - #dtmax = 0.005, saveat = 0.005, ) res = read_results(sim) @@ -786,7 +775,7 @@ end end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing function f_loss(p, states, δ_gt) - #plot_traces(δ, δ_gt) + #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -795,31 +784,28 @@ end sim, [("generator-102-1", :Machine, :Xd_p)], [("generator-102-1", :δ)], - MethodOfSteps(Rodas4()), + MethodOfSteps(Rodas5()), f_loss; sensealg = ForwardDiffSensitivity(), abstol = 1e-6, reltol = 1e-6, - # dtmax = 0.005, saveat = 0.005, ) - loss_zero = f_forward(p, δ_gt) - #loss_non_zero_1 = f_forward(p * 1.01, δ_gt) - #loss_non_zero_2 = f_forward(p * 0.99, δ_gt) - #@test isapprox(loss_zero, 0.0, atol = 1e-9) - #@test loss_non_zero_1 != 0.0 - #@test loss_non_zero_2 != 0.0 - #grad_zero = f_grad(p, δ_gt) - #grad_nonzero_1 = f_grad(p * 1.01, δ_gt) - #grad_nonzero_2 = f_grad(p * 0.99, δ_gt) - #@test isapprox(grad_zero[1], 497, atol = 1.0) - #@test isapprox(grad_nonzero_1[1], 499.0, atol = 1.0) - #@test isapprox(grad_nonzero_2[1], -498.0; atol = 1.0) + loss_zero = f_forward(p, [s_change], δ_gt) + loss_non_zero_1 = f_forward(p * 1.01, [s_change], δ_gt) + loss_non_zero_2 = f_forward(p * 0.99, [s_change], δ_gt) + @test isapprox(loss_zero, 0.0, atol = 0.02) + @test isapprox(loss_non_zero_1, 1.4914986021363859, atol = 1e-6) + @test isapprox(loss_non_zero_2, 1.489669782933298, atol = 1e-6) + grad_zero = f_grad(p, [s_change], δ_gt) + grad_nonzero_1 = f_grad(p * 1.01, [s_change], δ_gt) + grad_nonzero_2 = f_grad(p * 0.99, [s_change], δ_gt) + @test isapprox(grad_zero[1], -5.337145710251008, atol = 1e-6) + @test isapprox(grad_nonzero_1[1], 500.0118950662703, atol = 1e-6) + @test isapprox(grad_nonzero_2[1], -498.56135720277706; atol = 1e-6) finally @info("removing test files") rm(path; force = true, recursive = true) end end - - =# From c12582ca31010e7e8d65a229037b62bc9864408a Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 12 Aug 2024 19:11:25 -0400 Subject: [PATCH 69/76] add functions for _get_refs to overload for surrogates --- src/base/sensitivity_analysis.jl | 10 +- src/base/simulation_inputs.jl | 176 +++++++++++++++++-------------- 2 files changed, 101 insertions(+), 85 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 216151a55..b20a4fdd7 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -272,9 +272,13 @@ function get_sensitivity_functions( end sol = SciMLBase.solve(prob_new, solver; callback = callbacks) #Hack to avoid unique(i -> sol.t[i], eachindex(sol.t)) which mutates and is incompatible with Zygote: - ix_first = findfirst(x -> x == pert.time, sol.t) - ix_last = findlast(x -> x == pert.time, sol.t) - ix_t = vcat(1:ix_first, (ix_last + 1):(length(sol.t))) + if sol.t[end] > pert.time + ix_first = findfirst(x -> x == pert.time, sol.t) + ix_last = findlast(x -> x == pert.time, sol.t) + ix_t = vcat(1:ix_first, (ix_last + 1):(length(sol.t))) + else + ix_t = vact(1:length(sol.t)) + end states = [sol[ix, ix_t] for ix in state_ixs] return f_loss(p, states, data) end diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index 3182d0258..a6074ec0d 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -218,46 +218,46 @@ end return initial_parameters end =# +function _get_refs_metadata(x) + return (;) +end + +function _get_refs_metadata(wrapped_device::DynamicWrapper) + return ( + V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + ω_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + P_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + Q_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + ) +end + +function _get_refs_metadata(wrapped_device::StaticLoadWrapper) + return ( + V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + θ_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + P_power = ParamsMetadata(DEVICE_SETPOINT, false, true), + P_current = ParamsMetadata(DEVICE_SETPOINT, false, true), + P_impedance = ParamsMetadata(DEVICE_SETPOINT, false, true), + Q_power = ParamsMetadata(DEVICE_SETPOINT, false, true), + Q_current = ParamsMetadata(DEVICE_SETPOINT, false, true), + Q_impedance = ParamsMetadata(DEVICE_SETPOINT, false, true), + ) +end + +function _get_refs_metadata(wrapped_device::StaticWrapper) + return ( + V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + θ_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + P_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + Q_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), + ) +end + function _add_parameters_metadata(parameter_metadata, wrapped_devices) for wrapped_device in wrapped_devices p_metadata = get_params_metadata(wrapped_device) name = _get_wrapper_name(wrapped_device) - if isa(wrapped_device, DynamicWrapper) - # Consider the special case when the static device is StandardLoad - static_device = get_static_device(wrapped_device) - if isa(static_device, PSY.StandardLoad) - reactive_power = PF.get_total_q(static_device) - else - reactive_power = PSY.get_reactive_power(static_device) - end - refs_metadata = ( - V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), - ω_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), - P_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), - Q_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), - ) - elseif isa(wrapped_device, StaticWrapper) - refs_metadata = ( - V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), - θ_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), - P_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), - Q_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), - ) - - elseif isa(wrapped_device, StaticLoadWrapper) - refs_metadata = ( - V_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), - θ_ref = ParamsMetadata(DEVICE_SETPOINT, false, true), - P_power = ParamsMetadata(DEVICE_SETPOINT, false, true), - P_current = ParamsMetadata(DEVICE_SETPOINT, false, true), - P_impedance = ParamsMetadata(DEVICE_SETPOINT, false, true), - Q_power = ParamsMetadata(DEVICE_SETPOINT, false, true), - Q_current = ParamsMetadata(DEVICE_SETPOINT, false, true), - Q_impedance = ParamsMetadata(DEVICE_SETPOINT, false, true), - ) - else - refs_metadata = (;) - end + refs_metadata = _get_refs_metadata(wrapped_device) parameter_metadata = ComponentArrays.ComponentVector( parameter_metadata; name => ( @@ -269,56 +269,68 @@ function _add_parameters_metadata(parameter_metadata, wrapped_devices) return parameter_metadata end +function _get_refs(x) + return (;) +end + +function _get_refs(wrapped_device::DynamicWrapper) + static_device = get_static_device(wrapped_device) + if isa(static_device, PSY.StandardLoad) + reactive_power = PF.get_total_q(static_device) + else + reactive_power = PSY.get_reactive_power(static_device) + end + refs = ( + V_ref = PSY.get_V_ref(get_device(wrapped_device)), + ω_ref = PSY.get_ω_ref(get_device(wrapped_device)), + P_ref = PSY.get_P_ref(get_device(wrapped_device)), + Q_ref = reactive_power, + ) + return refs +end + +function _get_refs(wrapped_device::StaticLoadWrapper) + refs = ( + V_ref = get_V_ref(wrapped_device), + θ_ref = get_θ_ref(wrapped_device), + P_power = get_P_power(wrapped_device), + P_current = get_P_current(wrapped_device), + P_impedance = get_P_impedance(wrapped_device), + Q_power = get_Q_power(wrapped_device), + Q_current = get_Q_current(wrapped_device), + Q_impedance = get_Q_impedance(wrapped_device), + ) + return refs +end + +function _get_refs(wrapped_device::StaticWrapper) + device = get_device(wrapped_device) + bus = PSY.get_bus(device) + refs = ( + V_ref = PSY.get_magnitude(bus), + θ_ref = PSY.get_angle(bus), + P_ref = PSY.get_active_power(device), + Q_ref = PSY.get_reactive_power(device), + ) + return refs +end + +function _get_refs(wrapped_device::StaticWrapper{PSY.Source}) + device = get_device(wrapped_device) + refs = ( + V_ref = PSY.get_internal_voltage(device), + θ_ref = PSY.get_internal_angle(device), + P_ref = PSY.get_active_power(device), + Q_ref = PSY.get_reactive_power(device), + ) + return refs +end + function _add_parameters(initial_parameters, wrapped_devices) for wrapped_device in wrapped_devices p = get_params(wrapped_device) name = _get_wrapper_name(wrapped_device) - if isa(wrapped_device, DynamicWrapper) - # Consider the special case when the static device is StandardLoad - static_device = get_static_device(wrapped_device) - if isa(static_device, PSY.StandardLoad) - reactive_power = PF.get_total_q(static_device) - else - reactive_power = PSY.get_reactive_power(static_device) - end - refs = ( - V_ref = PSY.get_V_ref(get_device(wrapped_device)), - ω_ref = PSY.get_ω_ref(get_device(wrapped_device)), - P_ref = PSY.get_P_ref(get_device(wrapped_device)), - Q_ref = reactive_power, - ) - elseif isa(wrapped_device, StaticWrapper) - device = get_device(wrapped_device) - if typeof(device) <: PSY.Source - refs = ( - V_ref = PSY.get_internal_voltage(device), - θ_ref = PSY.get_internal_angle(device), - P_ref = PSY.get_active_power(device), - Q_ref = PSY.get_reactive_power(device), - ) - else - bus = PSY.get_bus(device) - refs = ( - V_ref = PSY.get_magnitude(bus), - θ_ref = PSY.get_angle(bus), - P_ref = PSY.get_active_power(device), - Q_ref = PSY.get_reactive_power(device), - ) - end - elseif isa(wrapped_device, StaticLoadWrapper) - refs = ( - V_ref = get_V_ref(wrapped_device), - θ_ref = get_θ_ref(wrapped_device), - P_power = get_P_power(wrapped_device), - P_current = get_P_current(wrapped_device), - P_impedance = get_P_impedance(wrapped_device), - Q_power = get_Q_power(wrapped_device), - Q_current = get_Q_current(wrapped_device), - Q_impedance = get_Q_impedance(wrapped_device), - ) - else - refs = (;) - end + refs = _get_refs(wrapped_device) initial_parameters = ComponentArrays.ComponentVector( initial_parameters; name => ( From f07655eb27cc6d129f7162937e9ef65640980f9f Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 14 Aug 2024 09:50:57 -0400 Subject: [PATCH 70/76] generalize get_setpoints --- src/base/simulation_inputs.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/base/simulation_inputs.jl b/src/base/simulation_inputs.jl index a6074ec0d..9e0caaf4d 100644 --- a/src/base/simulation_inputs.jl +++ b/src/base/simulation_inputs.jl @@ -621,10 +621,9 @@ function get_setpoints(inputs::SimulationInputs) for w in get_dynamic_injectors(inputs) wrapped_device_name = _get_wrapper_name(w) dic_w = Dict{String, Float64}() - dic_w["P_ref"] = p[wrapped_device_name][:refs][:P_ref] - dic_w["Q_ref"] = p[wrapped_device_name][:refs][:Q_ref] - dic_w["ω_ref"] = p[wrapped_device_name][:refs][:ω_ref] - dic_w["V_ref"] = p[wrapped_device_name][:refs][:V_ref] + for ref_name in ComponentArrays.labels( p[wrapped_device_name][:refs]) + dic_w[ref_name] = p[wrapped_device_name][:refs][ref_name] + end dic[PSY.get_name(w)] = dic_w end return dic From 9e6424bb4c360d239b1e288bd138f4ccde0d3857 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Tue, 27 Aug 2024 12:06:27 -0600 Subject: [PATCH 71/76] workarounds for ml surrogates --- src/base/sensitivity_analysis.jl | 10 +++- test/test_case_enzyme.jl | 95 ++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index b20a4fdd7..fae8c42f8 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -128,6 +128,12 @@ function convert_perturbations_to_callbacks(sys, sim_inputs, perturbations) return callbacks, tstops end +#Dummy function that is overloaded in PowerSimulationsDynamicsSurrogates. +#Eventually transition to EnzymeAdjoint() and remove Zygote altogether: https://github.com/SciML/OrdinaryDiffEq.jl/pull/2282 +function _non_mutating_initialization_of_ml_surrogates(x0, p_new, sim_inputs) + return x0, p_new +end + function get_sensitivity_functions( sim, param_data, @@ -256,8 +262,8 @@ function get_sensitivity_functions( @error "POWERFLOW AND DEVICES -- not yet supported" #_initialize_powerflow_and_devices!(x0, inputs, sys) elseif init_level == DEVICES_ONLY - @error "Reinitializing not supported with Zygote" - _initialize_devices_only!(x0, sim_inputs) #Mutation + @error "Reinitializing of most devices not supported with Zygote" + x0, p_new = _non_mutating_initialization_of_ml_surrogates(x0, p_new, sim_inputs) elseif init_level == INITIALIZED @info "I.C.s not impacted by parameter change" end diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index cb8edd369..b29043e35 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -741,6 +741,101 @@ end end end +#Test delays + reversediffAdjoint. +@testset "Test Gradients - OMIB; H; PerturbState" begin + path = mktempdir() + try + omib_sys = build_system(PSIDTestSystems, "psid_test_omib") + s_device = get_component(Source, omib_sys, "InfBus") + p_state = PerturbState(1.0, 5, 0.18) + add_degov_to_omib!(omib_sys) + + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + p_state, + ) + #GET GROUND TRUTH DATA + execute!(sim, MethodOfSteps(Rodas5()); abstol = 1e-6, reltol = 1e-6, dtmax = 0.05, saveat = 0.05) + res = read_results(sim) + t, δ_gt = get_state_series(res, ("generator-102-1", :δ); unique_timestamps = true) #Avoid filtering of repeated timesteps + #GET PARAMETER VALUES + p = get_parameter_values(sim, [("generator-102-1", :Shaft, :H)]) + + function plot_traces(δ, δ_gt) + display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) + end + EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing + function f_loss(p, states, δ_gt) + #plot_traces(states[1], δ_gt) + return sum(abs.(states[1] - δ_gt)) + end + sim = Simulation!( + MassMatrixModel, + omib_sys, + path, + (0.0, 5.0), + ) + execute!(sim, MethodOfSteps(Rodas5())) + f_forward, f_grad, f_zygote_forward = get_sensitivity_functions( + sim, + [("generator-102-1", :Shaft, :H)], + [("generator-102-1", :δ)], + MethodOfSteps(Rodas5(autodiff=false)), + f_loss; + sensealg = ForwardDiffSensitivity(), + abstol = 1e-6, + reltol = 1e-6, + dtmax = 0.05, + saveat = 0.05, + ) + @test f_forward(p, [p_state], δ_gt) == + f_zygote_forward(p, [p_state], δ_gt) + @test f_forward([3.14], [p_state], δ_gt) == + f_zygote_forward([3.14], [p_state], δ_gt) + @test f_forward([3.15], [p_state], δ_gt) == + f_zygote_forward([3.15], [p_state], δ_gt) + #@test f_grad(p, [p_state], δ_gt) == + # Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), p)[1] + @test Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), p)[1][1] == -10.336102683050685 + + _, _, f_zygote_forward = get_sensitivity_functions( + sim, + [("generator-102-1", :Shaft, :H)], + [("generator-102-1", :δ)], + MethodOfSteps(Rodas5(autodiff=false)), + f_loss; + sensealg = ReverseDiffAdjoint(), + abstol = 1e-6, + reltol = 1e-6, + dtmax = 0.05, + saveat = 0.05, + ) + + + @test isapprox( + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), p)[1][1], + -15.973318599159727, + atol = 1e-6, + ) + @test isapprox( + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), [3.14])[1][1], + -25.735942518785052, + atol = 1e-6, + ) + @test isapprox( + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), [3.15])[1][1], + 25.684384617470563, + atol = 1e-6, + ) + finally + @info("removing test files") + rm(path; force = true, recursive = true) + end +end + @testset "Test Gradients - OMIB; Xd_p; delays" begin path = mktempdir() try From eb171d8aef8cd0992d188b33a746be7eb746460c Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sun, 1 Sep 2024 22:11:44 -0600 Subject: [PATCH 72/76] aux input to f_loss --- src/base/sensitivity_analysis.jl | 15 ++- test/test_case_enzyme.jl | 158 +++++++++++++++---------------- 2 files changed, 89 insertions(+), 84 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index fae8c42f8..464641615 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -196,6 +196,7 @@ function get_sensitivity_functions( sys_reinit, callbacks, tstops, + aux, ) p_new = sim_inputs.parameters p_new[param_ixs] .= p @@ -226,7 +227,7 @@ function get_sensitivity_functions( sol = solve_with_callback(prob_new, callbacks, solver) ix_t = unique(i -> sol.t[i], eachindex(sol.t)) states = [sol[ix, ix_t] for ix in state_ixs] - return f_loss(p, states, data) + return f_loss(p, states, data, aux) end function f_Zygote( p, @@ -238,6 +239,7 @@ function get_sensitivity_functions( init_level, sys_reinit, perts, + aux, ) p_new = sim_inputs.parameters p_new_buff = Zygote.Buffer(p_new) @@ -286,9 +288,9 @@ function get_sensitivity_functions( ix_t = vact(1:length(sol.t)) end states = [sol[ix, ix_t] for ix in state_ixs] - return f_loss(p, states, data) + return f_loss(p, states, data, aux) end - function f_forward(p, perts, data) + function f_forward(p, perts, data, aux) callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) f_enzyme( p, @@ -301,9 +303,10 @@ function get_sensitivity_functions( sys_reinit, callbacks, tstops, + aux, ) end - function f_grad(p, perts, data) + function f_grad(p, perts, data, aux) callbacks, tstops = convert_perturbations_to_callbacks(sys, sim_inputs, perts) dp = Enzyme.make_zero(p) dx0 = Enzyme.make_zero(x0) @@ -328,10 +331,11 @@ function get_sensitivity_functions( Enzyme.Const(sys_reinit), Enzyme.Duplicated(callbacks, dcallbacks), Enzyme.Duplicated(tstops, dtstops), + Enzyme.Const(aux), ) return dp end - function f_forward_zygote(p, perts, data) + function f_forward_zygote(p, perts, data, aux) f_Zygote( p, x0, @@ -342,6 +346,7 @@ function get_sensitivity_functions( init_level, sys_reinit, perts, + aux, ) end f_forward, f_grad, f_forward_zygote diff --git a/test/test_case_enzyme.jl b/test/test_case_enzyme.jl index b29043e35..76a71e89a 100644 --- a/test/test_case_enzyme.jl +++ b/test/test_case_enzyme.jl @@ -45,7 +45,7 @@ using PlotlyJS display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -70,20 +70,20 @@ using PlotlyJS dtmax = 0.005, saveat = 0.005, ) - loss_zero = f_forward(p, [s_change], δ_gt) - loss_non_zero_1 = f_forward([3.2], [s_change], δ_gt) - loss_non_zero_2 = f_forward(p, [s_change], δ_gt .* 2) + loss_zero = f_forward(p, [s_change], δ_gt, []) + loss_non_zero_1 = f_forward([3.2], [s_change], δ_gt, []) + loss_non_zero_2 = f_forward(p, [s_change], δ_gt .* 2, []) @test loss_zero == 0.0 @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 @test get_parameter_labels(sim, [("generator-102-1", :Shaft, :H)]) == ["generator-102-1.params.Shaft.H"] - @test isapprox(f_grad(p, [s_change], δ_gt)[1], -0.299332838697076, atol = 1e-3) - @test isapprox(f_grad([3.14], [s_change], δ_gt)[1], -8.174549313199039, atol = 1e-3) - @test isapprox(f_grad([3.15], [s_change], δ_gt)[1], 8.044840967274856; atol = 1e-3) + @test isapprox(f_grad(p, [s_change], δ_gt, [])[1], -0.299332838697076, atol = 1e-3) + @test isapprox(f_grad([3.14], [s_change], δ_gt, [])[1], -8.174549313199039, atol = 1e-3) + @test isapprox(f_grad([3.15], [s_change], δ_gt, [])[1], 8.044840967274856; atol = 1e-3) #Add in parameter regularization to loss - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) return sum(abs.(states[1] - δ_gt)) + sum(abs.(p)) end f_forward, f_grad, _ = get_sensitivity_functions( @@ -98,7 +98,7 @@ using PlotlyJS dtmax = 0.005, saveat = 0.005, ) - @test isapprox(f_grad(p, [s_change], δ_gt)[1], 0.7006671613029241, atol = 1e-3) + @test isapprox(f_grad(p, [s_change], δ_gt, [])[1], 0.7006671613029241, atol = 1e-3) finally @info("removing test files") rm(path; force = true, recursive = true) @@ -130,7 +130,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -155,15 +155,15 @@ end dtmax = 0.005, saveat = 0.005, ) - loss_zero = f_forward(p, [s_change], δ_gt) - loss_non_zero_1 = f_forward([3.2], [s_change], δ_gt) - loss_non_zero_2 = f_forward(p, [s_change], δ_gt .* 2) + loss_zero = f_forward(p, [s_change], δ_gt, []) + loss_non_zero_1 = f_forward([3.2], [s_change], δ_gt, []) + loss_non_zero_2 = f_forward(p, [s_change], δ_gt .* 2, []) @test loss_zero == 0.0 @test loss_non_zero_1 == 0.36199910927656687 @test loss_non_zero_2 == 172.66293171283323 - grad_zero = f_grad(p, [s_change], δ_gt) - grad_nonzero_1 = f_grad([3.14], [s_change], δ_gt) - grad_nonzero_2 = f_grad([3.15], [s_change], δ_gt) + grad_zero = f_grad(p, [s_change], δ_gt, []) + grad_nonzero_1 = f_grad([3.14], [s_change], δ_gt, []) + grad_nonzero_2 = f_grad([3.15], [s_change], δ_gt, []) @test isapprox(grad_zero[1], -1.0, atol = 1.0) @test isapprox(grad_nonzero_1[1], -8.0, atol = 1.0) @test isapprox(grad_nonzero_2[1], 8.0; atol = 1.0) @@ -198,7 +198,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -222,13 +222,13 @@ end dtmax = 0.005, saveat = 0.005, ) - loss_zero = f_forward(p, [s_change], δ_gt) - loss_non_zero_1 = f_forward(p .* 1.01, [s_change], δ_gt) + loss_zero = f_forward(p, [s_change], δ_gt, []) + loss_non_zero_1 = f_forward(p .* 1.01, [s_change], δ_gt, []) @test isapprox(loss_zero, 0.0, atol = 1e-9) @test isapprox(loss_non_zero_1, 1.49, atol = 1e-3) - grad_zero = f_grad(p, [s_change], δ_gt) + grad_zero = f_grad(p, [s_change], δ_gt, []) @test isapprox(sum(grad_zero), 524.5865384550988, atol = 1e-3) finally @info("removing test files") @@ -261,7 +261,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -284,14 +284,14 @@ end dtmax = 0.005, saveat = 0.005, ) - @test f_forward(p, [p_state], δ_gt) == - f_zygote_forward(p, [p_state], δ_gt) - @test f_forward([3.14], [p_state], δ_gt) == - f_zygote_forward([3.14], [p_state], δ_gt) - @test f_forward([3.15], [p_state], δ_gt) == - f_zygote_forward([3.15], [p_state], δ_gt) - @test f_grad(p, [p_state], δ_gt) == - Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), p)[1] + @test f_forward(p, [p_state], δ_gt, []) == + f_zygote_forward(p, [p_state], δ_gt, []) + @test f_forward([3.14], [p_state], δ_gt, []) == + f_zygote_forward([3.14], [p_state], δ_gt, []) + @test f_forward([3.15], [p_state], δ_gt, []) == + f_zygote_forward([3.15], [p_state], δ_gt, []) + @test f_grad(p, [p_state], δ_gt, []) == + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt, []), p)[1] _, _, f_zygote_forward = get_sensitivity_functions( sim, @@ -306,17 +306,17 @@ end saveat = 0.005, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), p)[1][1], + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt, []), p)[1][1], -223.7406308892161, atol = 1e-6, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), [3.14])[1][1], + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt, []), [3.14])[1][1], -256.88284936919246, atol = 1e-6, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), [3.15])[1][1], + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt, []), [3.15])[1][1], 256.36101155595964, atol = 1e-6, ) @@ -351,7 +351,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -384,8 +384,8 @@ end return false end optfun = OptimizationFunction{false}( - (u, p) -> f_forward(u, [s_change], δ_gt); - grad = (res, u, p) -> res .= f_grad(u, [s_change], δ_gt), + (u, p) -> f_forward(u, [s_change], δ_gt, []); + grad = (res, u, p) -> res .= f_grad(u, [s_change], δ_gt, []), ) optprob = OptimizationProblem{false}(optfun, [3.14]) sol = Optimization.solve( @@ -427,7 +427,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -452,15 +452,15 @@ end dtmax = 0.005, saveat = 0.005, ) - loss_zero = f_forward(p, [s_change], δ_gt) - loss_non_zero_1 = f_forward(p * 1.01, [s_change], δ_gt) - loss_non_zero_2 = f_forward(p * 0.99, [s_change], δ_gt) + loss_zero = f_forward(p, [s_change], δ_gt, []) + loss_non_zero_1 = f_forward(p * 1.01, [s_change], δ_gt, []) + loss_non_zero_2 = f_forward(p * 0.99, [s_change], δ_gt, []) @test isapprox(loss_zero, 0.0, atol = 1e-9) @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, [s_change], δ_gt) - grad_nonzero_1 = f_grad(p * 1.01, [s_change], δ_gt) - grad_nonzero_2 = f_grad(p * 0.99, [s_change], δ_gt) + grad_zero = f_grad(p, [s_change], δ_gt, []) + grad_nonzero_1 = f_grad(p * 1.01, [s_change], δ_gt, []) + grad_nonzero_2 = f_grad(p * 0.99, [s_change], δ_gt, []) @test isapprox(grad_zero[1], 499.3490613579809, atol = 1e-3) @test isapprox(grad_nonzero_1[1], 500.17141744869343, atol = 1e-3) @test isapprox(grad_nonzero_2[1], -498.73349996053315; atol = 1e-3) @@ -496,7 +496,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -523,15 +523,15 @@ end dtmax = 0.005, saveat = 0.005, ) - loss_zero = f_forward(p, [s_change], δ_gt) - loss_non_zero_1 = f_forward(p * 1.01, [s_change], δ_gt) - loss_non_zero_2 = f_forward(p * 0.99, [s_change], δ_gt) + loss_zero = f_forward(p, [s_change], δ_gt, []) + loss_non_zero_1 = f_forward(p * 1.01, [s_change], δ_gt, []) + loss_non_zero_2 = f_forward(p * 0.99, [s_change], δ_gt, []) @test isapprox(loss_zero, 0.0, atol = 1e-9) @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, [s_change], δ_gt) - grad_nonzero_1 = f_grad(p * 1.01, [s_change], δ_gt) - grad_nonzero_2 = f_grad(p * 0.99, [s_change], δ_gt) + grad_zero = f_grad(p, [s_change], δ_gt, []) + grad_nonzero_1 = f_grad(p * 1.01, [s_change], δ_gt, []) + grad_nonzero_2 = f_grad(p * 0.99, [s_change], δ_gt, []) @test isapprox(grad_zero[1], 496.9588401248536, atol = 1e-3) @test isapprox(grad_nonzero_1[1], 496.450046454591, atol = 1e-3) @test isapprox(grad_nonzero_2[1], -498.19053389100594; atol = 1e-3) @@ -599,7 +599,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -624,15 +624,15 @@ end dtmax = 0.05, saveat = 0.05, ) - loss_zero = f_forward(p, [p_ctrl], δ_gt) - loss_non_zero_1 = f_forward(p * 1.01, [p_ctrl], δ_gt) - loss_non_zero_2 = f_forward(p * 0.99, [p_ctrl], δ_gt) + loss_zero = f_forward(p, [p_ctrl], δ_gt, []) + loss_non_zero_1 = f_forward(p * 1.01, [p_ctrl], δ_gt, []) + loss_non_zero_2 = f_forward(p * 0.99, [p_ctrl], δ_gt, []) @test isapprox(loss_zero, 0.0, atol = 2e-9) @test loss_non_zero_1 != 0.0 @test loss_non_zero_2 != 0.0 - grad_zero = f_grad(p, [p_ctrl], δ_gt) - grad_nonzero_1 = f_grad(p * 1.01, [p_ctrl], δ_gt) - grad_nonzero_2 = f_grad(p * 0.99, [p_ctrl], δ_gt) + grad_zero = f_grad(p, [p_ctrl], δ_gt, []) + grad_nonzero_1 = f_grad(p * 1.01, [p_ctrl], δ_gt, []) + grad_nonzero_2 = f_grad(p * 0.99, [p_ctrl], δ_gt, []) @test isapprox(grad_zero[1], 0.8876855633591412, atol = 1e-6) #should pass --> once we convert outside of the test. @test isapprox(grad_nonzero_1[1], 0.5946989856464833, atol = 1.0) @test isapprox(grad_nonzero_2[1], -0.9432527319604077; atol = 1.0) @@ -704,7 +704,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -727,13 +727,13 @@ end reltol = 1e-6, saveat = 0.05, ) - loss_zero = f_forward(p, [s_change], δ_gt) - loss_non_zero_1 = f_forward([5.2], [s_change], δ_gt) - loss_non_zero_2 = f_forward(p, [s_change], δ_gt .* 2) + loss_zero = f_forward(p, [s_change], δ_gt, []) + loss_non_zero_1 = f_forward([5.2], [s_change], δ_gt, []) + loss_non_zero_2 = f_forward(p, [s_change], δ_gt .* 2, []) @test isapprox(loss_zero, 0.0, atol = 1e-6) @test isapprox(loss_non_zero_1, 0.266806977990823, atol = 1e-6) @test isapprox(loss_non_zero_2, 17.41277928345796, atol = 1e-6) - grad_zero = f_grad(p, [s_change], δ_gt) + grad_zero = f_grad(p, [s_change], δ_gt, []) @test isapprox(grad_zero[1], -0.034893046793070925, atol = 1e-9) finally @info("removing test files") @@ -768,7 +768,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -791,15 +791,15 @@ end dtmax = 0.05, saveat = 0.05, ) - @test f_forward(p, [p_state], δ_gt) == - f_zygote_forward(p, [p_state], δ_gt) - @test f_forward([3.14], [p_state], δ_gt) == - f_zygote_forward([3.14], [p_state], δ_gt) - @test f_forward([3.15], [p_state], δ_gt) == - f_zygote_forward([3.15], [p_state], δ_gt) + @test f_forward(p, [p_state], δ_gt, []) == + f_zygote_forward(p, [p_state], δ_gt, []) + @test f_forward([3.14], [p_state], δ_gt, []) == + f_zygote_forward([3.14], [p_state], δ_gt, []) + @test f_forward([3.15], [p_state], δ_gt, []) == + f_zygote_forward([3.15], [p_state], δ_gt, []) #@test f_grad(p, [p_state], δ_gt) == # Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), p)[1] - @test Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), p)[1][1] == -10.336102683050685 + @test Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt, []), p)[1][1] == -10.336102683050685 _, _, f_zygote_forward = get_sensitivity_functions( sim, @@ -816,17 +816,17 @@ end @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), p)[1][1], + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt, []), p)[1][1], -15.973318599159727, atol = 1e-6, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), [3.14])[1][1], + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt, []), [3.14])[1][1], -25.735942518785052, atol = 1e-6, ) @test isapprox( - Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt), [3.15])[1][1], + Zygote.gradient(p -> f_zygote_forward(p, [p_state], δ_gt, []), [3.15])[1][1], 25.684384617470563, atol = 1e-6, ) @@ -869,7 +869,7 @@ end display(plot([scatter(; y = δ_gt), scatter(; y = δ)])) end EnzymeRules.inactive(::typeof(plot_traces), args...) = nothing - function f_loss(p, states, δ_gt) + function f_loss(p, states, δ_gt, aux) #plot_traces(states[1], δ_gt) return sum(abs.(states[1] - δ_gt)) end @@ -887,15 +887,15 @@ end saveat = 0.005, ) - loss_zero = f_forward(p, [s_change], δ_gt) - loss_non_zero_1 = f_forward(p * 1.01, [s_change], δ_gt) - loss_non_zero_2 = f_forward(p * 0.99, [s_change], δ_gt) + loss_zero = f_forward(p, [s_change], δ_gt, []) + loss_non_zero_1 = f_forward(p * 1.01, [s_change], δ_gt, []) + loss_non_zero_2 = f_forward(p * 0.99, [s_change], δ_gt, []) @test isapprox(loss_zero, 0.0, atol = 0.02) @test isapprox(loss_non_zero_1, 1.4914986021363859, atol = 1e-6) @test isapprox(loss_non_zero_2, 1.489669782933298, atol = 1e-6) - grad_zero = f_grad(p, [s_change], δ_gt) - grad_nonzero_1 = f_grad(p * 1.01, [s_change], δ_gt) - grad_nonzero_2 = f_grad(p * 0.99, [s_change], δ_gt) + grad_zero = f_grad(p, [s_change], δ_gt, []) + grad_nonzero_1 = f_grad(p * 1.01, [s_change], δ_gt, []) + grad_nonzero_2 = f_grad(p * 0.99, [s_change], δ_gt, []) @test isapprox(grad_zero[1], -5.337145710251008, atol = 1e-6) @test isapprox(grad_nonzero_1[1], 500.0118950662703, atol = 1e-6) @test isapprox(grad_nonzero_2[1], -498.56135720277706; atol = 1e-6) From 072a62b712b4addaad6cb6ea120b8f7029ac1708 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Wed, 4 Sep 2024 13:32:26 -0600 Subject: [PATCH 73/76] convert some @errors to @warns --- src/base/sensitivity_analysis.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 464641615..058eb727d 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -251,7 +251,7 @@ function get_sensitivity_functions( end p_new = copy(p_new_buff) #Converting perturbations to callbacks, restore after : https://github.com/EnzymeAD/Enzyme.jl/issues/1650 - @error "Zygote assumes single perturbation" + @warn "Zygote assumes single perturbation" cb = Vector{SciMLBase.DiscreteCallback}(undef, 1) pert = perts[1] condition = (x, t, integrator) -> t in [pert.time] @@ -264,7 +264,7 @@ function get_sensitivity_functions( @error "POWERFLOW AND DEVICES -- not yet supported" #_initialize_powerflow_and_devices!(x0, inputs, sys) elseif init_level == DEVICES_ONLY - @error "Reinitializing of most devices not supported with Zygote" + @warn "Reinitializing of most devices not supported with Zygote" x0, p_new = _non_mutating_initialization_of_ml_surrogates(x0, p_new, sim_inputs) elseif init_level == INITIALIZED @info "I.C.s not impacted by parameter change" From b4b7bf9841b5ae04f7aa674c61ccf5f659a4d39e Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Thu, 5 Sep 2024 13:41:23 -0600 Subject: [PATCH 74/76] parameter typo --- src/utils/parameters.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/parameters.jl b/src/utils/parameters.jl index 4846db67e..e9f492156 100644 --- a/src/utils/parameters.jl +++ b/src/utils/parameters.jl @@ -985,7 +985,7 @@ get_params(x::PSY.SteamTurbineGov1) = ( get_params_metadata(::PSY.SteamTurbineGov1) = ( R = ParamsMetadata(DEVICE_PARAM, false, true), T1 = ParamsMetadata(DEVICE_PARAM, false, true), - valve_position = ( + valve_position_limits = ( min = ParamsMetadata(DEVICE_PARAM, false, true), max = ParamsMetadata(DEVICE_PARAM, false, true), ), From aabf6b8832cff741b8edd426006dca32d49c87c8 Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Sun, 8 Sep 2024 15:02:28 -0600 Subject: [PATCH 75/76] allow for passing parameter labels directly --- src/base/sensitivity_analysis.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/base/sensitivity_analysis.jl b/src/base/sensitivity_analysis.jl index 058eb727d..8c1340a1f 100644 --- a/src/base/sensitivity_analysis.jl +++ b/src/base/sensitivity_analysis.jl @@ -1,10 +1,14 @@ function get_indices_in_parameter_vector(p, device_param_pairs) indices = Int[] - for tuple in device_param_pairs - label = join((tuple[1], "params", tuple[2:end]...), ".") + for entry in device_param_pairs + if isa(entry, Tuple) + label = join((entry[1], "params", entry[2:end]...), ".") + else + label = entry + end ix = ComponentArrays.label2index(p, label) if ix === nothing - @error "Index not found for entry $tuple" + @error "Index not found for entry $entry" return nothing end if isa(ix, AbstractArray) From db8fce647870e04d13613921ad96234c7b7faf9e Mon Sep 17 00:00:00 2001 From: Matt Bossart Date: Mon, 23 Sep 2024 10:14:42 -0600 Subject: [PATCH 76/76] fix Project.toml --- Project.toml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Project.toml b/Project.toml index 356775544..2ffab3813 100644 --- a/Project.toml +++ b/Project.toml @@ -41,24 +41,19 @@ FastClosures = "^0.3" ForwardDiff = "~v0.10" InfrastructureSystems = "2" NLsolve = "4" +NonlinearSolve = "3.11" PowerSystems = "4" PowerFlows = "^0.7" PowerNetworkMatrices = "^0.11" PrettyTables = "1, 2" SciMLBase = "2" +SciMLSensitivity = "7.0" + TimerOutputs = "~0.5" LinearAlgebra = "1" Logging = "1" -NLsolve = "4" -NonlinearSolve = "3.11" -PowerFlows = "^0.6" -PowerNetworkMatrices = "^0.10" -PowerSystems = "^3.1.2" -PrettyTables = "1, 2" + Random = "1" -SciMLBase = "2" -SciMLSensitivity = "7.0" SparseArrays = "1" -TimerOutputs = "~0.5" Zygote = "0.6" julia = "^1.6"