From dadefbe7e89c59e57edeb4d0af1b23038956aec9 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 5 Aug 2024 09:36:42 -0600 Subject: [PATCH 01/99] WIP: ravens to math converter for PMD. --- src/PowerModelsDistribution.jl | 2 + src/data_model/transformations/ravens2math.jl | 814 ++++++++++++++++++ src/data_model/utils_ravens.jl | 52 ++ src/prob/common.jl | 43 + 4 files changed, 911 insertions(+) create mode 100644 src/data_model/transformations/ravens2math.jl create mode 100644 src/data_model/utils_ravens.jl diff --git a/src/PowerModelsDistribution.jl b/src/PowerModelsDistribution.jl index 0a8443a3a..77669ba5f 100644 --- a/src/PowerModelsDistribution.jl +++ b/src/PowerModelsDistribution.jl @@ -71,6 +71,7 @@ module PowerModelsDistribution include("data_model/transformations/math2eng.jl") include("data_model/transformations/utils.jl") include("data_model/transformations/reduce.jl") + include("data_model/transformations/ravens2math.jl") include("core/data.jl") include("core/ref.jl") @@ -113,6 +114,7 @@ module PowerModelsDistribution include("io/common.jl") include("data_model/utils.jl") + include("data_model/utils_ravens.jl") include("data_model/checks.jl") include("data_model/components.jl") include("data_model/multinetwork.jl") diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl new file mode 100644 index 000000000..b098de30f --- /dev/null +++ b/src/data_model/transformations/ravens2math.jl @@ -0,0 +1,814 @@ +"cim-ravens to math object mapping" +const _math_to_ravens = Dict{String,String}( + "bus" => "connectivity_node", + "transformer" => "power_transformer", + "switch" => "switch", + # "shunt" => "shunt_compensator", + "load" => "energy_consumer", + # "generator" => "rotating_machine", + # "solar" => "photovoltaic_unit", + # "storage" => "battery_unit", + "voltage_source" => "energy_source", +) + + +"list of nodal type elements in the ravens model" +const _ravens_node_elements = String[ + "energy_consumer", "energy_source" +] + +"list of edge type elements in the ravens model" +const _ravens_edge_elements = String[ + "conductor" +] + +"list of all ravens asset types" +const pmd_ravens_asset_types = String[ + "connectivity_node", _ravens_edge_elements..., _ravens_node_elements... +] + + +function transform_data_model_ravens( + data::Dict{String,<:Any}; + kron_reduce::Bool=true, + phase_project::Bool=false, + multinetwork::Bool=false, + global_keys::Set{String}=Set{String}(), + ravens2math_passthrough::Dict{String,<:Vector{<:String}}=Dict{String,Vector{String}}(), + ravens2math_extensions::Vector{<:Function}=Function[], + make_pu::Bool=true, + make_pu_extensions::Vector{<:Function}=Function[], + correct_network_data::Bool=true, + )::Dict{String,Any} + + current_data_model = get(data, "data_model", MATHEMATICAL) + + ## TODO + # if multinetwork && !ismultinetwork(data) + # data = make_multinetwork(data; global_keys=global_keys) + # end + + data_math = _map_ravens2math( + data; + kron_reduce=kron_reduce, + phase_project=phase_project, + ravens2math_extensions=ravens2math_extensions, + ravens2math_passthrough=ravens2math_passthrough, + global_keys=global_keys, + ) + + # TODO: Correct network data transforms a lot of the values of lines/branches (other values maybe too) + correct_network_data && correct_network_data!(data_math; make_pu=make_pu, make_pu_extensions=make_pu_extensions) + + return data_math + +end + + +"base function for converting ravens model to mathematical model" +function _map_ravens2math( + data_ravens::Dict{String,<:Any}; + kron_reduce::Bool=true, + phase_project::Bool=false, + ravens2math_extensions::Vector{<:Function}=Function[], + ravens2math_passthrough::Dict{String,Vector{String}}=Dict{String,Vector{String}}(), + global_keys::Set{String}=Set{String}(), + )::Dict{String,Any} + + _data_ravens = deepcopy(data_ravens) + + ## TODO + # if kron_reduce + # apply_kron_reduction!(_data_ravens) + # apply_phase_projection_delta!(_data_ravens) + # end + + # if phase_project + # apply_phase_projection!(_data_ravens) + # end + + + # # TODO: Add vbases to settings + # _vbases_default = Dict("vbases_default" => Dict{String, Real}()) + # for (name, ravens_obj) in get(data_ravens, "BaseVoltage", Dict{String,Any}()) + # _vbases_default = Dict(name => ravens_obj["BaseVoltage.nominalVoltage"]) + # end + + # TODO: Add settings (defaults) + basemva = 100 + _settings = Dict("sbase_default" => basemva * 1e3, + "voltage_scale_factor" => 1e3, + "power_scale_factor" => 1e3, + "base_frequency" => 60.0, + "vbases_default" => Dict{String,Real}() + ) + + ## TODO: Multinetwork + if ismultinetwork(data_ravens) + data_math = Dict{String,Any}( + "name" => get(_data_ravens, "name", ""), + "data_model" => MATHEMATICAL, + "nw" => Dict{String,Any}( + n => Dict{String,Any}( + "per_unit" => get(_data_ravens, "per_unit", false), + "is_projected" => get(nw, "is_projected", false), + "is_kron_reduced" => get(nw, "is_kron_reduced", false), + "settings" => deepcopy(_settings), + "time_elapsed" => get(nw, "time_elapsed", 1.0), + ) for (n,nw) in _data_ravens["nw"] + ), + "multinetwork" => ismultinetwork(data_ravens), + [k => data_ravens[k] for k in global_keys if haskey(data_ravens, k)]... + ) + else + data_math = Dict{String,Any}( + "name" => get(_data_ravens, "name", ""), + "per_unit" => get(_data_ravens, "per_unit", false), + "data_model" => MATHEMATICAL, + "is_projected" => get(_data_ravens, "is_projected", false), + "is_kron_reduced" => get(_data_ravens, "is_kron_reduced", false), + "settings" => deepcopy(_settings), + "time_elapsed" => get(_data_ravens, "time_elapsed", 1.0), + ) + end + + + @info "$(data_math)" + gfdgfdgf + + apply_pmd!(_map_ravens2math_nw!, data_math, _data_ravens; ravens2math_passthrough=ravens2math_passthrough, ravens2math_extensions=ravens2math_extensions) + + if ismultinetwork(data_ravens) + _collect_nw_maps!(data_math) + _collect_nw_bus_lookups!(data_math) + end + + return data_math +end + + +""" +""" +function _map_ravens2math_nw!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; ravens2math_passthrough::Dict{String,Vector{String}}=Dict{String,Vector{String}}(), ravens2math_extensions::Vector{<:Function}=Function[]) + data_math["map"] = Vector{Dict{String,Any}}([ + Dict{String,Any}("unmap_function" => "_map_math2ravens_root!") + ]) + + _init_base_components!(data_math) + + ## TODO + # for property in get(ravens2math_passthrough, "root", String[]) + # if haskey(data_ravens, property) + # data_math[property] = deepcopy(data_ravens[property]) + # end + # end + + for type in pmd_ravens_asset_types + getfield(PowerModelsDistribution, Symbol("_map_ravens2math_$(type)!"))(data_math, data_ravens; pass_props=get(ravens2math_passthrough, type, String[])) + end + + # Custom ravens2math transformation functions + for ravens2math_func! in ravens2math_extensions + ravens2math_func!(data_math, data_ravens) + end + + ## TODO: See if this is still neccesary for RAVENS + # # post fix + # if !get(data_math, "is_kron_reduced", false) + # #TODO fix this in place / throw error instead? IEEE8500 leads to switches + # # with 3x3 R matrices but only 1 phase + # #NOTE: Don't do this when kron-reducing, it will undo the padding + # _slice_branches!(data_math) + # end + + find_conductor_ids!(data_math) + _map_conductor_ids!(data_math) + + # TODO: See if this is still neccesary for RAVENS + _map_settings_vbases_default!(data_math) + +end + + +"converts ravens connectivity_node components into mathematical bus components" +function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + + for (name, ravens_obj) in get(data_ravens, "ConnectivityNode", Dict{String,Any}()) + + math_obj = _init_math_obj_ravens("bus", name, ravens_obj, length(data_math["bus"])+1; pass_props=pass_props) + math_obj["bus_i"] = math_obj["index"] + math_obj["source_id"] = "bus.$name" + + # default bus_type, change as elements are added (e.g., load, generator, source). + math_obj["bus_type"] = 1 + + # TODO: needed? - default grounded + math_obj["grounded"] = Bool[0, 0, 0] + + ## TODO + # # take care of grounding; convert to shunt if lossy + # grounded_perfect, shunts = _convert_grounding(ravens_obj["terminals"], ravens_obj["grounded"], ravens_obj["rg"], ravens_obj["xg"]) + + # math_obj["grounded"] = grounded_perfect + # to_sh = [] + # for (sh_connections, sh_y) in shunts + # sh_index = length(data_math["shunt"]) + 1 + # data_math["shunt"]["$sh_index"] = Dict( + # "index" => sh_index, + # "shunt_bus" => math_obj["bus_i"], + # "connections" => sh_connections, + # "gs" => real.(sh_y), + # "bs" => imag.(sh_y), + # ) + # push!(to_sh, "shunt.$sh_index") + # end + + if haskey(ravens_obj, "SvVoltage.v") + math_obj["vm"] = ravens_obj["SvVoltage.v"] + end + + if haskey(ravens_obj, "SvVoltage.angle") + math_obj["va"] = ravens_obj["SvVoltage.angle"] + end + + # TODO: add vm_pair_lb/ub (may not be needed!) + math_obj["vm_pair_lb"] = Tuple{Any, Any, Real}[] + math_obj["vm_pair_ub"] = Tuple{Any, Any, Real}[] + + data_math["bus"]["$(math_obj["index"])"] = math_obj + + if !haskey(data_math, "bus_lookup") + data_math["bus_lookup"] = Dict{Any,Int}() + end + + data_math["bus_lookup"][name] = math_obj["index"] + + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "bus.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_bus!", + )) + end +end + + +"converts ravensineering conductors (e.g., ACLineSegments) into mathematical branches" +function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + + _data_ravens_conductor = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["Conductor"] + + for (name, ravens_obj) in get(_data_ravens_conductor, "ACLineSegment", Dict{Any,Dict{String,Any}}()) + + math_obj = _init_math_obj_ravens("ac_line_segment", name, ravens_obj, length(data_math["branch"])+1; pass_props=pass_props) + + nphases = length(ravens_obj["ACLineSegment.ACLineSegmentPhase"]) + + f_connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + t_connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][2]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + math_obj["f_bus"] = data_math["bus_lookup"][f_connectivity_node] + math_obj["t_bus"] = data_math["bus_lookup"][t_connectivity_node] + + # define the number of terminals (i.e., phases) that the bus/es have, based on the lines + if nphases >= 3 + data_math["bus"][string(math_obj["f_bus"])]["terminals"]= [i for i = 1:nphases] + data_math["bus"][string(math_obj["t_bus"])]["terminals"]= [i for i = 1:nphases] + else + _terminals = Vector{Int64}() + for phase_info in ravens_obj["ACLineSegment.ACLineSegmentPhase"] + phase = phase_info["ACLineSegmentPhase.phase"] + if phase == "SinglePhaseKind.A" + push!(_terminals, 1) + elseif phase == "SinglePhaseKind.B" + push!(_terminals, 2) + elseif phase == "SinglePhaseKind.C" + push!(_terminals, 3) + else + @error("Terminals/Phases for buses '$(f_connectivity_node)' and '$(t_connectivity_node)' not recognized. Check your model!") + end + end + data_math["bus"][string(math_obj["f_bus"])]["terminals"]= _terminals + data_math["bus"][string(math_obj["t_bus"])]["terminals"]= _terminals + end + + # Initilize vmin and vmax in buses + data_math["bus"][string(math_obj["f_bus"])]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(math_obj["f_bus"])]["vmax"] = fill(Inf, nphases) + + data_math["bus"][string(math_obj["t_bus"])]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(math_obj["t_bus"])]["vmax"] = fill(Inf, nphases) + + #------------------------------------------------------------------------------- + + # f_ and t_connections for the lines/branches + math_obj["f_connections"] = data_math["bus"][string(math_obj["f_bus"])]["terminals"] + math_obj["t_connections"] = data_math["bus"][string(math_obj["t_bus"])]["terminals"] + + + _perlengthimpedance_name = replace(split(ravens_obj["ACLineSegment.PerLengthImpedance"], "::")[2], "'" => "") + _perlengthimpedance_data = data_ravens["PerLengthLineParameter"]["PerLengthImpedance"]["PerLengthPhaseImpedance"][_perlengthimpedance_name] + + math_obj["br_r"] = _impedance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.r") + math_obj["br_x"] = _impedance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.x") + + # b is given in mhos in CIM-RAVENS schema + math_obj["b_fr"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.b") + math_obj["b_to"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.b") + + # g is given in mhos in CIM-RAVENS schema + math_obj["g_fr"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.g") + math_obj["g_to"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.g") + + ## TODO:: these do not appear in JSON schema, are they needed? if yes, we need to represent them on CIM-RAVENS schema + math_obj["angmin"] = get(ravens_obj, "vad_lb", fill(-60.0, nphases)) + math_obj["angmax"] = get(ravens_obj, "vad_ub", fill( 60.0, nphases)) + + # Operational Limits + _oplimitset_id = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["ACDCTerminal.OperationalLimitSet"], "::")[2], "'" => "") + _oplimitset = data_ravens["OperationalLimitSet"][_oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][2] # [1] is Normal amps, [2] is Emergency amps - by default use emerg amps + + for (f_key, t_key) in [("CurrentLimit.value", "c_rating_a"), ("CurrentLimit.value", "c_rating_b"), ("CurrentLimit.value", "c_rating_c"), + ("ApparentPowerLimit.value", "rate_a"), ("ApparentPowerLimit.value", "rate_b"), ("ApparentPowerLimit.value", "rate_c")] + math_obj[t_key] = haskey(_oplimitset, f_key) ? fill(_oplimitset[f_key], nphases) : fill(Inf, nphases) + end + + math_obj["br_status"] = get(ravens_obj, "ConductingEquipment.SvStatus", 1) + + data_math["branch"]["$(math_obj["index"])"] = math_obj + + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "branch.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_line!", + )) + end + +end + +# TODO: Transformers need a lot of changes/refactors!!! +"converts ravensineering n-winding transformers into mathematical ideal 2-winding lossless transformer branches and impedance branches to represent the loss model" +function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + + _data_ravens_transformer = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"] + + for (name, ravens_obj) in get(_data_ravens_transformer, "PowerTransformer", Dict{Any,Dict{String,Any}}()) + + # Build map first, so we can update it as we decompose the transformer + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => String[], + "unmap_function" => "_map_math2ravens_transformer!", + )) + + to_map = data_math["map"][end]["to"] + + # _apply_xfmrcode!(ravens_obj, data_ravens) + + # PowerTransformerTank + if haskey(ravens_obj, "PowerTransformer.TransformerTank") + + @info "PowerTransformerTank ENTER" + @assert all(haskey(ravens_obj, k) for k in ["f_bus", "t_bus", "f_connections", "t_connections"]) "Incomplete definition of AL2W tranformer $name, aborting ravens2math conversion" + + nphases = length(ravens_obj["f_connections"]) + + math_obj = Dict{String,Any}( + "name" => name, + "source_id" => ravens_obj["source_id"], + "f_bus" => data_math["bus_lookup"][ravens_obj["f_bus"]], + "t_bus" => data_math["bus_lookup"][ravens_obj["t_bus"]], + "f_connections" => ravens_obj["f_connections"], + "t_connections" => ravens_obj["t_connections"], + "configuration" => get(ravens_obj, "configuration", WYE), + "tm_nom" => get(ravens_obj, "tm_nom", 1.0), + "tm_set" => get(ravens_obj, "tm_set", fill(1.0, nphases)), + "tm_fix" => get(ravens_obj, "tm_fix", fill(true, nphases)), + "polarity" => get(ravens_obj, "polarity", -1), + "sm_ub" => get(ravens_obj, "sm_ub", Inf), + "cm_ub" => get(ravens_obj, "cm_ub", Inf), + "status" => Int(get(ravens_obj, "status", ENABLED)), + "index" => length(data_math["transformer"])+1 + ) + + for k in [["tm_lb", "tm_ub"]; pass_props] + if haskey(ravens_obj, k) + math_obj[k] = ravens_obj[k] + end + end + + data_math["transformer"]["$(math_obj["index"])"] = math_obj + + push!(to_map, "transformer.$(math_obj["index"])") + + + # PowerTransformerEnd + else + + nrw = length(ravens_obj["bus"]) + + for w in 1:length(ravens_obj["PowerTransformer.PowerTransformerEnd"]) + + vnom = ravens_obj["PowerTransformer.PowerTransformerEnd"][w]["PowerTransformerEnd.ratedU"] + snom = ravens_obj["PowerTransformer.PowerTransformerEnd"][w]["PowerTransformerEnd.ratedS"] + + # calculate zbase in which the data is specified, and convert to SI + zbase = (vnom.^2) ./ snom + + # x_sc is specified with respect to first winding + x_sc = ravens_obj["xsc"] .* zbase[1] + + # rs is specified with respect to each winding + r_s = ravens_obj["rw"] .* zbase + + g_sh = (ravens_obj["noloadloss"]*snom[1])/vnom[1]^2 + b_sh = -(ravens_obj["cmag"]*snom[1])/vnom[1]^2 + + # data is measured externally, but we now refer it to the internal side + ratios = vnom/data_ravens["settings"]["voltage_scale_factor"] + x_sc = x_sc./ratios[1]^2 + r_s = r_s./ratios.^2 + g_sh = g_sh*ratios[1]^2 + b_sh = b_sh*ratios[1]^2 + + # convert x_sc from list of upper triangle elements to an explicit dict + y_sh = g_sh + im*b_sh + z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) + + dims = length(ravens_obj["tm_set"][1]) + transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh,ravens_obj["connections"][1]; nphases=dims, status=Int(ravens_obj["status"] == ENABLED)) + + # 2-WINDING TRANSFORMER + # make virtual bus and mark it for reduction + tm_nom = ravens_obj["configuration"][w]==DELTA ? ravens_obj["vm_nom"][w]*sqrt(3) : ravens_obj["vm_nom"][w] + transformer_2wa_obj = Dict{String,Any}( + "name" => "_virtual_transformer.$name.$w", + "source_id" => "_virtual_transformer.$(ravens_obj["source_id"]).$w", + "f_bus" => data_math["bus_lookup"][ravens_obj["bus"][w]], + "t_bus" => transformer_t_bus_w[w], + "tm_nom" => tm_nom, + "f_connections" => ravens_obj["connections"][w], + "t_connections" => get(data_math, "is_kron_reduced", false) ? ravens_obj["connections"][1] : collect(1:dims+1), + "configuration" => ravens_obj["configuration"][w], + "polarity" => ravens_obj["polarity"][w], + "tm_set" => ravens_obj["tm_set"][w], + "tm_fix" => ravens_obj["tm_fix"][w], + "sm_ub" => get(ravens_obj, "sm_ub", Inf), + "cm_ub" => get(ravens_obj, "cm_ub", Inf), + "status" => ravens_obj["status"] == DISABLED ? 0 : 1, + "index" => length(data_math["transformer"])+1 + ) + + for prop in [["tm_lb", "tm_ub", "tm_step"]; pass_props] + if haskey(ravens_obj, prop) + transformer_2wa_obj[prop] = ravens_obj[prop][w] + end + end + + data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj + + # add regcontrol items to math model + if haskey(ravens_obj,"controls") && !all(data_math["transformer"]["$(transformer_2wa_obj["index"])"]["tm_fix"]) + reg_obj = Dict{String,Any}( + "vreg" => ravens_obj["controls"]["vreg"][w], + "band" => ravens_obj["controls"]["band"][w], + "ptratio" => ravens_obj["controls"]["ptratio"][w], + "ctprim" => ravens_obj["controls"]["ctprim"][w], + "r" => ravens_obj["controls"]["r"][w], + "x" => ravens_obj["controls"]["x"][w], + ) + data_math["transformer"]["$(transformer_2wa_obj["index"])"]["controls"] = reg_obj + end + + if w==3 && ravens_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start + default_va = [0, -120, 120][ravens_obj["connections"][1][1]] + data_math["bus"]["$(transformer_2wa_obj["f_bus"])"]["va_start"] = haskey(data_ravens["bus"][ravens_obj["bus"][w]],"va_start") ? data_ravens["bus"][ravens_obj["bus"][w]]["va_start"] : [default_va, (default_va+180)] + idx = 0 + bus_ids = [] + t_bus = haskey(data_ravens, "line") ? [data["t_bus"] for (_,data) in data_ravens["line"] if data["f_bus"] == ravens_obj["bus"][w]] : [] + while length(t_bus)>0 || idx "") + + # Initialize energy consumer object + math_obj = _init_math_obj_ravens("energy_consumer", name, ravens_obj, length(data_math["load"])+1; pass_props=pass_props) + + # Get Bus/ConnectivityNode + connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + math_obj["load_bus"] = data_math["bus_lookup"][connectivity_node] + + # Model of the Load/EnergyConsumer + if load_response_characts == "Constant Z" + + elseif load_response_characts == "Motor" + + elseif load_response_characts == "Mix Motor/Res" + + elseif load_response_characts == "Constant I" + + elseif load_response_characts == "Variable P, Fixed Q" + + elseif load_response_characts == "Variable P, Fixed X" + + # "Constant kVA" : default + else + + if load_response_characts != "Constant kVA" + @warn("Load model (response characteristic) for $(name) not supported! Defaulting to 'Constant kVA'") + end + + # Add the model of the load based on loadresponsecharacteristic + math_obj["model"] = POWER + + # P and Q consumption + math_obj["pd"] = [ravens_obj["EnergyConsumer.p"]] + math_obj["qd"] = [ravens_obj["EnergyConsumer.q"]] + + end + + # Vnom + base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + math_obj["vnom_kv"] = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + + # Get voltage bounds for specific bus connected (TODO: see if it can be coverted to standalone function to avoid repetition) + bus_info = string(math_obj["load_bus"]) + bus_conn = data_math["bus"][bus_info] + + base_voltage_id = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + base_voltage = data_ravens["BaseVoltage"][base_voltage_id]["BaseVoltage.nominalVoltage"] + op_limit_id = replace(split(data_ravens["ConnectivityNode"][connectivity_node]["ConnectivityNode.OperationalLimitSet"], "::")[2], "'" => "") + # op_limit_max = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][1]["VoltageLimit.value"]./base_voltage + # op_limit_min = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][2]["VoltageLimit.value"]./base_voltage + op_limit_max = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][1]["VoltageLimit.value"] + op_limit_min = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][2]["VoltageLimit.value"] + + _connections = Vector{Int64}() + if haskey(ravens_obj, "EnergyConsumer.EnergyConsumerPhase") + for phase_info in ravens_obj["EnergyConsumer.EnergyConsumerPhase"] + phase = phase_info["EnergyConsumerPhase.phase"] + if phase == "SinglePhaseKind.A" + phase_index = findfirst(==(1), bus_conn["terminals"]) + bus_conn["vmax"][phase_index] = op_limit_max + bus_conn["vmin"][phase_index] = op_limit_min + push!(_connections, 1) + elseif phase == "SinglePhaseKind.B" + phase_index = findfirst(==(2), bus_conn["terminals"]) + bus_conn["vmax"][phase_index] = op_limit_max + bus_conn["vmin"][phase_index] = op_limit_min + push!(_connections, 2) + elseif phase == "SinglePhaseKind.C" + phase_index = findfirst(==(3), bus_conn["terminals"]) + bus_conn["vmax"][phase_index] = op_limit_max + bus_conn["vmin"][phase_index] = op_limit_min + push!(_connections, 3) + else + @error("Terminals/Phases for buses '$(f_connectivity_node)' and '$(t_connectivity_node)' not recognized. Check your model!") + end + end + math_obj["connections"] = _connections + else + # assumes it is a three-phase connection + N = length(bus_conn["terminals"]) + bus_conn["vmax"] = fill(op_limit_max, N) + bus_conn["vmin"] = fill(op_limit_min, N) + math_obj["connections"] = bus_conn["terminals"] + end + + # TODO: Configuration + _config = ravens_obj["EnergyConsumer.phaseConnection"] + if _config == "PhaseShuntConnectionKind.Y" + math_obj["configuration"] = WYE + elseif _config == "PhaseShuntConnectionKind.D" + math_obj["configuration"] = DELTA + elseif _config == "PhaseShuntConnectionKind.Yn" + elseif _config == "PhaseShuntConnectionKind.I" + elseif _config == "PhaseShuntConnectionKind.G" + else + @error("Configuration of load $(name) is not supported.") + end + + # Status + math_obj["status"] = ravens_obj["ConductingEquipment.SvStatus"] + + # TODO: Dispatchable? default=0 + math_obj["dispatchable"] = 0 + + # Index + data_math["load"]["$(math_obj["index"])"] = math_obj + + # TODO: Assign 'grounding' to corresponding connectivity node + if ravens_obj["EnergyConsumer.grounded"] == "true" + bus_conn["grounded"] = Bool[0, 0, 0] + end + + # Revise bus_type of connectivity node to PQ bus + bus_conn["bus_type"] = 1 + + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "load.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_load!", + )) + + end +end + + +#TODO: +"converts ravensineering voltage sources into mathematical generators and (if needed) impedance branches to represent the loss model" +function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + + _data_ravens_energyconnection = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] + + for (name, ravens_obj) in get(_data_ravens_energyconnection, "EnergySource", Dict{String,Any}()) + + math_obj = _init_math_obj_ravens("energy_source", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) + math_obj["name"] = "_virtual_gen.energy_source.$name" + + # get connectivity node info. (bus info) + connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + math_obj["gen_bus"] = gen_bus = data_math["bus_lookup"][connectivity_node] + bus_conn = data_math["bus"][string(gen_bus)] + + # Revise bus_type of connectivity node to PV bus + bus_conn["bus_type"] = 3 + + nconductors = 0 + _connections = Vector{Int64}() + if haskey(ravens_obj, "EnergySource.EnergySourcePhase") + + nconductors = length(ravens_obj["EnergySource.EnergySourcePhase"]) + # TODO: how to redefine the kron reduction? + # nphases = get(ravens_obj, "configuration", WYE) == WYE && !get(data_ravens, "is_kron_reduced", false) ? nconductors - 1 : nconductors + nphases = nconductors + + for phase_info in ravens_obj["EnergySource.EnergySourcePhase"] + phase = phase_info["EnergySourcePhase.phase"] + if phase == "SinglePhaseKind.A" + push!(_connections, 1) + elseif phase == "SinglePhaseKind.B" + push!(_connections, 2) + elseif phase == "SinglePhaseKind.C" + push!(_connections, 3) + else + @error("Connections for energy source '$(name)' not recognized. Check your model!") + end + end + + math_obj["connections"] = _connections + else + # assumes it is a three-phase connection + nconductors = length(bus_conn["terminals"]) + # TODO: how to redefine the kron reduction? we need + # nphases = get(ravens_obj, "configuration", WYE) == WYE && !get(data_ravens, "is_kron_reduced", false) ? nconductors - 1 : nconductors + nphases = nconductors + math_obj["connections"] = bus_conn["terminals"] + end + + math_obj["gen_status"] = status = Int(ravens_obj["ConductingEquipment.SvStatus"]) + + # Vnom and add vbases_default from energy source + base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + vnom = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] / sqrt(nphases) + data_math["settings"]["vbases_default"][connectivity_node] = vnom + + # P, Q, Vg, etc. + math_obj["pg"] = get(ravens_obj, "EnergySource.activePower", fill(0.0, nphases)).*fill(1.0, nphases) + math_obj["qg"] = get(ravens_obj, "EnergySource.reactivePower", fill(0.0, nphases)).*fill(1.0, nphases) + math_obj["vg"] = get(ravens_obj, "EnergySource.voltageMagnitude", fill(1.0, nphases)).*fill(1.0, nphases) + math_obj["pmin"] = get(ravens_obj, "EnergySource.pMin", fill(-Inf, nphases)).*fill(1.0, nphases) + math_obj["pmax"] = get(ravens_obj, "EnergySource.pMax", fill( Inf, nphases)).*fill(1.0, nphases) + math_obj["qmin"] = get(ravens_obj, "EnergySource.qMin", fill(-Inf, nphases)).*fill(1.0, nphases) + math_obj["qmax"] = get(ravens_obj, "EnergySource.qMax", fill( Inf, nphases)).*fill(1.0, nphases) + + #TODO: how to define configuration from terminals or add a connectionKind parameter? add to RAVENS schema? + math_obj["configuration"] = get(ravens_obj, "EnergySource.connectionKind", WYE) + + # TODO: Do we need a control_mode parameter for this? add to RAVENS schema + math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "EnergySource.connectionKind", ISOCHRONOUS)) + math_obj["source_id"] = "energy_source.$name" + + # TODO: inside this function, there are elements that do not exist in the RAVENS schema, so the default is used. + _add_gen_cost_model!(math_obj, ravens_obj) + + map_to = "gen.$(math_obj["index"])" + + if !all(isapprox.(get(ravens_obj, "EnergySource.r", zeros(1, 1)), 0)) && !all(isapprox.(get(ravens_obj, "EnergySource.x", zeros(1, 1)), 0)) + + # Revise bus_type of connectivity node to PV bus (virtual bus becomes the new slack bus) + bus_conn["bus_type"] = 1 + + f_bus = deepcopy(data_math["bus"]["$(math_obj["gen_bus"])"]) + + bus_obj = Dict{String,Any}( + "bus_i" => length(data_math["bus"])+1, + "index" => length(data_math["bus"])+1, + "terminals" => math_obj["connections"], + # TODO: grounded energyosurce default? + "grounded" => Bool[0, 0, 0], + "name" => "_virtual_bus.energy_source.$name", + "bus_type" => status == 0 ? 4 : control_mode == Int(ISOCHRONOUS) ? 3 : 2, + "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"], nphases), + "va" => rad2deg.(_wrap_to_pi.([-2*pi/nphases*(i-1)+deg2rad(ravens_obj["EnergySource.voltageAngle"]) for i in 1:nphases])), + "vmin" => fill(ravens_obj["EnergySource.voltageMagnitude"], nphases), + "vmax" => fill(ravens_obj["EnergySource.voltageMagnitude"], nphases), + "vm_pair_lb" => deepcopy(get(ravens_obj, "EnergySource.vpairMin", Tuple{Any,Any,Real}[])), + "vm_pair_ub" => deepcopy(get(ravens_obj, "EnergySource.vpairMax", Tuple{Any,Any,Real}[])), + "source_id" => "energy_source.$name", + ) + + # TODO: + # for (i,t) in enumerate(math_obj["connections"]) + # if data_math["bus"]["$(data_math["bus_lookup"][ravens_obj["bus"]])"]["grounded"][i] + # bus_obj["vm"][i] = 0 + # bus_obj["vmin"][i] = 0 + # bus_obj["vmax"][i] = Inf + # end + # end + + math_obj["gen_bus"] = gen_bus = bus_obj["bus_i"] + + data_math["bus"]["$(bus_obj["index"])"] = bus_obj + + branch_obj = Dict{String,Any}( + "name" => "_virtual_branch.energy_source.$name", + "source_id" => "energy_source.$name", + "f_bus" => bus_obj["bus_i"], + "t_bus" => data_math["bus_lookup"][connectivity_node], + # TODO: + "f_connections" => math_obj["connections"], + "t_connections" => math_obj["connections"], + "angmin" => fill(-10.0, nconductors), + "angmax" => fill( 10.0, nconductors), + "c_rating_a" => fill(Inf, nconductors), + "br_status" => status, + # "br_r" => _impedance_conversion_ravens(data_ravens, ravens_obj, "rs"), + # "br_x" => _impedance_conversion_ravens(data_ravens, ravens_obj, "xs"), + "br_r" => ravens_obj["EnergySource.r"], + "br_x" => ravens_obj["EnergySource.x"], + "g_fr" => zeros(nconductors, nconductors), + "g_to" => zeros(nconductors, nconductors), + "b_fr" => zeros(nconductors, nconductors), + "b_to" => zeros(nconductors, nconductors), + "index" => length(data_math["branch"])+1 + ) + + data_math["branch"]["$(branch_obj["index"])"] = branch_obj + + map_to = [map_to, "bus.$(bus_obj["index"])", "branch.$(branch_obj["index"])"] + else + vm_lb = control_mode == Int(ISOCHRONOUS) ? ravens_obj["EnergySource.voltageMagnitude"] : get(ravens_obj, "EnergySource.vMin", fill(0.0, nphases)) + vm_ub = control_mode == Int(ISOCHRONOUS) ? ravens_obj["EnergySource.voltageMagnitude"] : get(ravens_obj, "EnergySource.vMax", fill(Inf, nphases)) + + data_math["bus"]["$gen_bus"]["vmin"] = [vm_lb..., [0.0 for n in 1:(nconductors-nphases)]...] + data_math["bus"]["$gen_bus"]["vmax"] = [vm_ub..., [Inf for n in 1:(nconductors-nphases)]...] + data_math["bus"]["$gen_bus"]["vm"] = [ravens_obj["EnergySource.voltageMagnitude"]..., [0.0 for n in 1:(nconductors-nphases)]...] + data_math["bus"]["$gen_bus"]["va"] = [ravens_obj["EnergySource.voltageAngle"]..., [0.0 for n in 1:(nconductors-nphases)]...] + + bus_type = data_math["bus"]["$gen_bus"]["bus_type"] + data_math["bus"]["$gen_bus"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) + end + + data_math["gen"]["$(math_obj["index"])"] = math_obj + + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => map_to, + "unmap_function" => "_map_math2ravens_energy_source!", + )) + end +end + + +"converts ravensineering switches into mathematical switches and (if neeed) impedance branches to represent loss model" +function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + # TODO enable real switches (right now only using vitual lines) + for (name, ravens_obj) in get(data_ravens, "switch", Dict{Any,Dict{String,Any}}()) + # TODO + end +end diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl new file mode 100644 index 000000000..cfa7a5821 --- /dev/null +++ b/src/data_model/utils_ravens.jl @@ -0,0 +1,52 @@ + +"initializes the base math object of any type" +function _init_math_obj_ravens(obj_type::String, eng_id::Any, eng_obj::Dict{String,<:Any}, index::Int; pass_props::Vector{String}=String[])::Dict{String,Any} + math_obj = Dict{String,Any}( + "name" => "$eng_id", + "source_id" => "$obj_type.$eng_id" + ) + + math_obj["index"] = index + + return math_obj +end + + +"converts impendance in Ohm/m by multiplying by length" +function _impedance_conversion_ravens(data_eng::Dict{String,Any}, eng_obj::Dict{String,Any}, key::String) + + _conductor_count = data_eng["PerLengthPhaseImpedance.conductorCount"] + _impedance_matrix = zeros(Float64, _conductor_count, _conductor_count) + + _index = 1 + for i in 1:_conductor_count + for j in 1:i + _impedance_matrix[i, j] = get(data_eng["PerLengthPhaseImpedance.PhaseImpedanceData"][_index], key, 0.0) + _impedance_matrix[j, i] = get(data_eng["PerLengthPhaseImpedance.PhaseImpedanceData"][_index], key, 0.0) + _index += 1 + end + end + + return _impedance_matrix .* get(eng_obj, "Conductor.length", 1.0) +end + + +"converts admittance by multiplying by 2πωl" +function _admittance_conversion_ravens(data_eng::Dict{String,<:Any}, eng_obj::Dict{String,<:Any}, key::String) + + _conductor_count = data_eng["PerLengthPhaseImpedance.conductorCount"] + _admittance_matrix = zeros(Float64, _conductor_count, _conductor_count) + + _index = 1 + for i in 1:_conductor_count + for j in 1:i + _admittance_matrix[i, j] = get(data_eng["PerLengthPhaseImpedance.PhaseImpedanceData"][_index], key, 0.0) + _admittance_matrix[j, i] = get(data_eng["PerLengthPhaseImpedance.PhaseImpedanceData"][_index], key, 0.0) + _index += 1 + end + end + + # TODO: Default frequency - get actual frequency from ravens data + freq = 60.0 + return _admittance_matrix .* get(eng_obj, "Conductor.length", 1.0) .* freq ./ 1e2 # divide by 2 to get both sides _to and _fr +end diff --git a/src/prob/common.jl b/src/prob/common.jl index d0f9ea408..7f86adf3d 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -129,6 +129,49 @@ function instantiate_mc_model( end + +function instantiate_mc_model_ravens( + data::Dict{String,<:Any}, + model_type::Type, + build_method::Function; + ref_extensions::Vector{<:Function}=Function[], + multinetwork::Bool=ismultinetwork(data), + global_keys::Set{String}=Set{String}(), + ravens2math_extensions::Vector{<:Function}=Function[], + ravens2math_passthrough::Dict{String,<:Vector{<:String}}=Dict{String,Vector{String}}(), + make_pu_extensions::Vector{<:Function}=Function[], + kwargs... + ) + + # @info "$(data)" + + @info "Converting CIM-RAVENS data model to MATHEMATICAL first to build JuMP model" + + data = transform_data_model_ravens( + data; + multinetwork=multinetwork, + global_keys=global_keys, + ravens2math_extensions=ravens2math_extensions, + ravens2math_passthrough=ravens2math_passthrough, + make_pu_extensions=make_pu_extensions, + ) + + @info "$(data["load"])" + + DEFINIDOEN_instantiate_mc_model + + return _IM.instantiate_model( + data, + model_type, + build_method, + ref_add_core!, + union(_pmd_math_global_keys, global_keys), + pmd_it_sym; + ref_extensions=ref_extensions, + kwargs... + ) +end + """ solve_mc_model( data::Dict{String,<:Any}, From 542f3dd20d8412848af228bf1a48902eb2e0a8b4 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 5 Aug 2024 13:16:38 -0600 Subject: [PATCH 02/99] WIP: add bases to certain elements - debugging changes --- src/data_model/transformations/eng2math.jl | 3 ++ src/data_model/transformations/ravens2math.jl | 31 ++++++++++--------- src/data_model/utils_ravens.jl | 4 +-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/data_model/transformations/eng2math.jl b/src/data_model/transformations/eng2math.jl index f82208778..00bafc858 100644 --- a/src/data_model/transformations/eng2math.jl +++ b/src/data_model/transformations/eng2math.jl @@ -223,6 +223,9 @@ function _map_eng2math( apply_pmd!(_map_eng2math_nw!, data_math, _data_eng; eng2math_passthrough=eng2math_passthrough, eng2math_extensions=eng2math_extensions) + @info "$(data_math)" + gfdgfdgf + if ismultinetwork(data_eng) _collect_nw_maps!(data_math) _collect_nw_bus_lookups!(data_math) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index b098de30f..cdb8cdfee 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -99,7 +99,7 @@ function _map_ravens2math( _settings = Dict("sbase_default" => basemva * 1e3, "voltage_scale_factor" => 1e3, "power_scale_factor" => 1e3, - "base_frequency" => 60.0, + "base_frequency" => get(_data_ravens, "BaseFrequency", 60.0), "vbases_default" => Dict{String,Real}() ) @@ -132,11 +132,11 @@ function _map_ravens2math( ) end + apply_pmd!(_map_ravens2math_nw!, data_math, _data_ravens; ravens2math_passthrough=ravens2math_passthrough, ravens2math_extensions=ravens2math_extensions) - @info "$(data_math)" - gfdgfdgf - apply_pmd!(_map_ravens2math_nw!, data_math, _data_ravens; ravens2math_passthrough=ravens2math_passthrough, ravens2math_extensions=ravens2math_extensions) + @info "$(data_math["branch"])" + gfdgfdgf if ismultinetwork(data_ravens) _collect_nw_maps!(data_math) @@ -193,6 +193,8 @@ end "converts ravens connectivity_node components into mathematical bus components" function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + _voltage_scale_factor = data_math["settings"]["voltage_scale_factor"]*sqrt(3) + for (name, ravens_obj) in get(data_ravens, "ConnectivityNode", Dict{String,Any}()) math_obj = _init_math_obj_ravens("bus", name, ravens_obj, length(data_math["bus"])+1; pass_props=pass_props) @@ -224,7 +226,7 @@ function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data # end if haskey(ravens_obj, "SvVoltage.v") - math_obj["vm"] = ravens_obj["SvVoltage.v"] + math_obj["vm"] = (ravens_obj["SvVoltage.v"]/_voltage_scale_factor) end if haskey(ravens_obj, "SvVoltage.angle") @@ -311,12 +313,12 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj["br_x"] = _impedance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.x") # b is given in mhos in CIM-RAVENS schema - math_obj["b_fr"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.b") - math_obj["b_to"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.b") + math_obj["b_fr"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.b"; freq=data_math["settings"]["base_frequency"]) + math_obj["b_to"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.b"; freq=data_math["settings"]["base_frequency"]) # g is given in mhos in CIM-RAVENS schema - math_obj["g_fr"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.g") - math_obj["g_to"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.g") + math_obj["g_fr"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.g"; freq=data_math["settings"]["base_frequency"]) + math_obj["g_to"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.g"; freq=data_math["settings"]["base_frequency"]) ## TODO:: these do not appear in JSON schema, are they needed? if yes, we need to represent them on CIM-RAVENS schema math_obj["angmin"] = get(ravens_obj, "vad_lb", fill(-60.0, nphases)) @@ -644,6 +646,7 @@ end function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) _data_ravens_energyconnection = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] + _voltage_scale_factor = data_math["settings"]["voltage_scale_factor"]*sqrt(3) for (name, ravens_obj) in get(_data_ravens_energyconnection, "EnergySource", Dict{String,Any}()) @@ -700,7 +703,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav # P, Q, Vg, etc. math_obj["pg"] = get(ravens_obj, "EnergySource.activePower", fill(0.0, nphases)).*fill(1.0, nphases) math_obj["qg"] = get(ravens_obj, "EnergySource.reactivePower", fill(0.0, nphases)).*fill(1.0, nphases) - math_obj["vg"] = get(ravens_obj, "EnergySource.voltageMagnitude", fill(1.0, nphases)).*fill(1.0, nphases) + math_obj["vg"] = fill(get(ravens_obj, "EnergySource.voltageMagnitude", _voltage_scale_factor)/_voltage_scale_factor, nphases) math_obj["pmin"] = get(ravens_obj, "EnergySource.pMin", fill(-Inf, nphases)).*fill(1.0, nphases) math_obj["pmax"] = get(ravens_obj, "EnergySource.pMax", fill( Inf, nphases)).*fill(1.0, nphases) math_obj["qmin"] = get(ravens_obj, "EnergySource.qMin", fill(-Inf, nphases)).*fill(1.0, nphases) @@ -733,10 +736,10 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav "grounded" => Bool[0, 0, 0], "name" => "_virtual_bus.energy_source.$name", "bus_type" => status == 0 ? 4 : control_mode == Int(ISOCHRONOUS) ? 3 : 2, - "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"], nphases), + "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor, nphases), "va" => rad2deg.(_wrap_to_pi.([-2*pi/nphases*(i-1)+deg2rad(ravens_obj["EnergySource.voltageAngle"]) for i in 1:nphases])), - "vmin" => fill(ravens_obj["EnergySource.voltageMagnitude"], nphases), - "vmax" => fill(ravens_obj["EnergySource.voltageMagnitude"], nphases), + "vmin" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor, nphases), + "vmax" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor, nphases), "vm_pair_lb" => deepcopy(get(ravens_obj, "EnergySource.vpairMin", Tuple{Any,Any,Real}[])), "vm_pair_ub" => deepcopy(get(ravens_obj, "EnergySource.vpairMax", Tuple{Any,Any,Real}[])), "source_id" => "energy_source.$name", @@ -787,7 +790,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav data_math["bus"]["$gen_bus"]["vmin"] = [vm_lb..., [0.0 for n in 1:(nconductors-nphases)]...] data_math["bus"]["$gen_bus"]["vmax"] = [vm_ub..., [Inf for n in 1:(nconductors-nphases)]...] - data_math["bus"]["$gen_bus"]["vm"] = [ravens_obj["EnergySource.voltageMagnitude"]..., [0.0 for n in 1:(nconductors-nphases)]...] + data_math["bus"]["$gen_bus"]["vm"] = [ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor..., [0.0 for n in 1:(nconductors-nphases)]...] data_math["bus"]["$gen_bus"]["va"] = [ravens_obj["EnergySource.voltageAngle"]..., [0.0 for n in 1:(nconductors-nphases)]...] bus_type = data_math["bus"]["$gen_bus"]["bus_type"] diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index cfa7a5821..55a63e7ee 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -32,7 +32,7 @@ end "converts admittance by multiplying by 2πωl" -function _admittance_conversion_ravens(data_eng::Dict{String,<:Any}, eng_obj::Dict{String,<:Any}, key::String) +function _admittance_conversion_ravens(data_eng::Dict{String,<:Any}, eng_obj::Dict{String,<:Any}, key::String; freq::Float64=60.0) _conductor_count = data_eng["PerLengthPhaseImpedance.conductorCount"] _admittance_matrix = zeros(Float64, _conductor_count, _conductor_count) @@ -46,7 +46,5 @@ function _admittance_conversion_ravens(data_eng::Dict{String,<:Any}, eng_obj::Di end end - # TODO: Default frequency - get actual frequency from ravens data - freq = 60.0 return _admittance_matrix .* get(eng_obj, "Conductor.length", 1.0) .* freq ./ 1e2 # divide by 2 to get both sides _to and _fr end From b5dea9733a3f29a8135c45baae7ebc007d2faf87 Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 7 Aug 2024 11:03:44 -0600 Subject: [PATCH 03/99] WIP: revise case3 ravens to math model code. --- src/data_model/transformations/eng2math.jl | 3 -- src/data_model/transformations/ravens2math.jl | 40 +++++++++---------- src/data_model/utils_ravens.jl | 24 +++++++++++ src/prob/common.jl | 6 ++- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/data_model/transformations/eng2math.jl b/src/data_model/transformations/eng2math.jl index 00bafc858..f82208778 100644 --- a/src/data_model/transformations/eng2math.jl +++ b/src/data_model/transformations/eng2math.jl @@ -223,9 +223,6 @@ function _map_eng2math( apply_pmd!(_map_eng2math_nw!, data_math, _data_eng; eng2math_passthrough=eng2math_passthrough, eng2math_extensions=eng2math_extensions) - @info "$(data_math)" - gfdgfdgf - if ismultinetwork(data_eng) _collect_nw_maps!(data_math) _collect_nw_bus_lookups!(data_math) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index cdb8cdfee..8771d6196 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -134,10 +134,6 @@ function _map_ravens2math( apply_pmd!(_map_ravens2math_nw!, data_math, _data_ravens; ravens2math_passthrough=ravens2math_passthrough, ravens2math_extensions=ravens2math_extensions) - - @info "$(data_math["branch"])" - gfdgfdgf - if ismultinetwork(data_ravens) _collect_nw_maps!(data_math) _collect_nw_bus_lookups!(data_math) @@ -193,7 +189,7 @@ end "converts ravens connectivity_node components into mathematical bus components" function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) - _voltage_scale_factor = data_math["settings"]["voltage_scale_factor"]*sqrt(3) + _voltage_scale_factor_sqrt3 = data_math["settings"]["voltage_scale_factor"]*sqrt(3) for (name, ravens_obj) in get(data_ravens, "ConnectivityNode", Dict{String,Any}()) @@ -226,7 +222,7 @@ function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data # end if haskey(ravens_obj, "SvVoltage.v") - math_obj["vm"] = (ravens_obj["SvVoltage.v"]/_voltage_scale_factor) + math_obj["vm"] = (ravens_obj["SvVoltage.v"]/_voltage_scale_factor_sqrt3) end if haskey(ravens_obj, "SvVoltage.angle") @@ -511,6 +507,8 @@ end function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) _data_ravens_energyconnection = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] + _power_scale_factor = data_math["settings"]["power_scale_factor"] + _voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] for (name, ravens_obj) in get(_data_ravens_energyconnection, "EnergyConsumer", Dict{Any,Dict{String,Any}}()) @@ -548,14 +546,14 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r math_obj["model"] = POWER # P and Q consumption - math_obj["pd"] = [ravens_obj["EnergyConsumer.p"]] - math_obj["qd"] = [ravens_obj["EnergyConsumer.q"]] + math_obj["pd"] = [ravens_obj["EnergyConsumer.p"]/_power_scale_factor] + math_obj["qd"] = [ravens_obj["EnergyConsumer.q"]/_power_scale_factor] end # Vnom base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") - math_obj["vnom_kv"] = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + math_obj["vnom_kv"] = (data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"]/_voltage_scale_factor)/(sqrt(3)/2) # Get voltage bounds for specific bus connected (TODO: see if it can be coverted to standalone function to avoid repetition) bus_info = string(math_obj["load_bus"]) @@ -646,7 +644,8 @@ end function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) _data_ravens_energyconnection = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] - _voltage_scale_factor = data_math["settings"]["voltage_scale_factor"]*sqrt(3) + _voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + _voltage_scale_factor_sqrt3 = data_math["settings"]["voltage_scale_factor"]*sqrt(3) for (name, ravens_obj) in get(_data_ravens_energyconnection, "EnergySource", Dict{String,Any}()) @@ -698,18 +697,18 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav # Vnom and add vbases_default from energy source base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") vnom = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] / sqrt(nphases) - data_math["settings"]["vbases_default"][connectivity_node] = vnom + data_math["settings"]["vbases_default"][connectivity_node] = vnom/_voltage_scale_factor # P, Q, Vg, etc. math_obj["pg"] = get(ravens_obj, "EnergySource.activePower", fill(0.0, nphases)).*fill(1.0, nphases) math_obj["qg"] = get(ravens_obj, "EnergySource.reactivePower", fill(0.0, nphases)).*fill(1.0, nphases) - math_obj["vg"] = fill(get(ravens_obj, "EnergySource.voltageMagnitude", _voltage_scale_factor)/_voltage_scale_factor, nphases) + math_obj["vg"] = fill(get(ravens_obj, "EnergySource.voltageMagnitude", _voltage_scale_factor_sqrt3)/_voltage_scale_factor_sqrt3, nphases) math_obj["pmin"] = get(ravens_obj, "EnergySource.pMin", fill(-Inf, nphases)).*fill(1.0, nphases) math_obj["pmax"] = get(ravens_obj, "EnergySource.pMax", fill( Inf, nphases)).*fill(1.0, nphases) math_obj["qmin"] = get(ravens_obj, "EnergySource.qMin", fill(-Inf, nphases)).*fill(1.0, nphases) math_obj["qmax"] = get(ravens_obj, "EnergySource.qMax", fill( Inf, nphases)).*fill(1.0, nphases) - #TODO: how to define configuration from terminals or add a connectionKind parameter? add to RAVENS schema? + # configuration math_obj["configuration"] = get(ravens_obj, "EnergySource.connectionKind", WYE) # TODO: Do we need a control_mode parameter for this? add to RAVENS schema @@ -736,10 +735,10 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav "grounded" => Bool[0, 0, 0], "name" => "_virtual_bus.energy_source.$name", "bus_type" => status == 0 ? 4 : control_mode == Int(ISOCHRONOUS) ? 3 : 2, - "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor, nphases), + "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor_sqrt3, nphases), "va" => rad2deg.(_wrap_to_pi.([-2*pi/nphases*(i-1)+deg2rad(ravens_obj["EnergySource.voltageAngle"]) for i in 1:nphases])), - "vmin" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor, nphases), - "vmax" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor, nphases), + "vmin" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor_sqrt3, nphases), + "vmax" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor_sqrt3, nphases), "vm_pair_lb" => deepcopy(get(ravens_obj, "EnergySource.vpairMin", Tuple{Any,Any,Real}[])), "vm_pair_ub" => deepcopy(get(ravens_obj, "EnergySource.vpairMax", Tuple{Any,Any,Real}[])), "source_id" => "energy_source.$name", @@ -763,17 +762,14 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav "source_id" => "energy_source.$name", "f_bus" => bus_obj["bus_i"], "t_bus" => data_math["bus_lookup"][connectivity_node], - # TODO: "f_connections" => math_obj["connections"], "t_connections" => math_obj["connections"], "angmin" => fill(-10.0, nconductors), "angmax" => fill( 10.0, nconductors), "c_rating_a" => fill(Inf, nconductors), "br_status" => status, - # "br_r" => _impedance_conversion_ravens(data_ravens, ravens_obj, "rs"), - # "br_x" => _impedance_conversion_ravens(data_ravens, ravens_obj, "xs"), - "br_r" => ravens_obj["EnergySource.r"], - "br_x" => ravens_obj["EnergySource.x"], + "br_r" => _impedance_conversion_ravens_energy_source(data_ravens, ravens_obj, "EnergySource.r", "EnergySource.r0"), + "br_x" => _impedance_conversion_ravens_energy_source(data_ravens, ravens_obj, "EnergySource.x", "EnergySource.x0"), "g_fr" => zeros(nconductors, nconductors), "g_to" => zeros(nconductors, nconductors), "b_fr" => zeros(nconductors, nconductors), @@ -790,7 +786,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav data_math["bus"]["$gen_bus"]["vmin"] = [vm_lb..., [0.0 for n in 1:(nconductors-nphases)]...] data_math["bus"]["$gen_bus"]["vmax"] = [vm_ub..., [Inf for n in 1:(nconductors-nphases)]...] - data_math["bus"]["$gen_bus"]["vm"] = [ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor..., [0.0 for n in 1:(nconductors-nphases)]...] + data_math["bus"]["$gen_bus"]["vm"] = [ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor_sqrt3..., [0.0 for n in 1:(nconductors-nphases)]...] data_math["bus"]["$gen_bus"]["va"] = [ravens_obj["EnergySource.voltageAngle"]..., [0.0 for n in 1:(nconductors-nphases)]...] bus_type = data_math["bus"]["$gen_bus"]["bus_type"] diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 55a63e7ee..27ca59a61 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -31,6 +31,30 @@ function _impedance_conversion_ravens(data_eng::Dict{String,Any}, eng_obj::Dict{ end +"converts impendance in Ohm/m by multiplying by length" +function _impedance_conversion_ravens_energy_source(data_eng::Dict{String,Any}, eng_obj::Dict{String,Any}, key1::String, key2::String) + # Default energy sources considered 3 phases + nphases = 3 + _impedance_matrix = zeros(Float64, nphases, nphases) + + z = get(eng_obj, key1, 0.0) + z0 = get(eng_obj, key2, 0.0) + + for i in 1:nphases + for j in 1:i + if(i==j) + _impedance_matrix[i, j] = z + ((z0 - z)/3) + else + _impedance_matrix[i, j] = (z0 - z)/3 + _impedance_matrix[j, i] = (z0 - z)/3 + end + end + end + + return _impedance_matrix .* get(eng_obj, "Conductor.length", 1.0) +end + + "converts admittance by multiplying by 2πωl" function _admittance_conversion_ravens(data_eng::Dict{String,<:Any}, eng_obj::Dict{String,<:Any}, key::String; freq::Float64=60.0) diff --git a/src/prob/common.jl b/src/prob/common.jl index 7f86adf3d..3508d93cb 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,6 +116,10 @@ function instantiate_mc_model( ) end + @info "$(data["load"])" + + DEFINIDOEN_instantiate_mc_model + return _IM.instantiate_model( data, model_type, @@ -158,7 +162,7 @@ function instantiate_mc_model_ravens( @info "$(data["load"])" - DEFINIDOEN_instantiate_mc_model + DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( data, From d616a1e0c7aef56c2d26b3e021a35f5c64e8119e Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 7 Aug 2024 15:33:19 -0600 Subject: [PATCH 04/99] WIP: case3 balanced working. Still missing transformers, shunts, generators, solar, and storage. --- src/data_model/transformations/ravens2math.jl | 163 +----------------- src/prob/common.jl | 12 +- 2 files changed, 10 insertions(+), 165 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 8771d6196..b7268016b 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -349,155 +349,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data _data_ravens_transformer = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"] for (name, ravens_obj) in get(_data_ravens_transformer, "PowerTransformer", Dict{Any,Dict{String,Any}}()) - - # Build map first, so we can update it as we decompose the transformer - push!(data_math["map"], Dict{String,Any}( - "from" => name, - "to" => String[], - "unmap_function" => "_map_math2ravens_transformer!", - )) - - to_map = data_math["map"][end]["to"] - - # _apply_xfmrcode!(ravens_obj, data_ravens) - - # PowerTransformerTank - if haskey(ravens_obj, "PowerTransformer.TransformerTank") - - @info "PowerTransformerTank ENTER" - @assert all(haskey(ravens_obj, k) for k in ["f_bus", "t_bus", "f_connections", "t_connections"]) "Incomplete definition of AL2W tranformer $name, aborting ravens2math conversion" - - nphases = length(ravens_obj["f_connections"]) - - math_obj = Dict{String,Any}( - "name" => name, - "source_id" => ravens_obj["source_id"], - "f_bus" => data_math["bus_lookup"][ravens_obj["f_bus"]], - "t_bus" => data_math["bus_lookup"][ravens_obj["t_bus"]], - "f_connections" => ravens_obj["f_connections"], - "t_connections" => ravens_obj["t_connections"], - "configuration" => get(ravens_obj, "configuration", WYE), - "tm_nom" => get(ravens_obj, "tm_nom", 1.0), - "tm_set" => get(ravens_obj, "tm_set", fill(1.0, nphases)), - "tm_fix" => get(ravens_obj, "tm_fix", fill(true, nphases)), - "polarity" => get(ravens_obj, "polarity", -1), - "sm_ub" => get(ravens_obj, "sm_ub", Inf), - "cm_ub" => get(ravens_obj, "cm_ub", Inf), - "status" => Int(get(ravens_obj, "status", ENABLED)), - "index" => length(data_math["transformer"])+1 - ) - - for k in [["tm_lb", "tm_ub"]; pass_props] - if haskey(ravens_obj, k) - math_obj[k] = ravens_obj[k] - end - end - - data_math["transformer"]["$(math_obj["index"])"] = math_obj - - push!(to_map, "transformer.$(math_obj["index"])") - - - # PowerTransformerEnd - else - - nrw = length(ravens_obj["bus"]) - - for w in 1:length(ravens_obj["PowerTransformer.PowerTransformerEnd"]) - - vnom = ravens_obj["PowerTransformer.PowerTransformerEnd"][w]["PowerTransformerEnd.ratedU"] - snom = ravens_obj["PowerTransformer.PowerTransformerEnd"][w]["PowerTransformerEnd.ratedS"] - - # calculate zbase in which the data is specified, and convert to SI - zbase = (vnom.^2) ./ snom - - # x_sc is specified with respect to first winding - x_sc = ravens_obj["xsc"] .* zbase[1] - - # rs is specified with respect to each winding - r_s = ravens_obj["rw"] .* zbase - - g_sh = (ravens_obj["noloadloss"]*snom[1])/vnom[1]^2 - b_sh = -(ravens_obj["cmag"]*snom[1])/vnom[1]^2 - - # data is measured externally, but we now refer it to the internal side - ratios = vnom/data_ravens["settings"]["voltage_scale_factor"] - x_sc = x_sc./ratios[1]^2 - r_s = r_s./ratios.^2 - g_sh = g_sh*ratios[1]^2 - b_sh = b_sh*ratios[1]^2 - - # convert x_sc from list of upper triangle elements to an explicit dict - y_sh = g_sh + im*b_sh - z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) - - dims = length(ravens_obj["tm_set"][1]) - transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh,ravens_obj["connections"][1]; nphases=dims, status=Int(ravens_obj["status"] == ENABLED)) - - # 2-WINDING TRANSFORMER - # make virtual bus and mark it for reduction - tm_nom = ravens_obj["configuration"][w]==DELTA ? ravens_obj["vm_nom"][w]*sqrt(3) : ravens_obj["vm_nom"][w] - transformer_2wa_obj = Dict{String,Any}( - "name" => "_virtual_transformer.$name.$w", - "source_id" => "_virtual_transformer.$(ravens_obj["source_id"]).$w", - "f_bus" => data_math["bus_lookup"][ravens_obj["bus"][w]], - "t_bus" => transformer_t_bus_w[w], - "tm_nom" => tm_nom, - "f_connections" => ravens_obj["connections"][w], - "t_connections" => get(data_math, "is_kron_reduced", false) ? ravens_obj["connections"][1] : collect(1:dims+1), - "configuration" => ravens_obj["configuration"][w], - "polarity" => ravens_obj["polarity"][w], - "tm_set" => ravens_obj["tm_set"][w], - "tm_fix" => ravens_obj["tm_fix"][w], - "sm_ub" => get(ravens_obj, "sm_ub", Inf), - "cm_ub" => get(ravens_obj, "cm_ub", Inf), - "status" => ravens_obj["status"] == DISABLED ? 0 : 1, - "index" => length(data_math["transformer"])+1 - ) - - for prop in [["tm_lb", "tm_ub", "tm_step"]; pass_props] - if haskey(ravens_obj, prop) - transformer_2wa_obj[prop] = ravens_obj[prop][w] - end - end - - data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj - - # add regcontrol items to math model - if haskey(ravens_obj,"controls") && !all(data_math["transformer"]["$(transformer_2wa_obj["index"])"]["tm_fix"]) - reg_obj = Dict{String,Any}( - "vreg" => ravens_obj["controls"]["vreg"][w], - "band" => ravens_obj["controls"]["band"][w], - "ptratio" => ravens_obj["controls"]["ptratio"][w], - "ctprim" => ravens_obj["controls"]["ctprim"][w], - "r" => ravens_obj["controls"]["r"][w], - "x" => ravens_obj["controls"]["x"][w], - ) - data_math["transformer"]["$(transformer_2wa_obj["index"])"]["controls"] = reg_obj - end - - if w==3 && ravens_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start - default_va = [0, -120, 120][ravens_obj["connections"][1][1]] - data_math["bus"]["$(transformer_2wa_obj["f_bus"])"]["va_start"] = haskey(data_ravens["bus"][ravens_obj["bus"][w]],"va_start") ? data_ravens["bus"][ravens_obj["bus"][w]]["va_start"] : [default_va, (default_va+180)] - idx = 0 - bus_ids = [] - t_bus = haskey(data_ravens, "line") ? [data["t_bus"] for (_,data) in data_ravens["line"] if data["f_bus"] == ravens_obj["bus"][w]] : [] - while length(t_bus)>0 || idx "") - math_obj["vnom_kv"] = (data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"]/_voltage_scale_factor)/(sqrt(3)/2) + base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + math_obj["vnom_kv"] = (base_voltage/_voltage_scale_factor)/(sqrt(3)/2) # Get voltage bounds for specific bus connected (TODO: see if it can be coverted to standalone function to avoid repetition) bus_info = string(math_obj["load_bus"]) bus_conn = data_math["bus"][bus_info] - base_voltage_id = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") - base_voltage = data_ravens["BaseVoltage"][base_voltage_id]["BaseVoltage.nominalVoltage"] op_limit_id = replace(split(data_ravens["ConnectivityNode"][connectivity_node]["ConnectivityNode.OperationalLimitSet"], "::")[2], "'" => "") - # op_limit_max = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][1]["VoltageLimit.value"]./base_voltage - # op_limit_min = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][2]["VoltageLimit.value"]./base_voltage - op_limit_max = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][1]["VoltageLimit.value"] - op_limit_min = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][2]["VoltageLimit.value"] + op_limit_max = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][1]["VoltageLimit.value"]./_voltage_scale_factor_sqrt3 + op_limit_min = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][2]["VoltageLimit.value"]./_voltage_scale_factor_sqrt3 _connections = Vector{Int64}() if haskey(ravens_obj, "EnergyConsumer.EnergyConsumerPhase") @@ -645,7 +494,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav _data_ravens_energyconnection = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] _voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] - _voltage_scale_factor_sqrt3 = data_math["settings"]["voltage_scale_factor"]*sqrt(3) + _voltage_scale_factor_sqrt3 = _voltage_scale_factor*sqrt(3) for (name, ravens_obj) in get(_data_ravens_energyconnection, "EnergySource", Dict{String,Any}()) diff --git a/src/prob/common.jl b/src/prob/common.jl index 3508d93cb..45c2bdfbf 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,9 +116,8 @@ function instantiate_mc_model( ) end - @info "$(data["load"])" - - DEFINIDOEN_instantiate_mc_model + # @info "$(data)" + # DEFINIDOEN_instantiate_mc_model return _IM.instantiate_model( data, @@ -147,8 +146,6 @@ function instantiate_mc_model_ravens( kwargs... ) - # @info "$(data)" - @info "Converting CIM-RAVENS data model to MATHEMATICAL first to build JuMP model" data = transform_data_model_ravens( @@ -160,9 +157,8 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - @info "$(data["load"])" - - DEFINIDOEN_instantiate_mc_model_ravens + # @info "$(data["bus"])" + # DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( data, From 15d72f8da128da49b6bb4ae9e15ed446fad67e3b Mon Sep 17 00:00:00 2001 From: Juan Ospina Date: Thu, 8 Aug 2024 09:41:08 -0600 Subject: [PATCH 05/99] Revise ravens schema (#2) * REF: revise and refactor ravens2math functions to simplify them. * FIX: issues with dictionary access in ravens funcs. --- src/data_model/transformations/ravens2math.jl | 485 +++++++----------- 1 file changed, 175 insertions(+), 310 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index b7268016b..5baf17208 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -77,23 +77,6 @@ function _map_ravens2math( _data_ravens = deepcopy(data_ravens) - ## TODO - # if kron_reduce - # apply_kron_reduction!(_data_ravens) - # apply_phase_projection_delta!(_data_ravens) - # end - - # if phase_project - # apply_phase_projection!(_data_ravens) - # end - - - # # TODO: Add vbases to settings - # _vbases_default = Dict("vbases_default" => Dict{String, Real}()) - # for (name, ravens_obj) in get(data_ravens, "BaseVoltage", Dict{String,Any}()) - # _vbases_default = Dict(name => ravens_obj["BaseVoltage.nominalVoltage"]) - # end - # TODO: Add settings (defaults) basemva = 100 _settings = Dict("sbase_default" => basemva * 1e3, @@ -168,169 +151,113 @@ function _map_ravens2math_nw!(data_math::Dict{String,<:Any}, data_ravens::Dict{S ravens2math_func!(data_math, data_ravens) end - ## TODO: See if this is still neccesary for RAVENS - # # post fix - # if !get(data_math, "is_kron_reduced", false) - # #TODO fix this in place / throw error instead? IEEE8500 leads to switches - # # with 3x3 R matrices but only 1 phase - # #NOTE: Don't do this when kron-reducing, it will undo the padding - # _slice_branches!(data_math) - # end - find_conductor_ids!(data_math) _map_conductor_ids!(data_math) - - # TODO: See if this is still neccesary for RAVENS _map_settings_vbases_default!(data_math) end -"converts ravens connectivity_node components into mathematical bus components" +""" +Converts ravens connectivity_node components into mathematical bus components. +""" function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + voltage_scale_factor_sqrt3 = data_math["settings"]["voltage_scale_factor"] * sqrt(3) + connectivity_nodes = get(data_ravens, "ConnectivityNode", Dict{String,Any}()) - _voltage_scale_factor_sqrt3 = data_math["settings"]["voltage_scale_factor"]*sqrt(3) - - for (name, ravens_obj) in get(data_ravens, "ConnectivityNode", Dict{String,Any}()) + for (name, ravens_obj) in connectivity_nodes + index = length(data_math["bus"]) + 1 + math_obj = _init_math_obj_ravens("bus", name, ravens_obj, index; pass_props=pass_props) - math_obj = _init_math_obj_ravens("bus", name, ravens_obj, length(data_math["bus"])+1; pass_props=pass_props) - math_obj["bus_i"] = math_obj["index"] + # Set basic bus properties + math_obj["bus_i"] = index math_obj["source_id"] = "bus.$name" - - # default bus_type, change as elements are added (e.g., load, generator, source). - math_obj["bus_type"] = 1 - - # TODO: needed? - default grounded + math_obj["bus_type"] = 1 # Default bus_type, will be modified as needed math_obj["grounded"] = Bool[0, 0, 0] + math_obj["vm_pair_lb"] = Tuple{Any, Any, Real}[] + math_obj["vm_pair_ub"] = Tuple{Any, Any, Real}[] - ## TODO - # # take care of grounding; convert to shunt if lossy - # grounded_perfect, shunts = _convert_grounding(ravens_obj["terminals"], ravens_obj["grounded"], ravens_obj["rg"], ravens_obj["xg"]) - - # math_obj["grounded"] = grounded_perfect - # to_sh = [] - # for (sh_connections, sh_y) in shunts - # sh_index = length(data_math["shunt"]) + 1 - # data_math["shunt"]["$sh_index"] = Dict( - # "index" => sh_index, - # "shunt_bus" => math_obj["bus_i"], - # "connections" => sh_connections, - # "gs" => real.(sh_y), - # "bs" => imag.(sh_y), - # ) - # push!(to_sh, "shunt.$sh_index") - # end - + # Set voltage magnitude and angle if haskey(ravens_obj, "SvVoltage.v") - math_obj["vm"] = (ravens_obj["SvVoltage.v"]/_voltage_scale_factor_sqrt3) + math_obj["vm"] = (ravens_obj["SvVoltage.v"] / voltage_scale_factor_sqrt3) end if haskey(ravens_obj, "SvVoltage.angle") math_obj["va"] = ravens_obj["SvVoltage.angle"] end - # TODO: add vm_pair_lb/ub (may not be needed!) - math_obj["vm_pair_lb"] = Tuple{Any, Any, Real}[] - math_obj["vm_pair_ub"] = Tuple{Any, Any, Real}[] - - data_math["bus"]["$(math_obj["index"])"] = math_obj - - if !haskey(data_math, "bus_lookup") - data_math["bus_lookup"] = Dict{Any,Int}() - end + # Store the mathematical bus object + data_math["bus"]["$(index)"] = math_obj - data_math["bus_lookup"][name] = math_obj["index"] + # Update bus lookup if necessary + data_math["bus_lookup"] = get(data_math, "bus_lookup", Dict{Any,Int}()) + data_math["bus_lookup"][name] = index - push!(data_math["map"], Dict{String,Any}( + # Map the ravens object to the math object + push!(data_math["map"], Dict( "from" => name, - "to" => "bus.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_bus!", + "to" => "bus.$index", + "unmap_function" => "_map_math2ravens_bus!" )) end end -"converts ravensineering conductors (e.g., ACLineSegments) into mathematical branches" +""" +Converts ravens conductors (e.g., ACLineSegments) into mathematical branches. +""" function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + conductors = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["Conductor"] - _data_ravens_conductor = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["Conductor"] - - for (name, ravens_obj) in get(_data_ravens_conductor, "ACLineSegment", Dict{Any,Dict{String,Any}}()) - - math_obj = _init_math_obj_ravens("ac_line_segment", name, ravens_obj, length(data_math["branch"])+1; pass_props=pass_props) + for (name, ravens_obj) in get(conductors, "ACLineSegment", Dict{Any,Dict{String,Any}}()) + math_obj = _init_math_obj_ravens("ac_line_segment", name, ravens_obj, length(data_math["branch"]) + 1; pass_props=pass_props) nphases = length(ravens_obj["ACLineSegment.ACLineSegmentPhase"]) + terminals = ravens_obj["ConductingEquipment.Terminals"] - f_connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") - t_connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][2]["Terminal.ConnectivityNode"], "::")[2], "'" => "") - math_obj["f_bus"] = data_math["bus_lookup"][f_connectivity_node] - math_obj["t_bus"] = data_math["bus_lookup"][t_connectivity_node] + f_node = replace(split(terminals[1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + t_node = replace(split(terminals[2]["Terminal.ConnectivityNode"], "::")[2], "'" => "") - # define the number of terminals (i.e., phases) that the bus/es have, based on the lines - if nphases >= 3 - data_math["bus"][string(math_obj["f_bus"])]["terminals"]= [i for i = 1:nphases] - data_math["bus"][string(math_obj["t_bus"])]["terminals"]= [i for i = 1:nphases] - else - _terminals = Vector{Int64}() - for phase_info in ravens_obj["ACLineSegment.ACLineSegmentPhase"] - phase = phase_info["ACLineSegmentPhase.phase"] - if phase == "SinglePhaseKind.A" - push!(_terminals, 1) - elseif phase == "SinglePhaseKind.B" - push!(_terminals, 2) - elseif phase == "SinglePhaseKind.C" - push!(_terminals, 3) - else - @error("Terminals/Phases for buses '$(f_connectivity_node)' and '$(t_connectivity_node)' not recognized. Check your model!") - end - end - data_math["bus"][string(math_obj["f_bus"])]["terminals"]= _terminals - data_math["bus"][string(math_obj["t_bus"])]["terminals"]= _terminals - end + math_obj["f_bus"] = data_math["bus_lookup"][f_node] + math_obj["t_bus"] = data_math["bus_lookup"][t_node] - # Initilize vmin and vmax in buses - data_math["bus"][string(math_obj["f_bus"])]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(math_obj["f_bus"])]["vmax"] = fill(Inf, nphases) - - data_math["bus"][string(math_obj["t_bus"])]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(math_obj["t_bus"])]["vmax"] = fill(Inf, nphases) - - #------------------------------------------------------------------------------- - - # f_ and t_connections for the lines/branches - math_obj["f_connections"] = data_math["bus"][string(math_obj["f_bus"])]["terminals"] - math_obj["t_connections"] = data_math["bus"][string(math_obj["t_bus"])]["terminals"] + phase_map = Dict("SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, "SinglePhaseKind.C" => 3) + bus_terminals = nphases >= 3 ? collect(1:nphases) : [phase_map[phase["ACLineSegmentPhase.phase"]] for phase in ravens_obj["ACLineSegment.ACLineSegmentPhase"]] + for bus in [math_obj["f_bus"], math_obj["t_bus"]] + data_math["bus"][string(bus)]["terminals"] = bus_terminals + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + end - _perlengthimpedance_name = replace(split(ravens_obj["ACLineSegment.PerLengthImpedance"], "::")[2], "'" => "") - _perlengthimpedance_data = data_ravens["PerLengthLineParameter"]["PerLengthImpedance"]["PerLengthPhaseImpedance"][_perlengthimpedance_name] + math_obj["f_connections"] = bus_terminals + math_obj["t_connections"] = bus_terminals - math_obj["br_r"] = _impedance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.r") - math_obj["br_x"] = _impedance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.x") + impedance_name = replace(split(ravens_obj["ACLineSegment.PerLengthImpedance"], "::")[2], "'" => "") + impedance_data = data_ravens["PerLengthLineParameter"]["PerLengthImpedance"]["PerLengthPhaseImpedance"][impedance_name] - # b is given in mhos in CIM-RAVENS schema - math_obj["b_fr"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.b"; freq=data_math["settings"]["base_frequency"]) - math_obj["b_to"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.b"; freq=data_math["settings"]["base_frequency"]) + math_obj["br_r"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.r") + math_obj["br_x"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.x") - # g is given in mhos in CIM-RAVENS schema - math_obj["g_fr"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.g"; freq=data_math["settings"]["base_frequency"]) - math_obj["g_to"] = _admittance_conversion_ravens(_perlengthimpedance_data, ravens_obj, "PhaseImpedanceData.g"; freq=data_math["settings"]["base_frequency"]) + base_freq = data_math["settings"]["base_frequency"] + for (key, param) in [("b_fr", "PhaseImpedanceData.b"), ("b_to", "PhaseImpedanceData.b"), ("g_fr", "PhaseImpedanceData.g"), ("g_to", "PhaseImpedanceData.g")] + math_obj[key] = _admittance_conversion_ravens(impedance_data, ravens_obj, param; freq=base_freq) + end - ## TODO:: these do not appear in JSON schema, are they needed? if yes, we need to represent them on CIM-RAVENS schema math_obj["angmin"] = get(ravens_obj, "vad_lb", fill(-60.0, nphases)) - math_obj["angmax"] = get(ravens_obj, "vad_ub", fill( 60.0, nphases)) + math_obj["angmax"] = get(ravens_obj, "vad_ub", fill(60.0, nphases)) - # Operational Limits - _oplimitset_id = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["ACDCTerminal.OperationalLimitSet"], "::")[2], "'" => "") - _oplimitset = data_ravens["OperationalLimitSet"][_oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][2] # [1] is Normal amps, [2] is Emergency amps - by default use emerg amps + oplimitset_id = replace(split(terminals[1]["ACDCTerminal.OperationalLimitSet"], "::")[2], "'" => "") + oplimitset = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][2] - for (f_key, t_key) in [("CurrentLimit.value", "c_rating_a"), ("CurrentLimit.value", "c_rating_b"), ("CurrentLimit.value", "c_rating_c"), - ("ApparentPowerLimit.value", "rate_a"), ("ApparentPowerLimit.value", "rate_b"), ("ApparentPowerLimit.value", "rate_c")] - math_obj[t_key] = haskey(_oplimitset, f_key) ? fill(_oplimitset[f_key], nphases) : fill(Inf, nphases) + limit_keys = [("CurrentLimit.value", "c_rating_a"), ("CurrentLimit.value", "c_rating_b"), ("CurrentLimit.value", "c_rating_c"), + ("ApparentPowerLimit.value", "rate_a"), ("ApparentPowerLimit.value", "rate_b"), ("ApparentPowerLimit.value", "rate_c")] + + for (f_key, t_key) in limit_keys + math_obj[t_key] = haskey(oplimitset, f_key) ? fill(oplimitset[f_key], nphases) : fill(Inf, nphases) end math_obj["br_status"] = get(ravens_obj, "ConductingEquipment.SvStatus", 1) - data_math["branch"]["$(math_obj["index"])"] = math_obj push!(data_math["map"], Dict{String,Any}( @@ -338,10 +265,11 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: "to" => "branch.$(math_obj["index"])", "unmap_function" => "_map_math2ravens_line!", )) - end + end end + # TODO: Transformers need a lot of changes/refactors!!! "converts ravensineering n-winding transformers into mathematical ideal 2-winding lossless transformer branches and impedance branches to represent the loss model" function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) @@ -353,297 +281,234 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data end - -"converts ravensineering load components into mathematical load components" +""" +Converts ravens load components into mathematical load components. +""" function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] + power_scale_factor = data_math["settings"]["power_scale_factor"] + voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + voltage_scale_factor_sqrt3 = voltage_scale_factor * sqrt(3) - _data_ravens_energyconnection = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] - _power_scale_factor = data_math["settings"]["power_scale_factor"] - _voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] - _voltage_scale_factor_sqrt3 = _voltage_scale_factor*sqrt(3) - - for (name, ravens_obj) in get(_data_ravens_energyconnection, "EnergyConsumer", Dict{Any,Dict{String,Any}}()) - - # Get load response characteristic - load_response_characts = replace(split(ravens_obj["EnergyConsumer.LoadResponseCharacteristic"], "::")[2], "'" => "") + for (name, ravens_obj) in get(conducting_equipment, "EnergyConsumer", Dict{Any,Dict{String,Any}}()) + math_obj = _init_math_obj_ravens("energy_consumer", name, ravens_obj, length(data_math["load"]) + 1; pass_props=pass_props) - # Initialize energy consumer object - math_obj = _init_math_obj_ravens("energy_consumer", name, ravens_obj, length(data_math["load"])+1; pass_props=pass_props) - - # Get Bus/ConnectivityNode + # Set the load bus based on connectivity node connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") math_obj["load_bus"] = data_math["bus_lookup"][connectivity_node] - # Model of the Load/EnergyConsumer + # Handle Load Response Characteristics + load_response_characts = replace(split(ravens_obj["EnergyConsumer.LoadResponseCharacteristic"], "::")[2], "'" => "") if load_response_characts == "Constant Z" - + math_obj["model"] = IMPEDANCE elseif load_response_characts == "Motor" - + @error("Load model not supported yet!") elseif load_response_characts == "Mix Motor/Res" - + @error("Load model not supported yet!") elseif load_response_characts == "Constant I" - + math_obj["model"] = CURRENT elseif load_response_characts == "Variable P, Fixed Q" - + @error("Load model not supported yet!") elseif load_response_characts == "Variable P, Fixed X" - - # "Constant kVA" : default + @error("Load model not supported yet!") else - if load_response_characts != "Constant kVA" @warn("Load model (response characteristic) for $(name) not supported! Defaulting to 'Constant kVA'") end - - # Add the model of the load based on loadresponsecharacteristic + # Set default model and consumption values math_obj["model"] = POWER - - # P and Q consumption - math_obj["pd"] = [ravens_obj["EnergyConsumer.p"]/_power_scale_factor] - math_obj["qd"] = [ravens_obj["EnergyConsumer.q"]/_power_scale_factor] - end - # Vnom + # Set p and q + math_obj["pd"] = [ravens_obj["EnergyConsumer.p"] / power_scale_factor] + math_obj["qd"] = [ravens_obj["EnergyConsumer.q"] / power_scale_factor] + + # Set the nominal voltage base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - math_obj["vnom_kv"] = (base_voltage/_voltage_scale_factor)/(sqrt(3)/2) + math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor) / (sqrt(3) / 2) - # Get voltage bounds for specific bus connected (TODO: see if it can be coverted to standalone function to avoid repetition) + # Set voltage bounds for the bus connected bus_info = string(math_obj["load_bus"]) bus_conn = data_math["bus"][bus_info] - op_limit_id = replace(split(data_ravens["ConnectivityNode"][connectivity_node]["ConnectivityNode.OperationalLimitSet"], "::")[2], "'" => "") - op_limit_max = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][1]["VoltageLimit.value"]./_voltage_scale_factor_sqrt3 - op_limit_min = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"][2]["VoltageLimit.value"]./_voltage_scale_factor_sqrt3 + op_limits = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"] + op_limit_max = op_limits[1]["VoltageLimit.value"] / voltage_scale_factor_sqrt3 + op_limit_min = op_limits[2]["VoltageLimit.value"] / voltage_scale_factor_sqrt3 - _connections = Vector{Int64}() + # Handle phase-specific or three-phase connection + phase_map = Dict("SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, "SinglePhaseKind.C" => 3) if haskey(ravens_obj, "EnergyConsumer.EnergyConsumerPhase") + connections = Vector{Int64}() for phase_info in ravens_obj["EnergyConsumer.EnergyConsumerPhase"] - phase = phase_info["EnergyConsumerPhase.phase"] - if phase == "SinglePhaseKind.A" - phase_index = findfirst(==(1), bus_conn["terminals"]) - bus_conn["vmax"][phase_index] = op_limit_max - bus_conn["vmin"][phase_index] = op_limit_min - push!(_connections, 1) - elseif phase == "SinglePhaseKind.B" - phase_index = findfirst(==(2), bus_conn["terminals"]) - bus_conn["vmax"][phase_index] = op_limit_max - bus_conn["vmin"][phase_index] = op_limit_min - push!(_connections, 2) - elseif phase == "SinglePhaseKind.C" - phase_index = findfirst(==(3), bus_conn["terminals"]) - bus_conn["vmax"][phase_index] = op_limit_max - bus_conn["vmin"][phase_index] = op_limit_min - push!(_connections, 3) - else - @error("Terminals/Phases for buses '$(f_connectivity_node)' and '$(t_connectivity_node)' not recognized. Check your model!") - end + phase = phase_map[phase_info["EnergyConsumerPhase.phase"]] + phase_index = findfirst(==(phase), bus_conn["terminals"]) + bus_conn["vmax"][phase_index] = op_limit_max + bus_conn["vmin"][phase_index] = op_limit_min + push!(connections, phase) end - math_obj["connections"] = _connections + math_obj["connections"] = connections else - # assumes it is a three-phase connection N = length(bus_conn["terminals"]) bus_conn["vmax"] = fill(op_limit_max, N) bus_conn["vmin"] = fill(op_limit_min, N) math_obj["connections"] = bus_conn["terminals"] end - # TODO: Configuration - _config = ravens_obj["EnergyConsumer.phaseConnection"] - if _config == "PhaseShuntConnectionKind.Y" - math_obj["configuration"] = WYE - elseif _config == "PhaseShuntConnectionKind.D" - math_obj["configuration"] = DELTA - elseif _config == "PhaseShuntConnectionKind.Yn" - elseif _config == "PhaseShuntConnectionKind.I" - elseif _config == "PhaseShuntConnectionKind.G" + # Set the configuration + # TODO: ADD: "PhaseShuntConnectionKind.Yn", "PhaseShuntConnectionKind.I", "PhaseShuntConnectionKind.G" + config_map = Dict("PhaseShuntConnectionKind.Y" => WYE, "PhaseShuntConnectionKind.D" => DELTA) + config = get(config_map, ravens_obj["EnergyConsumer.phaseConnection"], nothing) + if config !== nothing + math_obj["configuration"] = config else @error("Configuration of load $(name) is not supported.") end - # Status + # Set status, dispatchable flag, and index math_obj["status"] = ravens_obj["ConductingEquipment.SvStatus"] - - # TODO: Dispatchable? default=0 math_obj["dispatchable"] = 0 - - # Index data_math["load"]["$(math_obj["index"])"] = math_obj - # TODO: Assign 'grounding' to corresponding connectivity node + # Handle grounding if ravens_obj["EnergyConsumer.grounded"] == "true" bus_conn["grounded"] = Bool[0, 0, 0] end - # Revise bus_type of connectivity node to PQ bus + # Set bus type to PQ bus bus_conn["bus_type"] = 1 + # Map the object push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => "load.$(math_obj["index"])", "unmap_function" => "_map_math2ravens_load!", )) - - end + end end -#TODO: -"converts ravensineering voltage sources into mathematical generators and (if needed) impedance branches to represent the loss model" +""" +Converts ravens voltage sources into mathematical generators and (if needed) impedance branches to represent the loss model. +""" function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] + voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + voltage_scale_factor_sqrt3 = voltage_scale_factor * sqrt(3) - _data_ravens_energyconnection = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] - _voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] - _voltage_scale_factor_sqrt3 = _voltage_scale_factor*sqrt(3) - - for (name, ravens_obj) in get(_data_ravens_energyconnection, "EnergySource", Dict{String,Any}()) - - math_obj = _init_math_obj_ravens("energy_source", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) + for (name, ravens_obj) in get(conducting_equipment, "EnergySource", Dict{Any,Dict{String,Any}}()) + math_obj = _init_math_obj_ravens("energy_source", name, ravens_obj, length(data_math["gen"]) + 1; pass_props=pass_props) math_obj["name"] = "_virtual_gen.energy_source.$name" - # get connectivity node info. (bus info) + # Get connectivity node info (bus info) connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") - math_obj["gen_bus"] = gen_bus = data_math["bus_lookup"][connectivity_node] + gen_bus = data_math["bus_lookup"][connectivity_node] + math_obj["gen_bus"] = gen_bus bus_conn = data_math["bus"][string(gen_bus)] + bus_conn["bus_type"] = 3 # Set bus type to PV bus - # Revise bus_type of connectivity node to PV bus - bus_conn["bus_type"] = 3 + # Handle phase-specific or three-phase connection + connections = Vector{Int64}() + nconductors = length(get(ravens_obj, "EnergySource.EnergySourcePhase", bus_conn["terminals"])) - nconductors = 0 - _connections = Vector{Int64}() if haskey(ravens_obj, "EnergySource.EnergySourcePhase") - - nconductors = length(ravens_obj["EnergySource.EnergySourcePhase"]) - # TODO: how to redefine the kron reduction? - # nphases = get(ravens_obj, "configuration", WYE) == WYE && !get(data_ravens, "is_kron_reduced", false) ? nconductors - 1 : nconductors - nphases = nconductors - + phase_map = Dict("SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, "SinglePhaseKind.C" => 3) for phase_info in ravens_obj["EnergySource.EnergySourcePhase"] - phase = phase_info["EnergySourcePhase.phase"] - if phase == "SinglePhaseKind.A" - push!(_connections, 1) - elseif phase == "SinglePhaseKind.B" - push!(_connections, 2) - elseif phase == "SinglePhaseKind.C" - push!(_connections, 3) - else - @error("Connections for energy source '$(name)' not recognized. Check your model!") - end + phase = phase_map[phase_info["EnergySourcePhase.phase"]] + push!(connections, phase) end - - math_obj["connections"] = _connections + math_obj["connections"] = connections else - # assumes it is a three-phase connection - nconductors = length(bus_conn["terminals"]) - # TODO: how to redefine the kron reduction? we need - # nphases = get(ravens_obj, "configuration", WYE) == WYE && !get(data_ravens, "is_kron_reduced", false) ? nconductors - 1 : nconductors - nphases = nconductors math_obj["connections"] = bus_conn["terminals"] end - math_obj["gen_status"] = status = Int(ravens_obj["ConductingEquipment.SvStatus"]) - - # Vnom and add vbases_default from energy source - base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") - vnom = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] / sqrt(nphases) - data_math["settings"]["vbases_default"][connectivity_node] = vnom/_voltage_scale_factor - - # P, Q, Vg, etc. - math_obj["pg"] = get(ravens_obj, "EnergySource.activePower", fill(0.0, nphases)).*fill(1.0, nphases) - math_obj["qg"] = get(ravens_obj, "EnergySource.reactivePower", fill(0.0, nphases)).*fill(1.0, nphases) - math_obj["vg"] = fill(get(ravens_obj, "EnergySource.voltageMagnitude", _voltage_scale_factor_sqrt3)/_voltage_scale_factor_sqrt3, nphases) - math_obj["pmin"] = get(ravens_obj, "EnergySource.pMin", fill(-Inf, nphases)).*fill(1.0, nphases) - math_obj["pmax"] = get(ravens_obj, "EnergySource.pMax", fill( Inf, nphases)).*fill(1.0, nphases) - math_obj["qmin"] = get(ravens_obj, "EnergySource.qMin", fill(-Inf, nphases)).*fill(1.0, nphases) - math_obj["qmax"] = get(ravens_obj, "EnergySource.qMax", fill( Inf, nphases)).*fill(1.0, nphases) - - # configuration + # Generator status and configuration + math_obj["gen_status"] = Int(ravens_obj["ConductingEquipment.SvStatus"]) math_obj["configuration"] = get(ravens_obj, "EnergySource.connectionKind", WYE) - # TODO: Do we need a control_mode parameter for this? add to RAVENS schema - math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "EnergySource.connectionKind", ISOCHRONOUS)) + # Vnom and vbases_default + base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + vnom = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] / sqrt(nconductors) + data_math["settings"]["vbases_default"][connectivity_node] = vnom / voltage_scale_factor + + # Power, voltage, and limits + nphases = nconductors # You can adjust nphases based on your specific kron reduction logic if needed + fill_values = (v) -> fill(v, nphases) + math_obj["pg"] = get(ravens_obj, "EnergySource.activePower", fill_values(0.0)) + math_obj["qg"] = get(ravens_obj, "EnergySource.reactivePower", fill_values(0.0)) + math_obj["vg"] = fill(get(ravens_obj, "EnergySource.voltageMagnitude", voltage_scale_factor_sqrt3) / voltage_scale_factor_sqrt3, nphases) + math_obj["pmin"] = get(ravens_obj, "EnergySource.pMin", fill_values(-Inf)) + math_obj["pmax"] = get(ravens_obj, "EnergySource.pMax", fill_values(Inf)) + math_obj["qmin"] = get(ravens_obj, "EnergySource.qMin", fill_values(-Inf)) + math_obj["qmax"] = get(ravens_obj, "EnergySource.qMax", fill_values(Inf)) + + # Control mode and source ID + math_obj["control_mode"] = Int(get(ravens_obj, "EnergySource.connectionKind", ISOCHRONOUS)) math_obj["source_id"] = "energy_source.$name" - # TODO: inside this function, there are elements that do not exist in the RAVENS schema, so the default is used. + # Add generator cost model _add_gen_cost_model!(math_obj, ravens_obj) + # Check for impedance and adjust bus type if necessary map_to = "gen.$(math_obj["index"])" - if !all(isapprox.(get(ravens_obj, "EnergySource.r", zeros(1, 1)), 0)) && !all(isapprox.(get(ravens_obj, "EnergySource.x", zeros(1, 1)), 0)) + bus_conn["bus_type"] = 1 # Virtual bus becomes the new slack bus - # Revise bus_type of connectivity node to PV bus (virtual bus becomes the new slack bus) - bus_conn["bus_type"] = 1 - - f_bus = deepcopy(data_math["bus"]["$(math_obj["gen_bus"])"]) - - bus_obj = Dict{String,Any}( - "bus_i" => length(data_math["bus"])+1, - "index" => length(data_math["bus"])+1, + bus_obj = Dict( + "bus_i" => length(data_math["bus"]) + 1, + "index" => length(data_math["bus"]) + 1, "terminals" => math_obj["connections"], - # TODO: grounded energyosurce default? "grounded" => Bool[0, 0, 0], "name" => "_virtual_bus.energy_source.$name", - "bus_type" => status == 0 ? 4 : control_mode == Int(ISOCHRONOUS) ? 3 : 2, - "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor_sqrt3, nphases), - "va" => rad2deg.(_wrap_to_pi.([-2*pi/nphases*(i-1)+deg2rad(ravens_obj["EnergySource.voltageAngle"]) for i in 1:nphases])), - "vmin" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor_sqrt3, nphases), - "vmax" => fill(ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor_sqrt3, nphases), + "bus_type" => math_obj["gen_status"] == 0 ? 4 : math_obj["control_mode"] == Int(ISOCHRONOUS) ? 3 : 2, + "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), + "va" => rad2deg.(_wrap_to_pi.([-2 * π / nphases * (i - 1) + deg2rad(ravens_obj["EnergySource.voltageAngle"]) for i in 1:nphases])), + "vmin" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), + "vmax" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), "vm_pair_lb" => deepcopy(get(ravens_obj, "EnergySource.vpairMin", Tuple{Any,Any,Real}[])), "vm_pair_ub" => deepcopy(get(ravens_obj, "EnergySource.vpairMax", Tuple{Any,Any,Real}[])), "source_id" => "energy_source.$name", ) - # TODO: - # for (i,t) in enumerate(math_obj["connections"]) - # if data_math["bus"]["$(data_math["bus_lookup"][ravens_obj["bus"]])"]["grounded"][i] - # bus_obj["vm"][i] = 0 - # bus_obj["vmin"][i] = 0 - # bus_obj["vmax"][i] = Inf - # end - # end - - math_obj["gen_bus"] = gen_bus = bus_obj["bus_i"] - + math_obj["gen_bus"] = bus_obj["bus_i"] data_math["bus"]["$(bus_obj["index"])"] = bus_obj - branch_obj = Dict{String,Any}( + branch_obj = Dict( "name" => "_virtual_branch.energy_source.$name", "source_id" => "energy_source.$name", "f_bus" => bus_obj["bus_i"], - "t_bus" => data_math["bus_lookup"][connectivity_node], + "t_bus" => gen_bus, "f_connections" => math_obj["connections"], "t_connections" => math_obj["connections"], "angmin" => fill(-10.0, nconductors), - "angmax" => fill( 10.0, nconductors), + "angmax" => fill(10.0, nconductors), "c_rating_a" => fill(Inf, nconductors), - "br_status" => status, + "br_status" => math_obj["gen_status"], "br_r" => _impedance_conversion_ravens_energy_source(data_ravens, ravens_obj, "EnergySource.r", "EnergySource.r0"), "br_x" => _impedance_conversion_ravens_energy_source(data_ravens, ravens_obj, "EnergySource.x", "EnergySource.x0"), "g_fr" => zeros(nconductors, nconductors), "g_to" => zeros(nconductors, nconductors), "b_fr" => zeros(nconductors, nconductors), "b_to" => zeros(nconductors, nconductors), - "index" => length(data_math["branch"])+1 + "index" => length(data_math["branch"]) + 1 ) data_math["branch"]["$(branch_obj["index"])"] = branch_obj - map_to = [map_to, "bus.$(bus_obj["index"])", "branch.$(branch_obj["index"])"] else - vm_lb = control_mode == Int(ISOCHRONOUS) ? ravens_obj["EnergySource.voltageMagnitude"] : get(ravens_obj, "EnergySource.vMin", fill(0.0, nphases)) - vm_ub = control_mode == Int(ISOCHRONOUS) ? ravens_obj["EnergySource.voltageMagnitude"] : get(ravens_obj, "EnergySource.vMax", fill(Inf, nphases)) + # Handle bus voltage limits if no impedance is present + vm_lb = math_obj["control_mode"] == Int(ISOCHRONOUS) ? ravens_obj["EnergySource.voltageMagnitude"] : get(ravens_obj, "EnergySource.vMin", fill(0.0, nphases)) + vm_ub = math_obj["control_mode"] == Int(ISOCHRONOUS) ? ravens_obj["EnergySource.voltageMagnitude"] : get(ravens_obj, "EnergySource.vMax", fill(Inf, nphases)) - data_math["bus"]["$gen_bus"]["vmin"] = [vm_lb..., [0.0 for n in 1:(nconductors-nphases)]...] - data_math["bus"]["$gen_bus"]["vmax"] = [vm_ub..., [Inf for n in 1:(nconductors-nphases)]...] - data_math["bus"]["$gen_bus"]["vm"] = [ravens_obj["EnergySource.voltageMagnitude"]/_voltage_scale_factor_sqrt3..., [0.0 for n in 1:(nconductors-nphases)]...] - data_math["bus"]["$gen_bus"]["va"] = [ravens_obj["EnergySource.voltageAngle"]..., [0.0 for n in 1:(nconductors-nphases)]...] + data_math["bus"]["$gen_bus"]["vmin"] = [vm_lb..., fill(0.0, nconductors - nphases)...] + data_math["bus"]["$gen_bus"]["vmax"] = [vm_ub..., fill(Inf, nconductors - nphases)...] + data_math["bus"]["$gen_bus"]["vm"] = fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases) + data_math["bus"]["$gen_bus"]["va"] = fill(ravens_obj["EnergySource.voltageAngle"], nphases) - bus_type = data_math["bus"]["$gen_bus"]["bus_type"] - data_math["bus"]["$gen_bus"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) + data_math["bus"]["$gen_bus"]["bus_type"] = _compute_bus_type(bus_conn["bus_type"], math_obj["gen_status"], math_obj["control_mode"]) end data_math["gen"]["$(math_obj["index"])"] = math_obj - push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => map_to, From bbfa2d7c19a8cd3f0e8013196a80cba9c1a8e8e6 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 5 Sep 2024 11:02:33 -0600 Subject: [PATCH 06/99] ADD: generator or rotating machine parser for ravens2math --- src/data_model/transformations/ravens2math.jl | 97 +++++++++++++++++-- src/prob/common.jl | 8 +- 2 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 5baf17208..9d079f8df 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -5,7 +5,7 @@ const _math_to_ravens = Dict{String,String}( "switch" => "switch", # "shunt" => "shunt_compensator", "load" => "energy_consumer", - # "generator" => "rotating_machine", + "generator" => "rotating_machine", # "solar" => "photovoltaic_unit", # "storage" => "battery_unit", "voltage_source" => "energy_source", @@ -14,7 +14,7 @@ const _math_to_ravens = Dict{String,String}( "list of nodal type elements in the ravens model" const _ravens_node_elements = String[ - "energy_consumer", "energy_source" + "energy_consumer", "rotating_machine", "energy_source" ] "list of edge type elements in the ravens model" @@ -247,8 +247,12 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj["angmin"] = get(ravens_obj, "vad_lb", fill(-60.0, nphases)) math_obj["angmax"] = get(ravens_obj, "vad_ub", fill(60.0, nphases)) - oplimitset_id = replace(split(terminals[1]["ACDCTerminal.OperationalLimitSet"], "::")[2], "'" => "") - oplimitset = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][2] + if (haskey(terminals[1], "ACDCTerminal.OperationalLimitSet")) + oplimitset_id = replace(split(terminals[1]["ACDCTerminal.OperationalLimitSet"], "::")[2], "'" => "") + oplimitset = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][2] + else + oplimitset = Dict() + end limit_keys = [("CurrentLimit.value", "c_rating_a"), ("CurrentLimit.value", "c_rating_b"), ("CurrentLimit.value", "c_rating_c"), ("ApparentPowerLimit.value", "rate_a"), ("ApparentPowerLimit.value", "rate_b"), ("ApparentPowerLimit.value", "rate_c")] @@ -366,7 +370,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end # Set status, dispatchable flag, and index - math_obj["status"] = ravens_obj["ConductingEquipment.SvStatus"] + math_obj["status"] = haskey(ravens_obj, "ConductingEquipment.SvStatus") ? ravens_obj["ConductingEquipment.SvStatus"] : 1 math_obj["dispatchable"] = 0 data_math["load"]["$(math_obj["index"])"] = math_obj @@ -423,7 +427,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav end # Generator status and configuration - math_obj["gen_status"] = Int(ravens_obj["ConductingEquipment.SvStatus"]) + math_obj["gen_status"] = haskey(ravens_obj, "ConductingEquipment.SvStatus") ? Int(ravens_obj["ConductingEquipment.SvStatus"]) : 1 math_obj["configuration"] = get(ravens_obj, "EnergySource.connectionKind", WYE) # Vnom and vbases_default @@ -518,6 +522,87 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav end + +"converts engineering generators into mathematical generators" +function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + + regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] + power_scale_factor = data_math["settings"]["power_scale_factor"] + voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + voltage_scale_factor_sqrt3 = voltage_scale_factor * sqrt(3) + + for (name, ravens_obj) in get(regulating_cond_eq, "RotatingMachine", Dict{Any,Dict{String,Any}}()) + + math_obj = _init_math_obj_ravens("rotating_machine", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) + + # TODO: connections/phases do not exist in the RAVENS-CIM (Need to be added) - should come from terminals + connections = [1, 2, 3] # TODO + nconductors = length(connections) + math_obj["connections"] = connections + + connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] + math_obj["gen_status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) + + # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) + math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) + + # Set Pmax for generator + if !haskey(ravens_obj, "GeneratingUnit.maxOperatingP") + math_obj["pmax"] = ((get(ravens_obj, "SynchronousMachine.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + else + math_obj["pmax"] = ((get(ravens_obj, "GeneratingUnit.maxOperatingP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + end + + # Set bus type + bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] + data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) + + # Set the nominal voltage + base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + base_voltage = nominal_voltage / sqrt(nconductors) + math_obj["vbase"] = base_voltage / voltage_scale_factor + + if control_mode == Int(ISOCHRONOUS) && status == 1 + data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "SynchronousMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vmax"] = ((get(ravens_obj, "SynchronousMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vmin"] = ((get(ravens_obj, "SynchronousMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["gen_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["gen_bus"])"]["terminals"]] + end + + # Set pmin + math_obj["pmin"] = ((get(ravens_obj, "GeneratingUnit.minOperatingP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set qmin + math_obj["qmin"] = ((get(ravens_obj, "SynchronousMachine.minQ", -Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set qmax + math_obj["qmax"] = ((get(ravens_obj, "SynchronousMachine.maxQ", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + + # Set pg and qg + math_obj["pg"] = (get(ravens_obj, "SynchronousMachine.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["qg"] = (get(ravens_obj, "SynchronousMachine.q", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + + # TODO: add a polynomial parameters to be added to gen cost + _add_gen_cost_model!(math_obj, ravens_obj) + + # TODO: configuration for generators is not available on CIM (yet) + math_obj["configuration"] = get(ravens_obj, "configuration", WYE) + + # Set index + data_math["gen"]["$(math_obj["index"])"] = math_obj + + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "gen.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_rotating_machine!", + )) + end + + +end + + + "converts ravensineering switches into mathematical switches and (if neeed) impedance branches to represent loss model" function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) # TODO enable real switches (right now only using vitual lines) diff --git a/src/prob/common.jl b/src/prob/common.jl index 45c2bdfbf..6eb79c6d4 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,8 +116,8 @@ function instantiate_mc_model( ) end - # @info "$(data)" - # DEFINIDOEN_instantiate_mc_model + @info "$(data["gen"])" + DEFINIDOEN_instantiate_mc_model return _IM.instantiate_model( data, @@ -157,8 +157,8 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - # @info "$(data["bus"])" - # DEFINIDOEN_instantiate_mc_model_ravens + @info "$(data["gen"])" + DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( data, From 03a55d4f18a3ee352618a29a88ca2c3f56feff78 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 5 Sep 2024 12:54:56 -0600 Subject: [PATCH 07/99] ADD: pv or photovoltaic unit parser for ravens2math. --- src/data_model/transformations/ravens2math.jl | 99 ++++++++++++++++++- 1 file changed, 96 insertions(+), 3 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 9d079f8df..8b01347ab 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -6,7 +6,7 @@ const _math_to_ravens = Dict{String,String}( # "shunt" => "shunt_compensator", "load" => "energy_consumer", "generator" => "rotating_machine", - # "solar" => "photovoltaic_unit", + "solar" => "photovoltaic_unit", # "storage" => "battery_unit", "voltage_source" => "energy_source", ) @@ -14,7 +14,7 @@ const _math_to_ravens = Dict{String,String}( "list of nodal type elements in the ravens model" const _ravens_node_elements = String[ - "energy_consumer", "rotating_machine", "energy_source" + "energy_consumer", "rotating_machine", "photovoltaic_unit", "energy_source" ] "list of edge type elements in the ravens model" @@ -529,7 +529,6 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] power_scale_factor = data_math["settings"]["power_scale_factor"] voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] - voltage_scale_factor_sqrt3 = voltage_scale_factor * sqrt(3) for (name, ravens_obj) in get(regulating_cond_eq, "RotatingMachine", Dict{Any,Dict{String,Any}}()) @@ -602,6 +601,100 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ end +"converts ravens photovoltaic_unit components into mathematical generators" +function _map_ravens2math_photovoltaic_unit!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + + regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] + power_scale_factor = data_math["settings"]["power_scale_factor"] + voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + + for (name, ravens_obj) in get(regulating_cond_eq, "PowerElectronicsConnection", Dict{Any,Dict{String,Any}}()) + + # Get type of PowerElectronicsUnit + pec_type = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "Ravens.CimObjectType", "") + + if pec_type == "PhotoVoltaicUnit" + + math_obj = _init_math_obj_ravens("photovoltaic_unit", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) + + # TODO: connections/phases do not exist in the RAVENS-CIM (Need to be added) - should come from terminals + connections = [1, 2, 3] # TODO + nconductors = length(connections) + math_obj["connections"] = connections + + connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] + math_obj["gen_status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) + + # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) + math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) + + # Set bus type + bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] + data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) + + # Set the nominal voltage + base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + base_voltage = nominal_voltage / sqrt(nconductors) + math_obj["vbase"] = base_voltage / voltage_scale_factor + + if control_mode == Int(ISOCHRONOUS) && status == 1 + data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vmax"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vmin"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["gen_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["gen_bus"])"]["terminals"]] + data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = 3 + end + + # Set vg + for (fr_k, to_k) in [("PowerElectronicsConnection.ratedU", "vg")] + if haskey(ravens_obj, fr_k) + math_obj[to_k] = (ravens_obj[fr_k]/nominal_voltage)*ones(nconductors)/voltage_scale_factor + end + end + + # TODO: configuration for generators is not available on CIM (yet) + math_obj["configuration"] = get(ravens_obj, "configuration", WYE) + + + # TODO: refactor the calculation of N when connections and configuration issues are solved. + N = math_obj["configuration"]==DELTA && length(connections)==1 ? 1 : _infer_int_dim(connections, math_obj["configuration"], false) # if solar is delta-connected to triplex node, N can be equal to 1 + + # Set pmax + if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") + math_obj["pmax"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + else + math_obj["pmax"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + end + # Set pmin + math_obj["pmin"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.minP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set qmin + math_obj["qmin"] = ((get(ravens_obj, "PowerElectronicsConnection.minQ", -0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set qmax + math_obj["qmax"] = ((get(ravens_obj, "PowerElectronicsConnection.maxQ", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + + + # Set pg and qg + math_obj["pg"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["qg"] = (get(ravens_obj, "PowerElectronicsConnection.q", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + + # TODO: add a polynomial parameters to be added to gen cost + _add_gen_cost_model!(math_obj, ravens_obj) + + # Set index + data_math["gen"]["$(math_obj["index"])"] = math_obj + + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "gen.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_photovoltaic_unit!", + )) + + end + end +end + "converts ravensineering switches into mathematical switches and (if neeed) impedance branches to represent loss model" function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) From 05f483e43316bfde9962a53d5fe6f42de361d858 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 5 Sep 2024 15:24:22 -0600 Subject: [PATCH 08/99] ADD: storage or battery unit parser for ravens2math --- src/data_model/transformations/ravens2math.jl | 97 ++++++++++++++++++- src/prob/common.jl | 8 +- 2 files changed, 97 insertions(+), 8 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 8b01347ab..3f2e5d41d 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1,20 +1,20 @@ "cim-ravens to math object mapping" const _math_to_ravens = Dict{String,String}( "bus" => "connectivity_node", - "transformer" => "power_transformer", - "switch" => "switch", + "transformer" => "power_transformer", # TODO + "switch" => "switch", # TODO # "shunt" => "shunt_compensator", "load" => "energy_consumer", "generator" => "rotating_machine", "solar" => "photovoltaic_unit", - # "storage" => "battery_unit", + "storage" => "battery_unit", "voltage_source" => "energy_source", ) "list of nodal type elements in the ravens model" const _ravens_node_elements = String[ - "energy_consumer", "rotating_machine", "photovoltaic_unit", "energy_source" + "energy_consumer", "rotating_machine", "photovoltaic_unit", "battery_unit", "energy_source" ] "list of edge type elements in the ravens model" @@ -696,6 +696,95 @@ function _map_ravens2math_photovoltaic_unit!(data_math::Dict{String,<:Any}, data end + +"converts engineering storage into mathematical storage" +function _map_ravens2math_battery_unit!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + + regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] + power_scale_factor = data_math["settings"]["power_scale_factor"] + voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + + for (name, ravens_obj) in get(regulating_cond_eq, "PowerElectronicsConnection", Dict{Any,Dict{String,Any}}()) + + # Get type of PowerElectronicsUnit + pec_type = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "Ravens.CimObjectType", "") + + if pec_type == "BatteryUnit" + + math_obj = _init_math_obj_ravens("storage", name, ravens_obj, length(data_math["storage"])+1; pass_props=pass_props) + + # TODO: connections/phases do not exist in the RAVENS-CIM (Need to be added) - should come from terminals + connections = [1, 2, 3] # TODO + nconductors = length(connections) + math_obj["connections"] = connections + + # Set the bus + connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + math_obj["storage_bus"] = data_math["bus_lookup"][connectivity_node] + math_obj["status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) + + # TODO: configuration for generators is not available on CIM (yet) + math_obj["configuration"] = get(ravens_obj, "configuration", WYE) + + # Set battery parameters + math_obj["energy"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.storedE"]/power_scale_factor + + if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.limitEnergy") + math_obj["energy_rating"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.ratedE"]/power_scale_factor + else + math_obj["energy_rating"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["InefficientBatteryUnit.limitEnergy"]/power_scale_factor + end + + if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") + math_obj["charge_rating"] = (get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf))./(power_scale_factor) + math_obj["discharge_rating"] = math_obj["charge_rating"] + else + math_obj["charge_rating"] = (get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf))./(power_scale_factor) + math_obj["discharge_rating"] = math_obj["charge_rating"] + end + + math_obj["charge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.efficiencyCharge", 100.0) / 100.0 + math_obj["discharge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.efficiencyDischarge", 100.0) / 100.0 + math_obj["thermal_rating"] = get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf)/power_scale_factor + + math_obj["qmin"] = (get(ravens_obj, "PowerElectronicsConnection.minQ", -math_obj["discharge_rating"]*power_scale_factor))./(power_scale_factor) + math_obj["qmax"] = (get(ravens_obj, "PowerElectronicsConnection.maxQ", math_obj["charge_rating"]*power_scale_factor))./(power_scale_factor) + + # TODO: verify that these CIM terms are equivalent to the needed values. + math_obj["r"] = get(ravens_obj, "PowerElectronicsConnection.r", 0) + math_obj["x"] = get(ravens_obj, "PowerElectronicsConnection.x", 0) + + # TODO: These are still missing from the RAVENS Schema + math_obj["p_loss"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.idlingActivePower", 0)./(power_scale_factor) + math_obj["q_loss"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.idlingReactivePower", 0)./(power_scale_factor) + + # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) + math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) + + # Set the ps and qs + math_obj["ps"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0))./(power_scale_factor) + math_obj["qs"] = (get(ravens_obj, "PowerElectronicsConnection.q", 0.0))./(power_scale_factor) + + # Set bus type + bus_type = data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] + data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) + + if control_mode == Int(ISOCHRONOUS) && math_obj["status"] == 1 + data_math["bus"]["$(math_obj["storage_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["storage_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["storage_bus"])"]["terminals"]] + end + + data_math["storage"]["$(math_obj["index"])"] = math_obj + + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "storage.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_battery_unit!", + )) + end + end +end + + "converts ravensineering switches into mathematical switches and (if neeed) impedance branches to represent loss model" function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) # TODO enable real switches (right now only using vitual lines) diff --git a/src/prob/common.jl b/src/prob/common.jl index 6eb79c6d4..2a255bf27 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,8 +116,8 @@ function instantiate_mc_model( ) end - @info "$(data["gen"])" - DEFINIDOEN_instantiate_mc_model + # @info "$(data["storage"])" + # DEFINIDOEN_instantiate_mc_model return _IM.instantiate_model( data, @@ -157,8 +157,8 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - @info "$(data["gen"])" - DEFINIDOEN_instantiate_mc_model_ravens + # @info "$(data["storage"])" + # DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( data, From 1021d87cd0f85ed7ff6c9c60e529a9a3055b4076 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 5 Sep 2024 16:07:42 -0600 Subject: [PATCH 09/99] REF: combined PVs and Battery Units in Ravens parser to avoid multiple loops through PowerElectronicsConnection. --- src/data_model/transformations/ravens2math.jl | 28 ++++--------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 3f2e5d41d..4cd0d3437 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -14,7 +14,7 @@ const _math_to_ravens = Dict{String,String}( "list of nodal type elements in the ravens model" const _ravens_node_elements = String[ - "energy_consumer", "rotating_machine", "photovoltaic_unit", "battery_unit", "energy_source" + "energy_consumer", "rotating_machine", "power_electronics", "energy_source" ] "list of edge type elements in the ravens model" @@ -601,8 +601,8 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ end -"converts ravens photovoltaic_unit components into mathematical generators" -function _map_ravens2math_photovoltaic_unit!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) +"converts ravens power_electronics units such as PVs and Batteries into mathematical components" +function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] power_scale_factor = data_math["settings"]["power_scale_factor"] @@ -613,7 +613,7 @@ function _map_ravens2math_photovoltaic_unit!(data_math::Dict{String,<:Any}, data # Get type of PowerElectronicsUnit pec_type = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "Ravens.CimObjectType", "") - if pec_type == "PhotoVoltaicUnit" + if (pec_type == "PhotoVoltaicUnit") math_obj = _init_math_obj_ravens("photovoltaic_unit", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) @@ -691,25 +691,7 @@ function _map_ravens2math_photovoltaic_unit!(data_math::Dict{String,<:Any}, data "unmap_function" => "_map_math2ravens_photovoltaic_unit!", )) - end - end -end - - - -"converts engineering storage into mathematical storage" -function _map_ravens2math_battery_unit!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) - - regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] - power_scale_factor = data_math["settings"]["power_scale_factor"] - voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] - - for (name, ravens_obj) in get(regulating_cond_eq, "PowerElectronicsConnection", Dict{Any,Dict{String,Any}}()) - - # Get type of PowerElectronicsUnit - pec_type = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "Ravens.CimObjectType", "") - - if pec_type == "BatteryUnit" + elseif (pec_type == "BatteryUnit") math_obj = _init_math_obj_ravens("storage", name, ravens_obj, length(data_math["storage"])+1; pass_props=pass_props) From d7559d7aed829cccdfb55cc4e031e3622e3e1fac Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 26 Sep 2024 12:45:21 -0600 Subject: [PATCH 10/99] REF: ravens2math parser to fix impedance calculations and support files coming from dss-xml-json ravens exporters. --- src/data_model/transformations/ravens2math.jl | 89 +++++++++++++++---- src/data_model/utils_ravens.jl | 26 +++--- src/prob/common.jl | 4 +- 3 files changed, 88 insertions(+), 31 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 4cd0d3437..2deb9e187 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -335,10 +335,25 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r # Set voltage bounds for the bus connected bus_info = string(math_obj["load_bus"]) bus_conn = data_math["bus"][bus_info] - op_limit_id = replace(split(data_ravens["ConnectivityNode"][connectivity_node]["ConnectivityNode.OperationalLimitSet"], "::")[2], "'" => "") - op_limits = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"] - op_limit_max = op_limits[1]["VoltageLimit.value"] / voltage_scale_factor_sqrt3 - op_limit_min = op_limits[2]["VoltageLimit.value"] / voltage_scale_factor_sqrt3 + + if haskey(data_ravens["ConnectivityNode"][connectivity_node], "ConnectivityNode.OperationalLimitSet") + op_limit_id = replace(split(data_ravens["ConnectivityNode"][connectivity_node]["ConnectivityNode.OperationalLimitSet"], "::")[2], "'" => "") + op_limits = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"] + + # Loop through op. limits + for lim in op_limits + lim_type = lim["OperationalLimit.OperationalLimitType"]["OperationalLimitType.direction"] + if lim_type == "OperationalLimitDirectionKind.high" + op_limit_max = lim["VoltageLimit.value"] / voltage_scale_factor_sqrt3 + elseif lim_type == "OperationalLimitDirectionKind.low" + op_limit_min = lim["VoltageLimit.value"] / voltage_scale_factor_sqrt3 + end + end + + else + op_limit_max = Inf + op_limit_min = 0.0 + end # Handle phase-specific or three-phase connection phase_map = Dict("SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, "SinglePhaseKind.C" => 3) @@ -423,7 +438,29 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav end math_obj["connections"] = connections else - math_obj["connections"] = bus_conn["terminals"] + # Terminal Phases + if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") + phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] + if (phasecode == "PhaseCode.ABC") + math_obj["connections"] = [1, 2, 3] + elseif (phasecode == "PhaseCode.AB") + math_obj["connections"] = [1, 2] + elseif (phasecode == "PhaseCode.AC") + math_obj["connections"] = [1, 3] + elseif (phasecode == "PhaseCode.BC") + math_obj["connections"] = [2, 3] + elseif (phasecode == "PhaseCode.A") + math_obj["connections"] = [1] + elseif (phasecode == "PhaseCode.B") + math_obj["connections"] = [2] + elseif (phasecode == "PhaseCode.C") + math_obj["connections"] = [3] + else + @error("PhaseCode not supported yet!") + end + else + math_obj["connections"] = bus_conn["terminals"] + end end # Generator status and configuration @@ -534,8 +571,30 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ math_obj = _init_math_obj_ravens("rotating_machine", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) - # TODO: connections/phases do not exist in the RAVENS-CIM (Need to be added) - should come from terminals - connections = [1, 2, 3] # TODO + # Connections/phases obtained from Terminals + if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") + phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] + if (phasecode == "PhaseCode.ABC") + connections = [1, 2, 3] + elseif (phasecode == "PhaseCode.AB") + connections = [1, 2] + elseif (phasecode == "PhaseCode.AC") + connections = [1, 3] + elseif (phasecode == "PhaseCode.BC") + connections = [2, 3] + elseif (phasecode == "PhaseCode.A") + connections = [1] + elseif (phasecode == "PhaseCode.B") + connections = [2] + elseif (phasecode == "PhaseCode.C") + connections = [3] + else + @error("PhaseCode not supported yet!") + end + else + connections = [1, 2, 3] # default + end + nconductors = length(connections) math_obj["connections"] = connections @@ -548,7 +607,7 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ # Set Pmax for generator if !haskey(ravens_obj, "GeneratingUnit.maxOperatingP") - math_obj["pmax"] = ((get(ravens_obj, "SynchronousMachine.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + math_obj["pmax"] = ((get(ravens_obj, "RotatingMachine.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) else math_obj["pmax"] = ((get(ravens_obj, "GeneratingUnit.maxOperatingP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) end @@ -564,22 +623,22 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ math_obj["vbase"] = base_voltage / voltage_scale_factor if control_mode == Int(ISOCHRONOUS) && status == 1 - data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "SynchronousMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) - data_math["bus"]["$(math_obj["gen_bus"])"]["vmax"] = ((get(ravens_obj, "SynchronousMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) - data_math["bus"]["$(math_obj["gen_bus"])"]["vmin"] = ((get(ravens_obj, "SynchronousMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vmax"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vmin"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) data_math["bus"]["$(math_obj["gen_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["gen_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["gen_bus"])"]["terminals"]] end # Set pmin math_obj["pmin"] = ((get(ravens_obj, "GeneratingUnit.minOperatingP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) # Set qmin - math_obj["qmin"] = ((get(ravens_obj, "SynchronousMachine.minQ", -Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + math_obj["qmin"] = ((get(ravens_obj, "RotatingMachine.minQ", -Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) # Set qmax - math_obj["qmax"] = ((get(ravens_obj, "SynchronousMachine.maxQ", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + math_obj["qmax"] = ((get(ravens_obj, "RotatingMachine.maxQ", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) # Set pg and qg - math_obj["pg"] = (get(ravens_obj, "SynchronousMachine.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) - math_obj["qg"] = (get(ravens_obj, "SynchronousMachine.q", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["pg"] = (get(ravens_obj, "RotatingMachine.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["qg"] = (get(ravens_obj, "RotatingMachine.q", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) # TODO: add a polynomial parameters to be added to gen cost _add_gen_cost_model!(math_obj, ravens_obj) diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 27ca59a61..adf2ec79a 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -18,13 +18,12 @@ function _impedance_conversion_ravens(data_eng::Dict{String,Any}, eng_obj::Dict{ _conductor_count = data_eng["PerLengthPhaseImpedance.conductorCount"] _impedance_matrix = zeros(Float64, _conductor_count, _conductor_count) - _index = 1 - for i in 1:_conductor_count - for j in 1:i - _impedance_matrix[i, j] = get(data_eng["PerLengthPhaseImpedance.PhaseImpedanceData"][_index], key, 0.0) - _impedance_matrix[j, i] = get(data_eng["PerLengthPhaseImpedance.PhaseImpedanceData"][_index], key, 0.0) - _index += 1 - end + for obj in data_eng["PerLengthPhaseImpedance.PhaseImpedanceData"] + row = obj["PhaseImpedanceData.row"] + col = obj["PhaseImpedanceData.column"] + value = get(obj, key, 0.0) + _impedance_matrix[row, col] = value + _impedance_matrix[col, row] = value end return _impedance_matrix .* get(eng_obj, "Conductor.length", 1.0) @@ -61,13 +60,12 @@ function _admittance_conversion_ravens(data_eng::Dict{String,<:Any}, eng_obj::Di _conductor_count = data_eng["PerLengthPhaseImpedance.conductorCount"] _admittance_matrix = zeros(Float64, _conductor_count, _conductor_count) - _index = 1 - for i in 1:_conductor_count - for j in 1:i - _admittance_matrix[i, j] = get(data_eng["PerLengthPhaseImpedance.PhaseImpedanceData"][_index], key, 0.0) - _admittance_matrix[j, i] = get(data_eng["PerLengthPhaseImpedance.PhaseImpedanceData"][_index], key, 0.0) - _index += 1 - end + for obj in data_eng["PerLengthPhaseImpedance.PhaseImpedanceData"] + row = obj["PhaseImpedanceData.row"] + col = obj["PhaseImpedanceData.column"] + value = get(obj, key, 0.0) + _admittance_matrix[row, col] = value + _admittance_matrix[col, row] = value end return _admittance_matrix .* get(eng_obj, "Conductor.length", 1.0) .* freq ./ 1e2 # divide by 2 to get both sides _to and _fr diff --git a/src/prob/common.jl b/src/prob/common.jl index 2a255bf27..90ce1673b 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,7 +116,7 @@ function instantiate_mc_model( ) end - # @info "$(data["storage"])" + # @info "$(data["branch"])" # DEFINIDOEN_instantiate_mc_model return _IM.instantiate_model( @@ -157,7 +157,7 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - # @info "$(data["storage"])" + # @info "$(data["branch"])" # DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( From e7b082ccdb827d6ab047ed513a8820720e2e2a9c Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 26 Sep 2024 13:53:09 -0600 Subject: [PATCH 11/99] REF: add haskey check when looking for gens and power electronics --- src/data_model/transformations/ravens2math.jl | 264 +++++++++--------- src/prob/common.jl | 8 +- 2 files changed, 140 insertions(+), 132 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 2deb9e187..fbf86e3f2 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -563,11 +563,13 @@ end "converts engineering generators into mathematical generators" function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) - regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] - power_scale_factor = data_math["settings"]["power_scale_factor"] - voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + if haskey(data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"], "RegulatingCondEq") + + regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] + power_scale_factor = data_math["settings"]["power_scale_factor"] + voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] - for (name, ravens_obj) in get(regulating_cond_eq, "RotatingMachine", Dict{Any,Dict{String,Any}}()) + for (name, ravens_obj) in get(regulating_cond_eq, "RotatingMachine", Dict{Any,Dict{String,Any}}()) math_obj = _init_math_obj_ravens("rotating_machine", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) @@ -654,8 +656,9 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ "to" => "gen.$(math_obj["index"])", "unmap_function" => "_map_math2ravens_rotating_machine!", )) - end + end + end end @@ -663,166 +666,171 @@ end "converts ravens power_electronics units such as PVs and Batteries into mathematical components" function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) - regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] - power_scale_factor = data_math["settings"]["power_scale_factor"] - voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + if haskey(data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"], "RegulatingCondEq") - for (name, ravens_obj) in get(regulating_cond_eq, "PowerElectronicsConnection", Dict{Any,Dict{String,Any}}()) + regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] + power_scale_factor = data_math["settings"]["power_scale_factor"] + voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] - # Get type of PowerElectronicsUnit - pec_type = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "Ravens.CimObjectType", "") + for (name, ravens_obj) in get(regulating_cond_eq, "PowerElectronicsConnection", Dict{Any,Dict{String,Any}}()) - if (pec_type == "PhotoVoltaicUnit") + # Get type of PowerElectronicsUnit + pec_type = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "Ravens.CimObjectType", "") - math_obj = _init_math_obj_ravens("photovoltaic_unit", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) + if (pec_type == "PhotoVoltaicUnit") - # TODO: connections/phases do not exist in the RAVENS-CIM (Need to be added) - should come from terminals - connections = [1, 2, 3] # TODO - nconductors = length(connections) - math_obj["connections"] = connections + math_obj = _init_math_obj_ravens("photovoltaic_unit", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) - connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") - math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] - math_obj["gen_status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) - - # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) - math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) - - # Set bus type - bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] - data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) - - # Set the nominal voltage - base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") - nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - base_voltage = nominal_voltage / sqrt(nconductors) - math_obj["vbase"] = base_voltage / voltage_scale_factor - - if control_mode == Int(ISOCHRONOUS) && status == 1 - data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) - data_math["bus"]["$(math_obj["gen_bus"])"]["vmax"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) - data_math["bus"]["$(math_obj["gen_bus"])"]["vmin"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) - data_math["bus"]["$(math_obj["gen_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["gen_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["gen_bus"])"]["terminals"]] - data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = 3 - end + # TODO: connections/phases do not exist in the RAVENS-CIM (Need to be added) - should come from terminals + connections = [1, 2, 3] # TODO + nconductors = length(connections) + math_obj["connections"] = connections + + connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] + math_obj["gen_status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) + + # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) + math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) + + # Set bus type + bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] + data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) + + # Set the nominal voltage + base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + base_voltage = nominal_voltage / sqrt(nconductors) + math_obj["vbase"] = base_voltage / voltage_scale_factor - # Set vg - for (fr_k, to_k) in [("PowerElectronicsConnection.ratedU", "vg")] - if haskey(ravens_obj, fr_k) - math_obj[to_k] = (ravens_obj[fr_k]/nominal_voltage)*ones(nconductors)/voltage_scale_factor + if control_mode == Int(ISOCHRONOUS) && status == 1 + data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vmax"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vmin"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["gen_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["gen_bus"])"]["terminals"]] + data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = 3 end - end - # TODO: configuration for generators is not available on CIM (yet) - math_obj["configuration"] = get(ravens_obj, "configuration", WYE) + # Set vg + for (fr_k, to_k) in [("PowerElectronicsConnection.ratedU", "vg")] + if haskey(ravens_obj, fr_k) + math_obj[to_k] = (ravens_obj[fr_k]/nominal_voltage)*ones(nconductors)/voltage_scale_factor + end + end + # TODO: configuration for generators is not available on CIM (yet) + math_obj["configuration"] = get(ravens_obj, "configuration", WYE) - # TODO: refactor the calculation of N when connections and configuration issues are solved. - N = math_obj["configuration"]==DELTA && length(connections)==1 ? 1 : _infer_int_dim(connections, math_obj["configuration"], false) # if solar is delta-connected to triplex node, N can be equal to 1 - # Set pmax - if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") - math_obj["pmax"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - else - math_obj["pmax"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - end - # Set pmin - math_obj["pmin"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.minP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set qmin - math_obj["qmin"] = ((get(ravens_obj, "PowerElectronicsConnection.minQ", -0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set qmax - math_obj["qmax"] = ((get(ravens_obj, "PowerElectronicsConnection.maxQ", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # TODO: refactor the calculation of N when connections and configuration issues are solved. + N = math_obj["configuration"]==DELTA && length(connections)==1 ? 1 : _infer_int_dim(connections, math_obj["configuration"], false) # if solar is delta-connected to triplex node, N can be equal to 1 + # Set pmax + if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") + math_obj["pmax"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + else + math_obj["pmax"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + end + # Set pmin + math_obj["pmin"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.minP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set qmin + math_obj["qmin"] = ((get(ravens_obj, "PowerElectronicsConnection.minQ", -0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set qmax + math_obj["qmax"] = ((get(ravens_obj, "PowerElectronicsConnection.maxQ", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set pg and qg - math_obj["pg"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) - math_obj["qg"] = (get(ravens_obj, "PowerElectronicsConnection.q", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) - # TODO: add a polynomial parameters to be added to gen cost - _add_gen_cost_model!(math_obj, ravens_obj) + # Set pg and qg + math_obj["pg"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["qg"] = (get(ravens_obj, "PowerElectronicsConnection.q", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) - # Set index - data_math["gen"]["$(math_obj["index"])"] = math_obj + # TODO: add a polynomial parameters to be added to gen cost + _add_gen_cost_model!(math_obj, ravens_obj) - push!(data_math["map"], Dict{String,Any}( - "from" => name, - "to" => "gen.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_photovoltaic_unit!", - )) + # Set index + data_math["gen"]["$(math_obj["index"])"] = math_obj - elseif (pec_type == "BatteryUnit") + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "gen.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_photovoltaic_unit!", + )) - math_obj = _init_math_obj_ravens("storage", name, ravens_obj, length(data_math["storage"])+1; pass_props=pass_props) + elseif (pec_type == "BatteryUnit") - # TODO: connections/phases do not exist in the RAVENS-CIM (Need to be added) - should come from terminals - connections = [1, 2, 3] # TODO - nconductors = length(connections) - math_obj["connections"] = connections + math_obj = _init_math_obj_ravens("storage", name, ravens_obj, length(data_math["storage"])+1; pass_props=pass_props) - # Set the bus - connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") - math_obj["storage_bus"] = data_math["bus_lookup"][connectivity_node] - math_obj["status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) + # TODO: connections/phases do not exist in the RAVENS-CIM (Need to be added) - should come from terminals + connections = [1, 2, 3] # TODO + nconductors = length(connections) + math_obj["connections"] = connections - # TODO: configuration for generators is not available on CIM (yet) - math_obj["configuration"] = get(ravens_obj, "configuration", WYE) + # Set the bus + connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + math_obj["storage_bus"] = data_math["bus_lookup"][connectivity_node] + math_obj["status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) - # Set battery parameters - math_obj["energy"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.storedE"]/power_scale_factor + # TODO: configuration for generators is not available on CIM (yet) + math_obj["configuration"] = get(ravens_obj, "configuration", WYE) - if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.limitEnergy") - math_obj["energy_rating"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.ratedE"]/power_scale_factor - else - math_obj["energy_rating"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["InefficientBatteryUnit.limitEnergy"]/power_scale_factor - end + # Set battery parameters + math_obj["energy"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.storedE"]/power_scale_factor - if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") - math_obj["charge_rating"] = (get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf))./(power_scale_factor) - math_obj["discharge_rating"] = math_obj["charge_rating"] - else - math_obj["charge_rating"] = (get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf))./(power_scale_factor) - math_obj["discharge_rating"] = math_obj["charge_rating"] - end + if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.limitEnergy") + math_obj["energy_rating"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.ratedE"]/power_scale_factor + else + math_obj["energy_rating"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["InefficientBatteryUnit.limitEnergy"]/power_scale_factor + end - math_obj["charge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.efficiencyCharge", 100.0) / 100.0 - math_obj["discharge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.efficiencyDischarge", 100.0) / 100.0 - math_obj["thermal_rating"] = get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf)/power_scale_factor + if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") + math_obj["charge_rating"] = (get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf))./(power_scale_factor) + math_obj["discharge_rating"] = math_obj["charge_rating"] + else + math_obj["charge_rating"] = (get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf))./(power_scale_factor) + math_obj["discharge_rating"] = math_obj["charge_rating"] + end - math_obj["qmin"] = (get(ravens_obj, "PowerElectronicsConnection.minQ", -math_obj["discharge_rating"]*power_scale_factor))./(power_scale_factor) - math_obj["qmax"] = (get(ravens_obj, "PowerElectronicsConnection.maxQ", math_obj["charge_rating"]*power_scale_factor))./(power_scale_factor) + math_obj["charge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.efficiencyCharge", 100.0) / 100.0 + math_obj["discharge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.efficiencyDischarge", 100.0) / 100.0 + math_obj["thermal_rating"] = get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf)/power_scale_factor - # TODO: verify that these CIM terms are equivalent to the needed values. - math_obj["r"] = get(ravens_obj, "PowerElectronicsConnection.r", 0) - math_obj["x"] = get(ravens_obj, "PowerElectronicsConnection.x", 0) + math_obj["qmin"] = (get(ravens_obj, "PowerElectronicsConnection.minQ", -math_obj["discharge_rating"]*power_scale_factor))./(power_scale_factor) + math_obj["qmax"] = (get(ravens_obj, "PowerElectronicsConnection.maxQ", math_obj["charge_rating"]*power_scale_factor))./(power_scale_factor) - # TODO: These are still missing from the RAVENS Schema - math_obj["p_loss"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.idlingActivePower", 0)./(power_scale_factor) - math_obj["q_loss"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.idlingReactivePower", 0)./(power_scale_factor) + # TODO: verify that these CIM terms are equivalent to the needed values. + math_obj["r"] = get(ravens_obj, "PowerElectronicsConnection.r", 0) + math_obj["x"] = get(ravens_obj, "PowerElectronicsConnection.x", 0) - # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) - math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) + # TODO: These are still missing from the RAVENS Schema + math_obj["p_loss"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.idlingActivePower", 0)./(power_scale_factor) + math_obj["q_loss"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.idlingReactivePower", 0)./(power_scale_factor) - # Set the ps and qs - math_obj["ps"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0))./(power_scale_factor) - math_obj["qs"] = (get(ravens_obj, "PowerElectronicsConnection.q", 0.0))./(power_scale_factor) + # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) + math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) - # Set bus type - bus_type = data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] - data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) + # Set the ps and qs + math_obj["ps"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0))./(power_scale_factor) + math_obj["qs"] = (get(ravens_obj, "PowerElectronicsConnection.q", 0.0))./(power_scale_factor) - if control_mode == Int(ISOCHRONOUS) && math_obj["status"] == 1 - data_math["bus"]["$(math_obj["storage_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["storage_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["storage_bus"])"]["terminals"]] - end + # Set bus type + bus_type = data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] + data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) + + if control_mode == Int(ISOCHRONOUS) && math_obj["status"] == 1 + data_math["bus"]["$(math_obj["storage_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["storage_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["storage_bus"])"]["terminals"]] + end - data_math["storage"]["$(math_obj["index"])"] = math_obj + data_math["storage"]["$(math_obj["index"])"] = math_obj - push!(data_math["map"], Dict{String,Any}( - "from" => name, - "to" => "storage.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_battery_unit!", - )) + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "storage.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_battery_unit!", + )) + end end + end + end diff --git a/src/prob/common.jl b/src/prob/common.jl index 90ce1673b..c96407c27 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,8 +116,8 @@ function instantiate_mc_model( ) end - # @info "$(data["branch"])" - # DEFINIDOEN_instantiate_mc_model + @info "$(data["switch"])" + DEFINIDOEN_instantiate_mc_model return _IM.instantiate_model( data, @@ -157,8 +157,8 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - # @info "$(data["branch"])" - # DEFINIDOEN_instantiate_mc_model_ravens + @info "$(data["switch"])" + DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( data, From 8bb608de7b2dab5a118b3426448f00f16aa26248 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 26 Sep 2024 15:32:21 -0600 Subject: [PATCH 12/99] WIP: Switches - still missing connection to virtual bus and branches. --- src/data_model/transformations/ravens2math.jl | 130 +++++++++++++++++- src/prob/common.jl | 8 +- 2 files changed, 130 insertions(+), 8 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index fbf86e3f2..3406fe19a 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -19,7 +19,7 @@ const _ravens_node_elements = String[ "list of edge type elements in the ravens model" const _ravens_edge_elements = String[ - "conductor" + "conductor", "switch" ] "list of all ravens asset types" @@ -834,10 +834,132 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data end -"converts ravensineering switches into mathematical switches and (if neeed) impedance branches to represent loss model" +"converts ravens switches into mathematical switches and (if neeed) impedance branches to represent loss model" function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + # TODO enable real switches (right now only using vitual lines) - for (name, ravens_obj) in get(data_ravens, "switch", Dict{Any,Dict{String,Any}}()) - # TODO + if haskey(data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"], "Switch") + + conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"] + + for (name, ravens_obj) in get(conducting_equipment, "Switch", Dict{Any,Dict{String,Any}}()) + + math_obj = _init_math_obj_ravens("switch", name, ravens_obj, length(data_math["switch"])+1; pass_props=pass_props) + + # Terminals and phases + terminals = ravens_obj["ConductingEquipment.Terminals"] + + # TODO: refactor - Loop through terminals and verify connections + f_conns = [0,0,0] + t_conns = [0,0,0] + for term in terminals + if haskey(term, "Terminal.phases") + phasecode = term["Terminal.phases"] + if (phasecode == "PhaseCode.ABC") + if term["ACDCTerminal.sequenceNumber"] == 1 + f_conns = [1, 2, 3] + else + t_conns = [1, 2, 3] + end + elseif (phasecode == "PhaseCode.AB") + if term["ACDCTerminal.sequenceNumber"] == 1 + f_conns = [1, 2] + else + t_conns = [1, 2] + end + elseif (phasecode == "PhaseCode.AC") + if term["ACDCTerminal.sequenceNumber"] == 1 + f_conns = [1, 3] + else + t_conns = [1, 3] + end + elseif (phasecode == "PhaseCode.BC") + if term["ACDCTerminal.sequenceNumber"] == 1 + f_conns = [2, 3] + else + t_conns = [2, 3] + end + elseif (phasecode == "PhaseCode.A") + if term["ACDCTerminal.sequenceNumber"] == 1 + f_conns = [1] + else + t_conns = [1] + end + elseif (phasecode == "PhaseCode.B") + if term["ACDCTerminal.sequenceNumber"] == 1 + f_conns = [2] + else + t_conns = [2] + end + elseif (phasecode == "PhaseCode.C") + if term["ACDCTerminal.sequenceNumber"] == 1 + f_conns = [3] + else + t_conns = [3] + end + else + @error("PhaseCode not supported yet!") + end + else + f_conns = [1, 2, 3] + t_conns = [1, 2, 3] + end + end + + # Verify connections are correct. + if (f_conns != t_conns ) + @error("f_conns are not equal to t_conns!. Revise connections/phases in Switch terminals") + end + + # Phases + nphases = length(f_conns) + + # Connectivity Nodes + f_node = replace(split(terminals[1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + t_node = replace(split(terminals[2]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + math_obj["f_bus"] = data_math["bus_lookup"][f_node] + math_obj["t_bus"] = data_math["bus_lookup"][t_node] + + # TODO: Status + math_obj["status"] = get(ravens_obj, "ConductingEquipment.SvStatus", 1) + + # State + sw_state = get(ravens_obj, "Switch.open", "false") + sw_state = sw_state == "false" ? CLOSED : OPEN + math_obj["state"] = Int(sw_state) + + # TODO: Dispatchable + math_obj["dispatchable"] = Int(get(ravens_obj, "dispatchable", YES)) + + # TODO: OPF bounds - Do we really need all of these values? + for (f_key, t_key) in [("Switch.ratedCurrent", "current_rating"), ("cm_ub_b", "c_rating_b"), ("cm_ub_c", "c_rating_c"), + ("sm_ub", "thermal_rating"), ("sm_ub_b", "rate_b"), ("sm_ub_c", "rate_c")] + math_obj[t_key] = haskey(ravens_obj, f_key) ? fill(ravens_obj[f_key], nphases) : fill(Inf, nphases) + + @info "$(math_obj[t_key])" + + end + + # Map index + map_to = "switch.$(math_obj["index"])" + + # TODO: Apply linecode? No information is given in CIM related to linecodes + + + # TODO: Create virtual bus + + + # Push Mapping + data_math["switch"]["$(math_obj["index"])"] = math_obj + + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => map_to, + "unmap_function" => "_map_math2ravens_switch!", + )) + + end + end + end diff --git a/src/prob/common.jl b/src/prob/common.jl index c96407c27..6f00dc75c 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,8 +116,8 @@ function instantiate_mc_model( ) end - @info "$(data["switch"])" - DEFINIDOEN_instantiate_mc_model + # @info "$(data["switch"])" + # DEFINIDOEN_instantiate_mc_model return _IM.instantiate_model( data, @@ -157,8 +157,8 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - @info "$(data["switch"])" - DEFINIDOEN_instantiate_mc_model_ravens + # @info "$(data["switch"])" + # DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( data, From 248210b69512e4d77b82526434b9914586b24ca3 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 3 Oct 2024 12:41:44 -0600 Subject: [PATCH 13/99] REF: OperationalLimitType parsing with new style. --- src/data_model/transformations/ravens2math.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 3406fe19a..af07737e2 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -342,7 +342,9 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r # Loop through op. limits for lim in op_limits - lim_type = lim["OperationalLimit.OperationalLimitType"]["OperationalLimitType.direction"] + lim_type_name = replace(split(lim["OperationalLimit.OperationalLimitType"], "::")[2], "'" => "") + lim_type = data_ravens["OperationalLimitType"][lim_type_name]["OperationalLimitType.direction"] + if lim_type == "OperationalLimitDirectionKind.high" op_limit_max = lim["VoltageLimit.value"] / voltage_scale_factor_sqrt3 elseif lim_type == "OperationalLimitDirectionKind.low" From dda9e4a3fca3962e1407fa8ec6a0c4cd3ee9080b Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 7 Oct 2024 13:20:32 -0600 Subject: [PATCH 14/99] FIX: storage ravens2math parser. --- src/data_model/transformations/ravens2math.jl | 6 +++--- src/prob/common.jl | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index af07737e2..6caa078c7 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -780,14 +780,14 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.limitEnergy") math_obj["energy_rating"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.ratedE"]/power_scale_factor else - math_obj["energy_rating"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["InefficientBatteryUnit.limitEnergy"]/power_scale_factor + math_obj["energy_rating"] = ((ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["InefficientBatteryUnit.limitEnergy"]/100)*ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.ratedE"])/power_scale_factor end if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") - math_obj["charge_rating"] = (get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf))./(power_scale_factor) + math_obj["charge_rating"] = -(get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf))./(power_scale_factor) math_obj["discharge_rating"] = math_obj["charge_rating"] else - math_obj["charge_rating"] = (get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf))./(power_scale_factor) + math_obj["charge_rating"] = -(get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf))./(power_scale_factor) math_obj["discharge_rating"] = math_obj["charge_rating"] end diff --git a/src/prob/common.jl b/src/prob/common.jl index 6f00dc75c..2a255bf27 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,7 +116,7 @@ function instantiate_mc_model( ) end - # @info "$(data["switch"])" + # @info "$(data["storage"])" # DEFINIDOEN_instantiate_mc_model return _IM.instantiate_model( @@ -157,7 +157,7 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - # @info "$(data["switch"])" + # @info "$(data["storage"])" # DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( From a5d54a469b0a64d8a16f7ab1f053714b415e4ed3 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 7 Oct 2024 13:43:27 -0600 Subject: [PATCH 15/99] REF: a function that extracts the name of a ravens string. --- src/data_model/transformations/ravens2math.jl | 36 +++++++++---------- src/data_model/utils_ravens.jl | 7 ++++ 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 6caa078c7..5ca5bbfea 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -215,8 +215,8 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: nphases = length(ravens_obj["ACLineSegment.ACLineSegmentPhase"]) terminals = ravens_obj["ConductingEquipment.Terminals"] - f_node = replace(split(terminals[1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") - t_node = replace(split(terminals[2]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + f_node = _extract_name(terminals[1]["Terminal.ConnectivityNode"]) + t_node = _extract_name(terminals[2]["Terminal.ConnectivityNode"]) math_obj["f_bus"] = data_math["bus_lookup"][f_node] math_obj["t_bus"] = data_math["bus_lookup"][t_node] @@ -233,7 +233,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj["f_connections"] = bus_terminals math_obj["t_connections"] = bus_terminals - impedance_name = replace(split(ravens_obj["ACLineSegment.PerLengthImpedance"], "::")[2], "'" => "") + impedance_name = _extract_name(ravens_obj["ACLineSegment.PerLengthImpedance"]) impedance_data = data_ravens["PerLengthLineParameter"]["PerLengthImpedance"]["PerLengthPhaseImpedance"][impedance_name] math_obj["br_r"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.r") @@ -248,7 +248,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj["angmax"] = get(ravens_obj, "vad_ub", fill(60.0, nphases)) if (haskey(terminals[1], "ACDCTerminal.OperationalLimitSet")) - oplimitset_id = replace(split(terminals[1]["ACDCTerminal.OperationalLimitSet"], "::")[2], "'" => "") + oplimitset_id = _extract_name(terminals[1]["ACDCTerminal.OperationalLimitSet"]) oplimitset = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][2] else oplimitset = Dict() @@ -298,11 +298,11 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r math_obj = _init_math_obj_ravens("energy_consumer", name, ravens_obj, length(data_math["load"]) + 1; pass_props=pass_props) # Set the load bus based on connectivity node - connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) math_obj["load_bus"] = data_math["bus_lookup"][connectivity_node] # Handle Load Response Characteristics - load_response_characts = replace(split(ravens_obj["EnergyConsumer.LoadResponseCharacteristic"], "::")[2], "'" => "") + load_response_characts = _extract_name(ravens_obj["EnergyConsumer.LoadResponseCharacteristic"]) if load_response_characts == "Constant Z" math_obj["model"] = IMPEDANCE elseif load_response_characts == "Motor" @@ -328,7 +328,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r math_obj["qd"] = [ravens_obj["EnergyConsumer.q"] / power_scale_factor] # Set the nominal voltage - base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor) / (sqrt(3) / 2) @@ -337,12 +337,12 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r bus_conn = data_math["bus"][bus_info] if haskey(data_ravens["ConnectivityNode"][connectivity_node], "ConnectivityNode.OperationalLimitSet") - op_limit_id = replace(split(data_ravens["ConnectivityNode"][connectivity_node]["ConnectivityNode.OperationalLimitSet"], "::")[2], "'" => "") + op_limit_id = _extract_name(data_ravens["ConnectivityNode"][connectivity_node]["ConnectivityNode.OperationalLimitSet"]) op_limits = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"] # Loop through op. limits for lim in op_limits - lim_type_name = replace(split(lim["OperationalLimit.OperationalLimitType"], "::")[2], "'" => "") + lim_type_name = _extract_name(lim["OperationalLimit.OperationalLimitType"]) lim_type = data_ravens["OperationalLimitType"][lim_type_name]["OperationalLimitType.direction"] if lim_type == "OperationalLimitDirectionKind.high" @@ -422,7 +422,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav math_obj["name"] = "_virtual_gen.energy_source.$name" # Get connectivity node info (bus info) - connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) gen_bus = data_math["bus_lookup"][connectivity_node] math_obj["gen_bus"] = gen_bus bus_conn = data_math["bus"][string(gen_bus)] @@ -470,7 +470,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav math_obj["configuration"] = get(ravens_obj, "EnergySource.connectionKind", WYE) # Vnom and vbases_default - base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) vnom = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] / sqrt(nconductors) data_math["settings"]["vbases_default"][connectivity_node] = vnom / voltage_scale_factor @@ -602,7 +602,7 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ nconductors = length(connections) math_obj["connections"] = connections - connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] math_obj["gen_status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) @@ -621,7 +621,7 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) # Set the nominal voltage - base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] base_voltage = nominal_voltage / sqrt(nconductors) math_obj["vbase"] = base_voltage / voltage_scale_factor @@ -688,7 +688,7 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data nconductors = length(connections) math_obj["connections"] = connections - connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] math_obj["gen_status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) @@ -700,7 +700,7 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) # Set the nominal voltage - base_voltage_ref = replace(split(ravens_obj["ConductingEquipment.BaseVoltage"], "::")[2], "'" => "") + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] base_voltage = nominal_voltage / sqrt(nconductors) math_obj["vbase"] = base_voltage / voltage_scale_factor @@ -767,7 +767,7 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data math_obj["connections"] = connections # Set the bus - connectivity_node = replace(split(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) math_obj["storage_bus"] = data_math["bus_lookup"][connectivity_node] math_obj["status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) @@ -917,8 +917,8 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di nphases = length(f_conns) # Connectivity Nodes - f_node = replace(split(terminals[1]["Terminal.ConnectivityNode"], "::")[2], "'" => "") - t_node = replace(split(terminals[2]["Terminal.ConnectivityNode"], "::")[2], "'" => "") + f_node = _extract_name(terminals[1]["Terminal.ConnectivityNode"]) + t_node = _extract_name(terminals[2]["Terminal.ConnectivityNode"]) math_obj["f_bus"] = data_math["bus_lookup"][f_node] math_obj["t_bus"] = data_math["bus_lookup"][t_node] diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index adf2ec79a..188a1ccad 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -70,3 +70,10 @@ function _admittance_conversion_ravens(data_eng::Dict{String,<:Any}, eng_obj::Di return _admittance_matrix .* get(eng_obj, "Conductor.length", 1.0) .* freq ./ 1e2 # divide by 2 to get both sides _to and _fr end + +"extracts the name from a ravens reference string" +function _extract_name(element) + + name = replace(split(element, "::")[2], "'" => "") + return name +end From 2fb384d68d1cc856d1e86c0f5cd929e79a9fdfcf Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 7 Oct 2024 15:45:47 -0600 Subject: [PATCH 16/99] REF: replace SvStatus with Equipment.inService --- src/data_model/transformations/ravens2math.jl | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 5ca5bbfea..5dd35d107 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -261,7 +261,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj[t_key] = haskey(oplimitset, f_key) ? fill(oplimitset[f_key], nphases) : fill(Inf, nphases) end - math_obj["br_status"] = get(ravens_obj, "ConductingEquipment.SvStatus", 1) + math_obj["br_status"] = get(ravens_obj, "Equipment.inService", "true") == "true" ? 1 : 0 data_math["branch"]["$(math_obj["index"])"] = math_obj push!(data_math["map"], Dict{String,Any}( @@ -387,7 +387,8 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end # Set status, dispatchable flag, and index - math_obj["status"] = haskey(ravens_obj, "ConductingEquipment.SvStatus") ? ravens_obj["ConductingEquipment.SvStatus"] : 1 + math_obj["status"] = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" + math_obj["status"] = math_obj["status"] == "true" ? 1 : 0 math_obj["dispatchable"] = 0 data_math["load"]["$(math_obj["index"])"] = math_obj @@ -466,7 +467,9 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav end # Generator status and configuration - math_obj["gen_status"] = haskey(ravens_obj, "ConductingEquipment.SvStatus") ? Int(ravens_obj["ConductingEquipment.SvStatus"]) : 1 + math_obj["gen_status"] = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" + math_obj["gen_status"] = math_obj["gen_status"] == "true" ? 1 : 0 + math_obj["configuration"] = get(ravens_obj, "EnergySource.connectionKind", WYE) # Vnom and vbases_default @@ -604,7 +607,8 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] - math_obj["gen_status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) + math_obj["gen_status"] = get(ravens_obj, "Equipment.inService", "true") + math_obj["gen_status"] = status = math_obj["gen_status"] == "true" ? 1 : 0 # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) @@ -690,7 +694,8 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] - math_obj["gen_status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) + math_obj["gen_status"] = get(ravens_obj, "Equipment.inService", "true") + math_obj["gen_status"] = status = math_obj["gen_status"] == "true" ? 1 : 0 # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) @@ -769,7 +774,8 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data # Set the bus connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) math_obj["storage_bus"] = data_math["bus_lookup"][connectivity_node] - math_obj["status"] = status = Int(get(ravens_obj, "ConductingEquipment.SvStatus", 1)) + math_obj["status"] = get(ravens_obj, "Equipment.inService", "true") + math_obj["status"] = status = math_obj["status"] == "true" ? 1 : 0 # TODO: configuration for generators is not available on CIM (yet) math_obj["configuration"] = get(ravens_obj, "configuration", WYE) @@ -923,7 +929,8 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di math_obj["t_bus"] = data_math["bus_lookup"][t_node] # TODO: Status - math_obj["status"] = get(ravens_obj, "ConductingEquipment.SvStatus", 1) + math_obj["status"] = get(ravens_obj, "Equipment.inService", "true") + math_obj["status"] = status = math_obj["status"] == "true" ? 1 : 0 # State sw_state = get(ravens_obj, "Switch.open", "false") From b54fbc5dbc743879905af8501971a6baa22e0f6b Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 10 Oct 2024 10:39:23 -0600 Subject: [PATCH 17/99] FIX: charge and discharge on BatteryUnit. --- src/data_model/transformations/ravens2math.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 5dd35d107..10594f421 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -790,11 +790,11 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data end if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") - math_obj["charge_rating"] = -(get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf))./(power_scale_factor) + math_obj["charge_rating"] = (get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf))./(power_scale_factor) math_obj["discharge_rating"] = math_obj["charge_rating"] else - math_obj["charge_rating"] = -(get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf))./(power_scale_factor) - math_obj["discharge_rating"] = math_obj["charge_rating"] + math_obj["charge_rating"] = -(get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.minP", Inf))./(power_scale_factor) + math_obj["discharge_rating"] = (get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf))./(power_scale_factor) end math_obj["charge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.efficiencyCharge", 100.0) / 100.0 From 8ee4faa51cdaf370c4f4fa3ad5c975f857f55899 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 10 Oct 2024 15:39:33 -0600 Subject: [PATCH 18/99] WIP: Add Parser for PowerTransformer based on PowerTransformerEnd. Errors still exist. --- src/data_model/transformations/eng2math.jl | 5 + src/data_model/transformations/ravens2math.jl | 203 +++++++++++++++++- src/prob/common.jl | 8 +- 3 files changed, 207 insertions(+), 9 deletions(-) diff --git a/src/data_model/transformations/eng2math.jl b/src/data_model/transformations/eng2math.jl index f82208778..61f57e097 100644 --- a/src/data_model/transformations/eng2math.jl +++ b/src/data_model/transformations/eng2math.jl @@ -157,6 +157,11 @@ function transform_data_model( eng2math_passthrough=eng2math_passthrough, global_keys=global_keys, ) + + @info "$(data_math)" + + dadadsa + correct_network_data && correct_network_data!(data_math; make_pu=make_pu, make_pu_extensions=make_pu_extensions) return data_math diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 10594f421..2736ce074 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1,7 +1,7 @@ "cim-ravens to math object mapping" const _math_to_ravens = Dict{String,String}( "bus" => "connectivity_node", - "transformer" => "power_transformer", # TODO + "transformer" => "power_transformer", "switch" => "switch", # TODO # "shunt" => "shunt_compensator", "load" => "energy_consumer", @@ -19,7 +19,7 @@ const _ravens_node_elements = String[ "list of edge type elements in the ravens model" const _ravens_edge_elements = String[ - "conductor", "switch" + "conductor", "switch", "power_transformer" ] "list of all ravens asset types" @@ -57,6 +57,8 @@ function transform_data_model_ravens( global_keys=global_keys, ) + @info "$(data_math)" + # TODO: Correct network data transforms a lot of the values of lines/branches (other values maybe too) correct_network_data && correct_network_data!(data_math; make_pu=make_pu, make_pu_extensions=make_pu_extensions) @@ -275,12 +277,203 @@ end # TODO: Transformers need a lot of changes/refactors!!! -"converts ravensineering n-winding transformers into mathematical ideal 2-winding lossless transformer branches and impedance branches to represent the loss model" +"converts ravens n-winding transformers into mathematical ideal 2-winding lossless transformer branches and impedance branches to represent the loss model" function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) - _data_ravens_transformer = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"] + conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"] + power_scale_factor = data_math["settings"]["power_scale_factor"] + voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + voltage_scale_factor_sqrt3 = voltage_scale_factor * sqrt(3) + + for (name, ravens_obj) in get(conducting_equipment, "PowerTransformer", Dict{Any,Dict{String,Any}}()) + + # Build map first, so we can update it as we decompose the transformer + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => String[], + "unmap_function" => "_map_math2ravens_transformer!", + )) + + to_map = data_math["map"][end]["to"] + + # TODO: Check if we still need this function (or a similar function) + # _apply_xfmrcode!(ravens_obj, data_ravens) + + # Get nrw: number of windings + wdgs = ravens_obj["PowerTransformer.PowerTransformerEnd"] + nrw = length(wdgs) + + # Loop through Windings + wdg1_data = 0 + wdg2_data = 0 + wdgN_data = 0 + # connections + connections = Vector{Int64}[] + # Nodes + f_node = "" + t_node = "" + for wdg in wdgs + + # wdg phasecode + wdg_terminals = wdg["ConductingEquipment.Terminals"][1] + wdg_phasecode = wdg_terminals["Terminal.phases"] + + if (wdg_phasecode == "PhaseCode.ABC") + push!(connections, [1, 2, 3]) + elseif (wdg_phasecode == "PhaseCode.AB") + push!(connections, [1, 2]) + elseif (wdg_phasecode == "PhaseCode.AC") + push!(connections, [1, 3]) + elseif (wdg_phasecode == "PhaseCode.BC") + push!(connections, [2, 3]) + elseif (wdg_phasecode == "PhaseCode.A") + push!(connections, [1]) + elseif (wdg_phasecode == "PhaseCode.B") + push!(connections, [2]) + elseif (wdg_phasecode == "PhaseCode.C") + push!(connections, [3]) + else + @error("PhaseCode not supported yet!") + end + + # wdg endNumber + wdg_endNumber = wdg["TransformerEnd.endNumber"] + + # nphases + nphases = length(connections[1]) + + # Get Winding 1 information & create bus + if wdg_endNumber == 1 + wdg1_data = wdg + f_node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) + f_bus = data_math["bus_lookup"][f_node] + data_math["bus"][string(f_bus)]["terminals"] = connections[wdg_endNumber] + data_math["bus"][string(f_bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(f_bus)]["vmax"] = fill(Inf, nphases) + # Get Winding 2 information & create bus + elseif wdg_endNumber == 2 + wdg2_data = wdg + t_node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) + t_bus= data_math["bus_lookup"][t_node] + data_math["bus"][string(t_bus)]["terminals"] = connections[wdg_endNumber] + data_math["bus"][string(t_bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(t_bus)]["vmax"] = fill(Inf, nphases) + else + wdgN_data = wdg + end + end + + # nphases + nphases = length(connections[1]) + + # vnom and snom + vnom = [wdg1_data["PowerTransformerEnd.ratedU"], wdg2_data["PowerTransformerEnd.ratedU"]] + snom = [wdg1_data["PowerTransformerEnd.ratedS"], wdg2_data["PowerTransformerEnd.ratedS"]] + + # calculate zbase in which the data is specified, and convert to SI + zbase = (vnom.^2) ./ snom + + # x_sc is specified with respect to first winding + x_sc = [wdg1_data["TransformerEnd.MeshImpedance"]["TransformerMeshImpedance.x"]] + + # rs is specified with respect to each winding + r_s = [wdg1_data["PowerTransformerEnd.r"], wdg2_data["PowerTransformerEnd.r"]] + + g_sh = (wdg1_data["TransformerEnd.CoreAdmittance"]["TransformerCoreAdmittance.g"]) + b_sh = -(wdg1_data["TransformerEnd.CoreAdmittance"]["TransformerCoreAdmittance.b"]) - for (name, ravens_obj) in get(_data_ravens_transformer, "PowerTransformer", Dict{Any,Dict{String,Any}}()) + # data is measured externally, but we now refer it to the internal side + ratios = vnom/voltage_scale_factor + x_sc = x_sc./ratios[1]^2 + r_s = r_s./ratios.^2 + g_sh = g_sh*ratios[1]^2 + b_sh = b_sh*ratios[1]^2 + + # convert x_sc from list of upper triangle elements to an explicit dict + y_sh = g_sh + im*b_sh + z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) + + # TODO: RatioTapChanger + if haskey(wdg1_data, "TransformerEnd.RatioTapChanger") || haskey(wdg2_data, "TransformerEnd.RatioTapChanger") + else # default + tm_set = Vector{Vector{Float64}}(fill(fill(1.0, nphases), nrw)) + tm_lb = Vector{Vector{Float64}}(fill(fill(0.9, nphases), nrw)) + tm_ub = Vector{Vector{Float64}}(fill(fill(1.1, nphases), nrw)) + tm_fix = Vector{Vector{Bool}}(fill(ones(Bool, nphases), nrw)) + tm_step = Vector{Vector{Float64}}(fill(fill(1/32, nphases), nrw)) + end + + dims = length(tm_set[1]) + + + # TODO: Polarity + polarity = fill(1, nrw) + + # Status + status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" + status = status == "true" ? 1 : 0 + + # Build loss model + transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=dims, status=Int(status == ENABLED)) + + # Mathematical model for transformer + for w in 1:nrw + # 2-WINDING TRANSFORMER + + # Configuration + if wdgs[w]["PowerTransformerEnd.connectionKind"] == "WindingConnection.Y" + configuration = WYE + elseif wdgs[w]["PowerTransformerEnd.connectionKind"] == "WindingConnection.D" + configuration = DELTA + else + @error("PowerTransformer ConnectionKind not supported yet!") + end + + # make virtual bus and mark it for reduction + tm_nom = configuration==DELTA ? wdgs[w]["PowerTransformerEnd.ratedU"]*sqrt(3)/voltage_scale_factor : wdgs[w]["PowerTransformerEnd.ratedU"]/voltage_scale_factor + + # Transformer Object + transformer_2wa_obj = Dict{String,Any}( + "name" => "_virtual_transformer.$name.$w", + "source_id" => "_virtual_transformer.powertransformer.$name.$w", + "f_bus" => data_math["bus_lookup"][f_node], + "t_bus" => transformer_t_bus_w[w], + "tm_nom" => tm_nom, + "f_connections" => connections[w], + "t_connections" => connections[w], + "configuration" => configuration, + "polarity" => polarity[w], + "tm_set" => tm_set[w], + "tm_fix" => tm_fix[w], + "sm_ub" => get(wdgs[w], "PowerTransformerEnd.ratedS", Inf)/power_scale_factor, + "cm_ub" => get(wdgs[w], "PowerTransformerEnd.ratedI", Inf), + "status" => status, + "index" => length(data_math["transformer"])+1 + ) + + # TODO: RatioTapChanger + for prop in [pass_props] + if haskey(wdgs[w], prop) + transformer_2wa_obj[prop] = wdgs[w][prop] + end + end + transformer_2wa_obj["tm_lb"] = tm_lb[w] + transformer_2wa_obj["tm_ub"] = tm_ub[w] + transformer_2wa_obj["tm_step"] = tm_step[w] + + data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj + + ## TODO: Regulator Control + # if haskey(eng_obj,"controls") && !all(data_math["transformer"]["$(transformer_2wa_obj["index"])"]["tm_fix"]) + # end + + # TODO: Center-Tapped Transformers (3 Windings) + # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start + # end + + push!(to_map, "transformer.$(transformer_2wa_obj["index"])") + + end end end diff --git a/src/prob/common.jl b/src/prob/common.jl index 2a255bf27..f0edc9445 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,8 +116,8 @@ function instantiate_mc_model( ) end - # @info "$(data["storage"])" - # DEFINIDOEN_instantiate_mc_model + @info "$(data["transformer"])" + DEFINIDOEN_instantiate_mc_model return _IM.instantiate_model( data, @@ -157,8 +157,8 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - # @info "$(data["storage"])" - # DEFINIDOEN_instantiate_mc_model_ravens + @info "$(data["transformer"])" + DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( data, From f6698b930c37a5b798d86a70eadb653410fe0ff1 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 10 Oct 2024 16:36:55 -0600 Subject: [PATCH 19/99] WIP: debig powertransformer issues related to terminals and bus_type coming from build_loss --- src/data_model/transformations/eng2math.jl | 5 ----- src/data_model/transformations/ravens2math.jl | 10 ++++------ 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/data_model/transformations/eng2math.jl b/src/data_model/transformations/eng2math.jl index 61f57e097..f82208778 100644 --- a/src/data_model/transformations/eng2math.jl +++ b/src/data_model/transformations/eng2math.jl @@ -157,11 +157,6 @@ function transform_data_model( eng2math_passthrough=eng2math_passthrough, global_keys=global_keys, ) - - @info "$(data_math)" - - dadadsa - correct_network_data && correct_network_data!(data_math; make_pu=make_pu, make_pu_extensions=make_pu_extensions) return data_math diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 2736ce074..0ab60d81b 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -57,8 +57,6 @@ function transform_data_model_ravens( global_keys=global_keys, ) - @info "$(data_math)" - # TODO: Correct network data transforms a lot of the values of lines/branches (other values maybe too) correct_network_data && correct_network_data!(data_math; make_pu=make_pu, make_pu_extensions=make_pu_extensions) @@ -97,7 +95,7 @@ function _map_ravens2math( n => Dict{String,Any}( "per_unit" => get(_data_ravens, "per_unit", false), "is_projected" => get(nw, "is_projected", false), - "is_kron_reduced" => get(nw, "is_kron_reduced", false), + "is_kron_reduced" => get(nw, "is_kron_reduced", true), # TODO: Kron reduction? "settings" => deepcopy(_settings), "time_elapsed" => get(nw, "time_elapsed", 1.0), ) for (n,nw) in _data_ravens["nw"] @@ -111,7 +109,7 @@ function _map_ravens2math( "per_unit" => get(_data_ravens, "per_unit", false), "data_model" => MATHEMATICAL, "is_projected" => get(_data_ravens, "is_projected", false), - "is_kron_reduced" => get(_data_ravens, "is_kron_reduced", false), + "is_kron_reduced" => get(_data_ravens, "is_kron_reduced", true), # TODO: Kron reduction? "settings" => deepcopy(_settings), "time_elapsed" => get(_data_ravens, "time_elapsed", 1.0), ) @@ -414,7 +412,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data status = status == "true" ? 1 : 0 # Build loss model - transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=dims, status=Int(status == ENABLED)) + transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=dims, status=status) # Mathematical model for transformer for w in 1:nrw @@ -435,7 +433,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Transformer Object transformer_2wa_obj = Dict{String,Any}( "name" => "_virtual_transformer.$name.$w", - "source_id" => "_virtual_transformer.powertransformer.$name.$w", + "source_id" => "_virtual_transformer.transformer.$name.$w", "f_bus" => data_math["bus_lookup"][f_node], "t_bus" => transformer_t_bus_w[w], "tm_nom" => tm_nom, From 86f3f47eb96977c8eb8186ef756ce4e8e4d8b2dd Mon Sep 17 00:00:00 2001 From: jjospina Date: Fri, 11 Oct 2024 10:22:16 -0600 Subject: [PATCH 20/99] FIX: powertransformer issue related to fnode when creating virtual branches. --- src/data_model/transformations/ravens2math.jl | 6 +++++- src/prob/common.jl | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 0ab60d81b..28841a6c6 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -430,11 +430,15 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # make virtual bus and mark it for reduction tm_nom = configuration==DELTA ? wdgs[w]["PowerTransformerEnd.ratedU"]*sqrt(3)/voltage_scale_factor : wdgs[w]["PowerTransformerEnd.ratedU"]/voltage_scale_factor + # Get correct f_node for winding + wdg_term = wdgs[w]["ConductingEquipment.Terminals"][1] + f_node_wdgterm = _extract_name(wdg_term["Terminal.ConnectivityNode"]) + # Transformer Object transformer_2wa_obj = Dict{String,Any}( "name" => "_virtual_transformer.$name.$w", "source_id" => "_virtual_transformer.transformer.$name.$w", - "f_bus" => data_math["bus_lookup"][f_node], + "f_bus" => data_math["bus_lookup"][f_node_wdgterm], "t_bus" => transformer_t_bus_w[w], "tm_nom" => tm_nom, "f_connections" => connections[w], diff --git a/src/prob/common.jl b/src/prob/common.jl index f0edc9445..3ab55c1f6 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,8 +116,8 @@ function instantiate_mc_model( ) end - @info "$(data["transformer"])" - DEFINIDOEN_instantiate_mc_model + # @info "$(data["transformer"])" + # DEFINIDOEN_instantiate_mc_model return _IM.instantiate_model( data, @@ -157,8 +157,8 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - @info "$(data["transformer"])" - DEFINIDOEN_instantiate_mc_model_ravens + # @info "$(data["transformer"])" + # DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( data, From 87269410692fa9a57b5b481991df35783968f893 Mon Sep 17 00:00:00 2001 From: Juan Ospina Date: Fri, 11 Oct 2024 14:07:55 -0600 Subject: [PATCH 21/99] REF: phasecode in transformers. --- src/data_model/transformations/ravens2math.jl | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 28841a6c6..40bd45465 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -310,26 +310,26 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Nodes f_node = "" t_node = "" + + phasecode_map = Dict( + "PhaseCode.ABC" => [1, 2, 3], + "PhaseCode.AB" => [1, 2], + "PhaseCode.AC" => [1, 3], + "PhaseCode.BC" => [2, 3], + "PhaseCode.A" => [1], + "PhaseCode.B" => [2], + "PhaseCode.C" => [3] + ) + for wdg in wdgs # wdg phasecode wdg_terminals = wdg["ConductingEquipment.Terminals"][1] wdg_phasecode = wdg_terminals["Terminal.phases"] - if (wdg_phasecode == "PhaseCode.ABC") - push!(connections, [1, 2, 3]) - elseif (wdg_phasecode == "PhaseCode.AB") - push!(connections, [1, 2]) - elseif (wdg_phasecode == "PhaseCode.AC") - push!(connections, [1, 3]) - elseif (wdg_phasecode == "PhaseCode.BC") - push!(connections, [2, 3]) - elseif (wdg_phasecode == "PhaseCode.A") - push!(connections, [1]) - elseif (wdg_phasecode == "PhaseCode.B") - push!(connections, [2]) - elseif (wdg_phasecode == "PhaseCode.C") - push!(connections, [3]) + # Connections (based on phasecode_map) + if haskey(phasecode_map, wdg_phasecode) + push!(connections, phasecode_map[wdg_phasecode]) else @error("PhaseCode not supported yet!") end @@ -356,8 +356,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data data_math["bus"][string(t_bus)]["terminals"] = connections[wdg_endNumber] data_math["bus"][string(t_bus)]["vmin"] = fill(0.0, nphases) data_math["bus"][string(t_bus)]["vmax"] = fill(Inf, nphases) - else - wdgN_data = wdg end end From 4688964c85a80ec5c52dee25494eccb66d433e5a Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 14 Oct 2024 12:39:52 -0600 Subject: [PATCH 22/99] ADD: ShuntCompensator ravens parser. --- src/data_model/transformations/ravens2math.jl | 84 ++++++++++++++++++- src/data_model/utils_ravens.jl | 10 +++ 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 40bd45465..59a9538d3 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -2,8 +2,8 @@ const _math_to_ravens = Dict{String,String}( "bus" => "connectivity_node", "transformer" => "power_transformer", - "switch" => "switch", # TODO - # "shunt" => "shunt_compensator", + "switch" => "switch", + "shunt" => "shunt_compensator", "load" => "energy_consumer", "generator" => "rotating_machine", "solar" => "photovoltaic_unit", @@ -14,7 +14,7 @@ const _math_to_ravens = Dict{String,String}( "list of nodal type elements in the ravens model" const _ravens_node_elements = String[ - "energy_consumer", "rotating_machine", "power_electronics", "energy_source" + "energy_consumer", "shunt_compensator", "rotating_machine", "power_electronics", "energy_source" ] "list of edge type elements in the ravens model" @@ -1165,3 +1165,81 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di end end + + +"converts ravens generic shunt components into mathematical shunt components" +function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + + regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] + power_scale_factor = data_math["settings"]["power_scale_factor"] + voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + + for (name, ravens_obj) in get(regulating_cond_eq, "ShuntCompensator", Dict{Any,Dict{String,Any}}()) + + math_obj = _init_math_obj("shunt", name, ravens_obj, length(data_math["shunt"])+1; pass_props=pass_props) + + # Get connectivity node info (bus info) + connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) + math_obj["shunt_bus"] = data_math["bus_lookup"][connectivity_node] + + # Status + status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" + math_obj["status"] = status == "true" ? 1 : 0 + + # Connections/phases obtained from Terminals + if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") + phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] + if (phasecode == "PhaseCode.ABC") + connections = [1, 2, 3] + elseif (phasecode == "PhaseCode.AB") + connections = [1, 2] + elseif (phasecode == "PhaseCode.AC") + connections = [1, 3] + elseif (phasecode == "PhaseCode.BC") + connections = [2, 3] + elseif (phasecode == "PhaseCode.A") + connections = [1] + elseif (phasecode == "PhaseCode.B") + connections = [2] + elseif (phasecode == "PhaseCode.C") + connections = [3] + else + @error("PhaseCode not supported yet!") + end + else + connections = [1, 2, 3] # default + end + math_obj["connections"] = connections + terminals = connections + + # TODO: dispatchable + math_obj["dispatchable"] = 0 + + # bs - TODO: make sure b matrix is being calculated correctly + b = ravens_obj["LinearShuntCompensator.bPerSection"] + B = _calc_shunt_admittance_matrix(terminals, b) + math_obj["bs"] = B + + # gs + if haskey(ravens_obj, "LinearShuntCompensator.gPerSection") + g = ravens_obj["LinearShuntCompensator.gPerSection"] + G = _calc_shunt_admittance_matrix(terminals, g) + math_obj["gs"] = G + else + math_obj["gs"] = zeros(size(math_obj["bs"])) + end + + # Index + data_math["shunt"]["$(math_obj["index"])"] = math_obj + + # TODO: Add CapControl + # ..... + + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "shunt.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_shunt!", + )) + + end +end diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 188a1ccad..8376b31c7 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -77,3 +77,13 @@ function _extract_name(element) name = replace(split(element, "::")[2], "'" => "") return name end + + +"calculates the shunt admittance matrix based on terminals and b or g" +function _calc_shunt_admittance_matrix(terminals, b) + + N = length(terminals) + _shunt_matrix = b* Matrix(LinearAlgebra.I, N, N) + return _shunt_matrix + +end From 5f89b05f4dabfe5987040020ee6fbc835d531e71 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 7 Nov 2024 14:03:20 -0700 Subject: [PATCH 23/99] FIX: issues to be able to run test case with switches. --- src/data_model/transformations/ravens2math.jl | 136 +++++++++--------- 1 file changed, 67 insertions(+), 69 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 59a9538d3..5ba8c91e9 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -535,8 +535,9 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r # Loop through op. limits for lim in op_limits - lim_type_name = _extract_name(lim["OperationalLimit.OperationalLimitType"]) - lim_type = data_ravens["OperationalLimitType"][lim_type_name]["OperationalLimitType.direction"] + # lim_type_name = _extract_name(lim["OperationalLimit.OperationalLimitType"]) # TODO: separate way of doing where OperationalLimitType is separated + # lim_type = data_ravens["OperationalLimitType"][lim_type_name]["OperationalLimitType.direction"] + lim_type = lim["OperationalLimit.OperationalLimitType"]["OperationalLimitType.direction"] if lim_type == "OperationalLimitDirectionKind.high" op_limit_max = lim["VoltageLimit.value"] / voltage_scale_factor_sqrt3 @@ -1038,7 +1039,7 @@ end "converts ravens switches into mathematical switches and (if neeed) impedance branches to represent loss model" function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) - # TODO enable real switches (right now only using vitual lines) + # TODO enable real switches (right now only using virtual lines) if haskey(data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"], "Switch") conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"] @@ -1112,6 +1113,9 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di @error("f_conns are not equal to t_conns!. Revise connections/phases in Switch terminals") end + math_obj["f_connections"] = f_conns + math_obj["t_connections"] = t_conns + # Phases nphases = length(f_conns) @@ -1137,20 +1141,11 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di for (f_key, t_key) in [("Switch.ratedCurrent", "current_rating"), ("cm_ub_b", "c_rating_b"), ("cm_ub_c", "c_rating_c"), ("sm_ub", "thermal_rating"), ("sm_ub_b", "rate_b"), ("sm_ub_c", "rate_c")] math_obj[t_key] = haskey(ravens_obj, f_key) ? fill(ravens_obj[f_key], nphases) : fill(Inf, nphases) - - @info "$(math_obj[t_key])" - end # Map index map_to = "switch.$(math_obj["index"])" - # TODO: Apply linecode? No information is given in CIM related to linecodes - - - # TODO: Create virtual bus - - # Push Mapping data_math["switch"]["$(math_obj["index"])"] = math_obj @@ -1170,76 +1165,79 @@ end "converts ravens generic shunt components into mathematical shunt components" function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) - regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] - power_scale_factor = data_math["settings"]["power_scale_factor"] - voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] + if haskey(data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"], "RegulatingCondEq") + regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] + power_scale_factor = data_math["settings"]["power_scale_factor"] + voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] - for (name, ravens_obj) in get(regulating_cond_eq, "ShuntCompensator", Dict{Any,Dict{String,Any}}()) + for (name, ravens_obj) in get(regulating_cond_eq, "ShuntCompensator", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj("shunt", name, ravens_obj, length(data_math["shunt"])+1; pass_props=pass_props) + math_obj = _init_math_obj("shunt", name, ravens_obj, length(data_math["shunt"])+1; pass_props=pass_props) - # Get connectivity node info (bus info) - connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) - math_obj["shunt_bus"] = data_math["bus_lookup"][connectivity_node] + # Get connectivity node info (bus info) + connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) + math_obj["shunt_bus"] = data_math["bus_lookup"][connectivity_node] - # Status - status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" - math_obj["status"] = status == "true" ? 1 : 0 + # Status + status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" + math_obj["status"] = status == "true" ? 1 : 0 - # Connections/phases obtained from Terminals - if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") - phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] - if (phasecode == "PhaseCode.ABC") - connections = [1, 2, 3] - elseif (phasecode == "PhaseCode.AB") - connections = [1, 2] - elseif (phasecode == "PhaseCode.AC") - connections = [1, 3] - elseif (phasecode == "PhaseCode.BC") - connections = [2, 3] - elseif (phasecode == "PhaseCode.A") - connections = [1] - elseif (phasecode == "PhaseCode.B") - connections = [2] - elseif (phasecode == "PhaseCode.C") - connections = [3] + # Connections/phases obtained from Terminals + if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") + phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] + if (phasecode == "PhaseCode.ABC") + connections = [1, 2, 3] + elseif (phasecode == "PhaseCode.AB") + connections = [1, 2] + elseif (phasecode == "PhaseCode.AC") + connections = [1, 3] + elseif (phasecode == "PhaseCode.BC") + connections = [2, 3] + elseif (phasecode == "PhaseCode.A") + connections = [1] + elseif (phasecode == "PhaseCode.B") + connections = [2] + elseif (phasecode == "PhaseCode.C") + connections = [3] + else + @error("PhaseCode not supported yet!") + end else - @error("PhaseCode not supported yet!") + connections = [1, 2, 3] # default end - else - connections = [1, 2, 3] # default - end - math_obj["connections"] = connections - terminals = connections + math_obj["connections"] = connections + terminals = connections - # TODO: dispatchable - math_obj["dispatchable"] = 0 + # TODO: dispatchable + math_obj["dispatchable"] = 0 - # bs - TODO: make sure b matrix is being calculated correctly - b = ravens_obj["LinearShuntCompensator.bPerSection"] - B = _calc_shunt_admittance_matrix(terminals, b) - math_obj["bs"] = B + # bs - TODO: make sure b matrix is being calculated correctly + b = ravens_obj["LinearShuntCompensator.bPerSection"] + B = _calc_shunt_admittance_matrix(terminals, b) + math_obj["bs"] = B - # gs - if haskey(ravens_obj, "LinearShuntCompensator.gPerSection") - g = ravens_obj["LinearShuntCompensator.gPerSection"] - G = _calc_shunt_admittance_matrix(terminals, g) - math_obj["gs"] = G - else - math_obj["gs"] = zeros(size(math_obj["bs"])) - end + # gs + if haskey(ravens_obj, "LinearShuntCompensator.gPerSection") + g = ravens_obj["LinearShuntCompensator.gPerSection"] + G = _calc_shunt_admittance_matrix(terminals, g) + math_obj["gs"] = G + else + math_obj["gs"] = zeros(size(math_obj["bs"])) + end - # Index - data_math["shunt"]["$(math_obj["index"])"] = math_obj + # Index + data_math["shunt"]["$(math_obj["index"])"] = math_obj - # TODO: Add CapControl - # ..... + # TODO: Add CapControl + # ..... - push!(data_math["map"], Dict{String,Any}( - "from" => name, - "to" => "shunt.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_shunt!", - )) + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "shunt.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_shunt!", + )) + + end end end From 6aa181df4ca6eaec625a48d08a3f155d294b2421 Mon Sep 17 00:00:00 2001 From: jjospina Date: Fri, 8 Nov 2024 11:54:43 -0700 Subject: [PATCH 24/99] REF: ravens2math by removing if statements and using phasecode map in utils ravens. --- src/data_model/transformations/ravens2math.jl | 132 +++--------------- src/data_model/utils_ravens.jl | 10 ++ 2 files changed, 27 insertions(+), 115 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 5ba8c91e9..c3807b39c 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -294,9 +294,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data to_map = data_math["map"][end]["to"] - # TODO: Check if we still need this function (or a similar function) - # _apply_xfmrcode!(ravens_obj, data_ravens) - # Get nrw: number of windings wdgs = ravens_obj["PowerTransformer.PowerTransformerEnd"] nrw = length(wdgs) @@ -311,25 +308,15 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data f_node = "" t_node = "" - phasecode_map = Dict( - "PhaseCode.ABC" => [1, 2, 3], - "PhaseCode.AB" => [1, 2], - "PhaseCode.AC" => [1, 3], - "PhaseCode.BC" => [2, 3], - "PhaseCode.A" => [1], - "PhaseCode.B" => [2], - "PhaseCode.C" => [3] - ) - for wdg in wdgs # wdg phasecode wdg_terminals = wdg["ConductingEquipment.Terminals"][1] wdg_phasecode = wdg_terminals["Terminal.phases"] - # Connections (based on phasecode_map) - if haskey(phasecode_map, wdg_phasecode) - push!(connections, phasecode_map[wdg_phasecode]) + # Connections (based on _phasecode_map) + if haskey(_phasecode_map, wdg_phasecode) + push!(connections, _phasecode_map[wdg_phasecode]) else @error("PhaseCode not supported yet!") end @@ -401,7 +388,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data dims = length(tm_set[1]) - # TODO: Polarity polarity = fill(1, nrw) @@ -535,9 +521,13 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r # Loop through op. limits for lim in op_limits - # lim_type_name = _extract_name(lim["OperationalLimit.OperationalLimitType"]) # TODO: separate way of doing where OperationalLimitType is separated - # lim_type = data_ravens["OperationalLimitType"][lim_type_name]["OperationalLimitType.direction"] - lim_type = lim["OperationalLimit.OperationalLimitType"]["OperationalLimitType.direction"] + + if haskey(data_ravens, "OperationalLimitType") + lim_type_name = _extract_name(lim["OperationalLimit.OperationalLimitType"]) + lim_type = data_ravens["OperationalLimitType"][lim_type_name]["OperationalLimitType.direction"] + else + lim_type = lim["OperationalLimit.OperationalLimitType"]["OperationalLimitType.direction"] + end if lim_type == "OperationalLimitDirectionKind.high" op_limit_max = lim["VoltageLimit.value"] / voltage_scale_factor_sqrt3 @@ -638,23 +628,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav # Terminal Phases if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] - if (phasecode == "PhaseCode.ABC") - math_obj["connections"] = [1, 2, 3] - elseif (phasecode == "PhaseCode.AB") - math_obj["connections"] = [1, 2] - elseif (phasecode == "PhaseCode.AC") - math_obj["connections"] = [1, 3] - elseif (phasecode == "PhaseCode.BC") - math_obj["connections"] = [2, 3] - elseif (phasecode == "PhaseCode.A") - math_obj["connections"] = [1] - elseif (phasecode == "PhaseCode.B") - math_obj["connections"] = [2] - elseif (phasecode == "PhaseCode.C") - math_obj["connections"] = [3] - else - @error("PhaseCode not supported yet!") - end + math_obj["connections"] = _phasecode_map[phasecode] else math_obj["connections"] = bus_conn["terminals"] end @@ -775,23 +749,7 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ # Connections/phases obtained from Terminals if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] - if (phasecode == "PhaseCode.ABC") - connections = [1, 2, 3] - elseif (phasecode == "PhaseCode.AB") - connections = [1, 2] - elseif (phasecode == "PhaseCode.AC") - connections = [1, 3] - elseif (phasecode == "PhaseCode.BC") - connections = [2, 3] - elseif (phasecode == "PhaseCode.A") - connections = [1] - elseif (phasecode == "PhaseCode.B") - connections = [2] - elseif (phasecode == "PhaseCode.C") - connections = [3] - else - @error("PhaseCode not supported yet!") - end + connections = _phasecode_map[phasecode] else connections = [1, 2, 3] # default end @@ -1051,56 +1009,16 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di # Terminals and phases terminals = ravens_obj["ConductingEquipment.Terminals"] - # TODO: refactor - Loop through terminals and verify connections + # Loop through terminals f_conns = [0,0,0] t_conns = [0,0,0] for term in terminals if haskey(term, "Terminal.phases") phasecode = term["Terminal.phases"] - if (phasecode == "PhaseCode.ABC") - if term["ACDCTerminal.sequenceNumber"] == 1 - f_conns = [1, 2, 3] - else - t_conns = [1, 2, 3] - end - elseif (phasecode == "PhaseCode.AB") - if term["ACDCTerminal.sequenceNumber"] == 1 - f_conns = [1, 2] - else - t_conns = [1, 2] - end - elseif (phasecode == "PhaseCode.AC") - if term["ACDCTerminal.sequenceNumber"] == 1 - f_conns = [1, 3] - else - t_conns = [1, 3] - end - elseif (phasecode == "PhaseCode.BC") - if term["ACDCTerminal.sequenceNumber"] == 1 - f_conns = [2, 3] - else - t_conns = [2, 3] - end - elseif (phasecode == "PhaseCode.A") - if term["ACDCTerminal.sequenceNumber"] == 1 - f_conns = [1] - else - t_conns = [1] - end - elseif (phasecode == "PhaseCode.B") - if term["ACDCTerminal.sequenceNumber"] == 1 - f_conns = [2] - else - t_conns = [2] - end - elseif (phasecode == "PhaseCode.C") - if term["ACDCTerminal.sequenceNumber"] == 1 - f_conns = [3] - else - t_conns = [3] - end + if term["ACDCTerminal.sequenceNumber"] == 1 + f_conns = _phasecode_map[phasecode] else - @error("PhaseCode not supported yet!") + t_conns = _phasecode_map[phasecode] end else f_conns = [1, 2, 3] @@ -1185,23 +1103,7 @@ function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data # Connections/phases obtained from Terminals if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] - if (phasecode == "PhaseCode.ABC") - connections = [1, 2, 3] - elseif (phasecode == "PhaseCode.AB") - connections = [1, 2] - elseif (phasecode == "PhaseCode.AC") - connections = [1, 3] - elseif (phasecode == "PhaseCode.BC") - connections = [2, 3] - elseif (phasecode == "PhaseCode.A") - connections = [1] - elseif (phasecode == "PhaseCode.B") - connections = [2] - elseif (phasecode == "PhaseCode.C") - connections = [3] - else - @error("PhaseCode not supported yet!") - end + connections = _phasecode_map[phasecode] else connections = [1, 2, 3] # default end diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 8376b31c7..7091e60ae 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -1,3 +1,13 @@ +const _phasecode_map = Dict( + "PhaseCode.ABC" => [1, 2, 3], + "PhaseCode.AB" => [1, 2], + "PhaseCode.AC" => [1, 3], + "PhaseCode.BC" => [2, 3], + "PhaseCode.A" => [1], + "PhaseCode.B" => [2], + "PhaseCode.C" => [3] +) + "initializes the base math object of any type" function _init_math_obj_ravens(obj_type::String, eng_id::Any, eng_obj::Dict{String,<:Any}, index::Int; pass_props::Vector{String}=String[])::Dict{String,Any} From e04a1f00863bf93ea7d68bed997055c7dc4e4bb9 Mon Sep 17 00:00:00 2001 From: jjospina Date: Fri, 8 Nov 2024 13:13:17 -0700 Subject: [PATCH 25/99] REF: ravens2math to reduce if levels. --- src/data_model/transformations/ravens2math.jl | 258 +++++++++--------- 1 file changed, 125 insertions(+), 133 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index c3807b39c..fb56328fb 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -468,12 +468,12 @@ end Converts ravens load components into mathematical load components. """ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) - conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] + energy_connections = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] power_scale_factor = data_math["settings"]["power_scale_factor"] voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] voltage_scale_factor_sqrt3 = voltage_scale_factor * sqrt(3) - for (name, ravens_obj) in get(conducting_equipment, "EnergyConsumer", Dict{Any,Dict{String,Any}}()) + for (name, ravens_obj) in get(energy_connections, "EnergyConsumer", Dict{Any,Dict{String,Any}}()) math_obj = _init_math_obj_ravens("energy_consumer", name, ravens_obj, length(data_math["load"]) + 1; pass_props=pass_props) # Set the load bus based on connectivity node @@ -598,11 +598,11 @@ end Converts ravens voltage sources into mathematical generators and (if needed) impedance branches to represent the loss model. """ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) - conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] + energy_connections = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] voltage_scale_factor_sqrt3 = voltage_scale_factor * sqrt(3) - for (name, ravens_obj) in get(conducting_equipment, "EnergySource", Dict{Any,Dict{String,Any}}()) + for (name, ravens_obj) in get(energy_connections, "EnergySource", Dict{Any,Dict{String,Any}}()) math_obj = _init_math_obj_ravens("energy_source", name, ravens_obj, length(data_math["gen"]) + 1; pass_props=pass_props) math_obj["name"] = "_virtual_gen.energy_source.$name" @@ -735,85 +735,86 @@ end "converts engineering generators into mathematical generators" function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + energy_connections = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] - if haskey(data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"], "RegulatingCondEq") + if haskey(energy_connections, "RegulatingCondEq") - regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] + regulating_cond_eq = energy_connections["RegulatingCondEq"] power_scale_factor = data_math["settings"]["power_scale_factor"] voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] for (name, ravens_obj) in get(regulating_cond_eq, "RotatingMachine", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj_ravens("rotating_machine", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) + math_obj = _init_math_obj_ravens("rotating_machine", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) - # Connections/phases obtained from Terminals - if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") - phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] - connections = _phasecode_map[phasecode] - else - connections = [1, 2, 3] # default - end - - nconductors = length(connections) - math_obj["connections"] = connections + # Connections/phases obtained from Terminals + if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") + phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] + connections = _phasecode_map[phasecode] + else + connections = [1, 2, 3] # default + end - connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) - math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] - math_obj["gen_status"] = get(ravens_obj, "Equipment.inService", "true") - math_obj["gen_status"] = status = math_obj["gen_status"] == "true" ? 1 : 0 + nconductors = length(connections) + math_obj["connections"] = connections - # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) - math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) + connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) + math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] + math_obj["gen_status"] = get(ravens_obj, "Equipment.inService", "true") + math_obj["gen_status"] = status = math_obj["gen_status"] == "true" ? 1 : 0 - # Set Pmax for generator - if !haskey(ravens_obj, "GeneratingUnit.maxOperatingP") - math_obj["pmax"] = ((get(ravens_obj, "RotatingMachine.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - else - math_obj["pmax"] = ((get(ravens_obj, "GeneratingUnit.maxOperatingP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - end + # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) + math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) - # Set bus type - bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] - data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) + # Set Pmax for generator + if !haskey(ravens_obj, "GeneratingUnit.maxOperatingP") + math_obj["pmax"] = ((get(ravens_obj, "RotatingMachine.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + else + math_obj["pmax"] = ((get(ravens_obj, "GeneratingUnit.maxOperatingP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + end - # Set the nominal voltage - base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) - nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - base_voltage = nominal_voltage / sqrt(nconductors) - math_obj["vbase"] = base_voltage / voltage_scale_factor - - if control_mode == Int(ISOCHRONOUS) && status == 1 - data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) - data_math["bus"]["$(math_obj["gen_bus"])"]["vmax"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) - data_math["bus"]["$(math_obj["gen_bus"])"]["vmin"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) - data_math["bus"]["$(math_obj["gen_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["gen_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["gen_bus"])"]["terminals"]] - end + # Set bus type + bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] + data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) + + # Set the nominal voltage + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) + nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + base_voltage = nominal_voltage / sqrt(nconductors) + math_obj["vbase"] = base_voltage / voltage_scale_factor + + if control_mode == Int(ISOCHRONOUS) && status == 1 + data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vmax"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["vmin"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) + data_math["bus"]["$(math_obj["gen_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["gen_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["gen_bus"])"]["terminals"]] + end - # Set pmin - math_obj["pmin"] = ((get(ravens_obj, "GeneratingUnit.minOperatingP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set qmin - math_obj["qmin"] = ((get(ravens_obj, "RotatingMachine.minQ", -Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set qmax - math_obj["qmax"] = ((get(ravens_obj, "RotatingMachine.maxQ", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set pmin + math_obj["pmin"] = ((get(ravens_obj, "GeneratingUnit.minOperatingP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set qmin + math_obj["qmin"] = ((get(ravens_obj, "RotatingMachine.minQ", -Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set qmax + math_obj["qmax"] = ((get(ravens_obj, "RotatingMachine.maxQ", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set pg and qg - math_obj["pg"] = (get(ravens_obj, "RotatingMachine.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) - math_obj["qg"] = (get(ravens_obj, "RotatingMachine.q", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + # Set pg and qg + math_obj["pg"] = (get(ravens_obj, "RotatingMachine.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["qg"] = (get(ravens_obj, "RotatingMachine.q", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) - # TODO: add a polynomial parameters to be added to gen cost - _add_gen_cost_model!(math_obj, ravens_obj) + # TODO: add a polynomial parameters to be added to gen cost + _add_gen_cost_model!(math_obj, ravens_obj) - # TODO: configuration for generators is not available on CIM (yet) - math_obj["configuration"] = get(ravens_obj, "configuration", WYE) + # TODO: configuration for generators is not available on CIM (yet) + math_obj["configuration"] = get(ravens_obj, "configuration", WYE) - # Set index - data_math["gen"]["$(math_obj["index"])"] = math_obj + # Set index + data_math["gen"]["$(math_obj["index"])"] = math_obj - push!(data_math["map"], Dict{String,Any}( - "from" => name, - "to" => "gen.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_rotating_machine!", - )) + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "gen.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_rotating_machine!", + )) end end @@ -823,10 +824,11 @@ end "converts ravens power_electronics units such as PVs and Batteries into mathematical components" function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + energy_connections = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] - if haskey(data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"], "RegulatingCondEq") + if haskey(energy_connections, "RegulatingCondEq") - regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] + regulating_cond_eq = energy_connections["RegulatingCondEq"] power_scale_factor = data_math["settings"]["power_scale_factor"] voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] @@ -988,103 +990,95 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data )) end end - end - end "converts ravens switches into mathematical switches and (if neeed) impedance branches to represent loss model" function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"] - # TODO enable real switches (right now only using virtual lines) - if haskey(data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"], "Switch") - - conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"] - - for (name, ravens_obj) in get(conducting_equipment, "Switch", Dict{Any,Dict{String,Any}}()) + for (name, ravens_obj) in get(conducting_equipment, "Switch", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj_ravens("switch", name, ravens_obj, length(data_math["switch"])+1; pass_props=pass_props) + math_obj = _init_math_obj_ravens("switch", name, ravens_obj, length(data_math["switch"])+1; pass_props=pass_props) - # Terminals and phases - terminals = ravens_obj["ConductingEquipment.Terminals"] + # Terminals and phases + terminals = ravens_obj["ConductingEquipment.Terminals"] - # Loop through terminals - f_conns = [0,0,0] - t_conns = [0,0,0] - for term in terminals - if haskey(term, "Terminal.phases") - phasecode = term["Terminal.phases"] - if term["ACDCTerminal.sequenceNumber"] == 1 - f_conns = _phasecode_map[phasecode] - else - t_conns = _phasecode_map[phasecode] - end + # Loop through terminals + f_conns = [0,0,0] + t_conns = [0,0,0] + for term in terminals + if haskey(term, "Terminal.phases") + phasecode = term["Terminal.phases"] + if term["ACDCTerminal.sequenceNumber"] == 1 + f_conns = _phasecode_map[phasecode] else - f_conns = [1, 2, 3] - t_conns = [1, 2, 3] + t_conns = _phasecode_map[phasecode] end + else + f_conns = [1, 2, 3] + t_conns = [1, 2, 3] end + end - # Verify connections are correct. - if (f_conns != t_conns ) - @error("f_conns are not equal to t_conns!. Revise connections/phases in Switch terminals") - end - - math_obj["f_connections"] = f_conns - math_obj["t_connections"] = t_conns + # Verify connections are correct. + if (f_conns != t_conns ) + @error("f_conns are not equal to t_conns!. Revise connections/phases in Switch terminals") + end - # Phases - nphases = length(f_conns) + math_obj["f_connections"] = f_conns + math_obj["t_connections"] = t_conns - # Connectivity Nodes - f_node = _extract_name(terminals[1]["Terminal.ConnectivityNode"]) - t_node = _extract_name(terminals[2]["Terminal.ConnectivityNode"]) - math_obj["f_bus"] = data_math["bus_lookup"][f_node] - math_obj["t_bus"] = data_math["bus_lookup"][t_node] + # Phases + nphases = length(f_conns) - # TODO: Status - math_obj["status"] = get(ravens_obj, "Equipment.inService", "true") - math_obj["status"] = status = math_obj["status"] == "true" ? 1 : 0 + # Connectivity Nodes + f_node = _extract_name(terminals[1]["Terminal.ConnectivityNode"]) + t_node = _extract_name(terminals[2]["Terminal.ConnectivityNode"]) + math_obj["f_bus"] = data_math["bus_lookup"][f_node] + math_obj["t_bus"] = data_math["bus_lookup"][t_node] - # State - sw_state = get(ravens_obj, "Switch.open", "false") - sw_state = sw_state == "false" ? CLOSED : OPEN - math_obj["state"] = Int(sw_state) + # TODO: Status + math_obj["status"] = get(ravens_obj, "Equipment.inService", "true") + math_obj["status"] = status = math_obj["status"] == "true" ? 1 : 0 - # TODO: Dispatchable - math_obj["dispatchable"] = Int(get(ravens_obj, "dispatchable", YES)) + # State + sw_state = get(ravens_obj, "Switch.open", "false") + sw_state = sw_state == "false" ? CLOSED : OPEN + math_obj["state"] = Int(sw_state) - # TODO: OPF bounds - Do we really need all of these values? - for (f_key, t_key) in [("Switch.ratedCurrent", "current_rating"), ("cm_ub_b", "c_rating_b"), ("cm_ub_c", "c_rating_c"), - ("sm_ub", "thermal_rating"), ("sm_ub_b", "rate_b"), ("sm_ub_c", "rate_c")] - math_obj[t_key] = haskey(ravens_obj, f_key) ? fill(ravens_obj[f_key], nphases) : fill(Inf, nphases) - end + # TODO: Dispatchable + math_obj["dispatchable"] = Int(get(ravens_obj, "dispatchable", YES)) - # Map index - map_to = "switch.$(math_obj["index"])" + # TODO: OPF bounds - Do we really need all of these values? + for (f_key, t_key) in [("Switch.ratedCurrent", "current_rating"), ("cm_ub_b", "c_rating_b"), ("cm_ub_c", "c_rating_c"), + ("sm_ub", "thermal_rating"), ("sm_ub_b", "rate_b"), ("sm_ub_c", "rate_c")] + math_obj[t_key] = haskey(ravens_obj, f_key) ? fill(ravens_obj[f_key], nphases) : fill(Inf, nphases) + end - # Push Mapping - data_math["switch"]["$(math_obj["index"])"] = math_obj + # Map index + map_to = "switch.$(math_obj["index"])" - push!(data_math["map"], Dict{String,Any}( - "from" => name, - "to" => map_to, - "unmap_function" => "_map_math2ravens_switch!", - )) + # Push Mapping + data_math["switch"]["$(math_obj["index"])"] = math_obj - end + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => map_to, + "unmap_function" => "_map_math2ravens_switch!", + )) end - end "converts ravens generic shunt components into mathematical shunt components" function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) + energy_connections = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] - if haskey(data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"], "RegulatingCondEq") - regulating_cond_eq = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"]["RegulatingCondEq"] + if haskey(energy_connections, "RegulatingCondEq") + regulating_cond_eq = energy_connections["RegulatingCondEq"] power_scale_factor = data_math["settings"]["power_scale_factor"] voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] @@ -1138,8 +1132,6 @@ function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data "to" => "shunt.$(math_obj["index"])", "unmap_function" => "_map_math2ravens_shunt!", )) - end - end end From 86fa5be51407b76b950c543c9a9ed6ddf4a0d973 Mon Sep 17 00:00:00 2001 From: jjospina Date: Fri, 8 Nov 2024 14:37:56 -0700 Subject: [PATCH 26/99] ADD: unit tests for ravens parser. --- test/data/ravens/ravens_case3_withcap.json | 580 ++++++++++++ test/data/ravens/ravens_case3_withgens.json | 606 +++++++++++++ .../ravens/ravens_case3_withpvandstorage.json | 621 +++++++++++++ test/data/ravens/ravens_case3_withsubxf.json | 836 ++++++++++++++++++ test/data/ravens/ravens_test_switch_1w.json | 554 ++++++++++++ test/data/ravens/ravens_test_switch_3w.json | 785 ++++++++++++++++ test/opf_ravens.jl | 70 ++ test/runtests.jl | 2 + test/test_cases.jl | 8 + 9 files changed, 4062 insertions(+) create mode 100644 test/data/ravens/ravens_case3_withcap.json create mode 100644 test/data/ravens/ravens_case3_withgens.json create mode 100644 test/data/ravens/ravens_case3_withpvandstorage.json create mode 100644 test/data/ravens/ravens_case3_withsubxf.json create mode 100644 test/data/ravens/ravens_test_switch_1w.json create mode 100644 test/data/ravens/ravens_test_switch_3w.json create mode 100644 test/opf_ravens.jl diff --git a/test/data/ravens/ravens_case3_withcap.json b/test/data/ravens/ravens_case3_withcap.json new file mode 100644 index 000000000..a5afd36fc --- /dev/null +++ b/test/data/ravens/ravens_case3_withcap.json @@ -0,0 +1,580 @@ +{ + "PerLengthLineParameter": { + "PerLengthImpedance": { + "PerLengthPhaseImpedance": { + "4/0quad": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "b9ede34e-a50f-4afc-b83e-f3cd0578a600", + "IdentifiedObject.name": "4/0quad", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + } + ] + }, + "556mcm": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "c71a840c-a77b-4be6-b20e-8a372d0af874", + "IdentifiedObject.name": "556mcm", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + } + ] + } + } + } + }, + "PowerSystemResource": { + "Equipment": { + "ConductingEquipment": { + "Conductor": { + "ACLineSegment": { + "quad": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "f501b03c-aee6-4524-a253-3adc0a016c92", + "IdentifiedObject.name": "quad", + "Conductor.length": 1.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "9cce4dc1-447a-435f-ae0f-8b31058209b7", + "IdentifiedObject.name": "quad_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "349837bd-1743-4fdd-9305-129146cf7048", + "IdentifiedObject.name": "quad_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "31349b5e-6351-4ccb-8462-1f2717f03565", + "IdentifiedObject.name": "quad_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ], + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "645b55d4-e061-4163-b1ba-d0d74395a42c", + "IdentifiedObject.name": "quad_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "208c5aea-a854-4124-b365-c69677b1a5b2", + "IdentifiedObject.name": "quad_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ] + }, + "ohline": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "ea549d70-b21a-4132-a5d2-ef9996f6c0ea", + "IdentifiedObject.name": "ohline", + "Conductor.length": 1.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "b3094d11-632b-489b-a645-fa006dde1367", + "IdentifiedObject.name": "ohline_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "5191b2b6-09ee-44d5-b3a8-17de5b345216", + "IdentifiedObject.name": "ohline_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "d8523544-a3e0-466a-94ab-b68dbdf4f36a", + "IdentifiedObject.name": "ohline_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ], + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "d15f3652-af59-4f84-a4d4-b218c4ad6b2a", + "IdentifiedObject.name": "ohline_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "c72fbd81-3362-436d-be2b-ebff11174263", + "IdentifiedObject.name": "ohline_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + } + ] + } + } + }, + "EnergyConnection": { + "EnergyConsumer": { + "l1": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "8bef6e0f-813f-4cd5-9613-4fe60e159e7b", + "IdentifiedObject.name": "l1", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "09eb27e3-654c-4823-bdce-51fc6b3dbffe", + "IdentifiedObject.name": "l1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.A", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "317c70ec-5985-482f-b515-bf94de7eef00", + "IdentifiedObject.name": "l1_A", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.A" + } + ] + }, + "l2": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "92d0f990-dc53-4496-86a7-25244905f08e", + "IdentifiedObject.name": "l2", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "d4cb98f1-86d4-4860-aafd-563dd86e7a52", + "IdentifiedObject.name": "l2_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.B", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "d20c16f2-db2b-459a-81f1-535a1559c762", + "IdentifiedObject.name": "l2_B", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.B" + } + ] + }, + "l3": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "6bc98558-9400-4d89-a6fe-54ccaee27b38", + "IdentifiedObject.name": "l3", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "701902a4-7dab-40eb-b1f6-f5008e5fcb9c", + "IdentifiedObject.name": "l3_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.C", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "cdacb568-8574-4002-9635-64a893e4a2b0", + "IdentifiedObject.name": "l3_C", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.C" + } + ] + } + }, + "EnergySource": { + "source": { + "Ravens.CimObjectType": "EnergySource", + "IdentifiedObject.mRID": "c0d17284-08ca-46f4-899a-5a87055acd9a", + "IdentifiedObject.name": "source", + "EnergySource.nominalVoltage": 400.0, + "EnergySource.voltageMagnitude": 398.36, + "EnergySource.voltageAngle": 0.0, + "EnergySource.r": 3.880570000581328e-08, + "EnergySource.x": 1.5522280002325312e-07, + "EnergySource.r0": 5.069596039676399e-08, + "EnergySource.x0": 1.5208788119029196e-07, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "2709c1dc-e81b-41c1-9cdb-262c3df42a9e", + "IdentifiedObject.name": "source_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + } + ] + } + }, + "RegulatingCondEq": { + "ShuntCompensator": { + "c1": { + "Ravens.CimObjectType": "LinearShuntCompensator", + "IdentifiedObject.mRID": "41f54a4b-8980-4117-9aaf-985c316768ea", + "IdentifiedObject.name": "c1", + "ShuntCompensator.nomU": 400.0, + "LinearShuntCompensator.bPerSection": 0.12499999999999997, + "LinearShuntCompensator.gPerSection": 0.0, + "ShuntCompensator.phaseConnection": "ShuntConnectionKind.Y", + "LinearShuntCompensator.b0PerSection": 0.12499999999999997, + "LinearShuntCompensator.g0PerSection": 0.0, + "LinearShuntCompensator.normalSections": 1, + "LinearShuntCompensator.maximumSections": 1, + "Equipment.inService": "true", + "LinearShuntCompensator.aVRDelay": 0.0, + "ShuntCompensator.sections": 1, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "6095aca4-7c9c-4d4e-801c-469a47c6b595", + "IdentifiedObject.name": "c1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ] + } + } + } + } + } + } + }, + "OperationalLimitSet": { + "OpLimI_38.97114317029974_51.96152422706632": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "44764d73-372f-4d55-8e84-5ab8ffc703da", + "IdentifiedObject.name": "OpLimI_38.97114317029974_51.96152422706632", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "7f1251a9-83e6-42e1-9447-7af24510b432", + "IdentifiedObject.name": "OpLimI_38.97114317029974_51.96152422706632_Norm", + "CurrentLimit.value": 38.97114317029974, + "CurrentLimit.normalValue": 38.97114317029974, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" + }, + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "26784e14-226e-4420-84c3-e11c926df475", + "IdentifiedObject.name": "OpLimI_38.97114317029974_51.96152422706632_Emerg", + "CurrentLimit.value": 51.96152422706632, + "CurrentLimit.normalValue": 38.97114317029974, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" + } + ] + }, + "OpLimI_400.0_600.0": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "f59e344b-c2c5-4465-8584-11feeefaec83", + "IdentifiedObject.name": "OpLimI_400.0_600.0", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "e2876119-1166-41b7-82b2-55c3af3724ff", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", + "CurrentLimit.value": 600.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" + }, + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "318af2aa-38b8-4073-915d-cba9e3c02b3c", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", + "CurrentLimit.value": 400.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" + } + ] + }, + "OpLimV_380.0-420.00000000000006": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "ebe9634e-a35b-4086-be5a-3784f598c20a", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "d0fb9602-f090-467f-bdcc-594f7ea61c64", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAhigh", + "VoltageLimit.value": 420.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "6f5f1408-a98b-47cc-afa7-117e80e51771", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAlow", + "VoltageLimit.value": 380.0, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + } + ] + } + }, + "Location": { + "primary_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "37309db4-0940-411e-857a-93153c0359a2", + "IdentifiedObject.name": "primary_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + }, + "loadbus_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "f570a5d2-6a61-4776-959e-f4a8f19b1706", + "IdentifiedObject.name": "loadbus_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + }, + "sourcebus_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "758373e1-f065-4503-af46-6f89b548922c", + "IdentifiedObject.name": "sourcebus_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + } + }, + "EnergyConnectionProfile": { + "Ravens.CimObjectType": "EnergyConnectionProfile", + "IdentifiedObject.mRID": "d4723d5b-add9-49b0-88a1-d8e47ebbde66", + "IdentifiedObject.name": "Load::::::defaultload", + "EnergyConnectionProfile.dssSpectrum": "defaultload" + }, + "Versions": { + "IEC61970CIMVersion": { + "Ravens.CimObjectType": "IEC61970CIMVersion", + "IEC61970CIMVersion.version": "IEC61970CIM100", + "IEC61970CIMVersion.date": "2019-04-01" + } + }, + "OperationalLimitType": { + "absoluteValueType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "9c0ee368-c6f1-4ace-afeb-4e760aecba46", + "IdentifiedObject.name": "absoluteValueType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "highType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "05706366-f802-478e-91d6-f5aafaa14e04", + "IdentifiedObject.name": "highType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "absoluteValueType_86400.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "34e53b7e-0543-4ac6-8d1d-fa971d98b53f", + "IdentifiedObject.name": "absoluteValueType_86400.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 86400.0 + }, + "lowType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "473b0218-b900-4e00-9e93-8e8adc1767d2", + "IdentifiedObject.name": "lowType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low", + "OperationalLimitType.acceptableDuration": 5000000000.0 + } + }, + "ConnectivityNode": { + "primary": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "88e0ace1-46b4-491a-a521-bac23f64b8c0", + "IdentifiedObject.name": "primary" + }, + "sourcebus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "b4d268bc-7862-4be1-a540-71dcf3feeb4e", + "IdentifiedObject.name": "sourcebus" + }, + "loadbus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "a8274412-8b0f-4bb3-a8d8-1db65e3a3685", + "IdentifiedObject.name": "loadbus", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" + } + }, + "BaseVoltage": { + "BaseV_0.4": { + "Ravens.CimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "5c7d64a6-5188-43a6-bf1a-1740452091ef", + "IdentifiedObject.name": "BaseV_0.4", + "BaseVoltage.nominalVoltage": 400.0 + } + }, + "LoadResponseCharacteristic": { + "Constant kVA": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "0d3ba428-f9a0-40ad-953a-52a09911bc60", + "IdentifiedObject.name": "Constant kVA", + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantPower": 100 + } + } +} diff --git a/test/data/ravens/ravens_case3_withgens.json b/test/data/ravens/ravens_case3_withgens.json new file mode 100644 index 000000000..ecc5fac68 --- /dev/null +++ b/test/data/ravens/ravens_case3_withgens.json @@ -0,0 +1,606 @@ +{ + "PerLengthLineParameter": { + "PerLengthImpedance": { + "PerLengthPhaseImpedance": { + "4/0quad": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "88bc7e59-e9ce-4600-a949-3e2cecbc2fda", + "IdentifiedObject.name": "4/0quad", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + } + ] + }, + "556mcm": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "d6879f7a-124f-4e82-987a-46f5ba3e2f9d", + "IdentifiedObject.name": "556mcm", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + } + ] + } + } + } + }, + "PowerSystemResource": { + "Equipment": { + "ConductingEquipment": { + "EnergyConnection": { + "RegulatingCondEq": { + "RotatingMachine": { + "gen2": { + "Ravens.CimObjectType": "SynchronousMachine", + "IdentifiedObject.mRID": "c657d8a1-32c2-402f-8403-9b06c112318a", + "IdentifiedObject.name": "gen2", + "RotatingMachine.p": 1000.0, + "RotatingMachine.q": 484.3221048378525, + "RotatingMachine.ratedS": 1200.0, + "RotatingMachine.ratedU": 461.88021535170066, + "Equipment.inService": "true", + "RotatingMachine.ratedPowerFactor": 0.9, + "GeneratingUnit.minOperatingP": 0.0, + "GeneratingUnit.maxOperatingP": 1080.0, + "SynchronousMachine.maxQ": 523.0678732248807, + "SynchronousMachine.minQ": -523.0678732248807, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "012eb2d2-f4d8-4cc9-825f-b634c66e5d84", + "IdentifiedObject.name": "gen2_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + } + ] + }, + "gen1": { + "Ravens.CimObjectType": "SynchronousMachine", + "IdentifiedObject.mRID": "3f2267a8-4f0c-4ac5-9415-8568d7d414b2", + "IdentifiedObject.name": "gen1", + "RotatingMachine.p": 2000.0, + "RotatingMachine.q": 968.644209675705, + "RotatingMachine.ratedS": 2400.0, + "RotatingMachine.ratedU": 461.88021535170066, + "Equipment.inService": "true", + "RotatingMachine.ratedPowerFactor": 0.9, + "GeneratingUnit.minOperatingP": 0.0, + "GeneratingUnit.maxOperatingP": 2160.0, + "SynchronousMachine.maxQ": 1046.1357464497614, + "SynchronousMachine.minQ": -1046.1357464497614, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "20cd756e-faae-47d9-a177-b605e6ae55fb", + "IdentifiedObject.name": "gen1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ] + } + } + }, + "EnergySource": { + "source": { + "Ravens.CimObjectType": "EnergySource", + "IdentifiedObject.mRID": "494c011a-7640-4ed7-a3d5-2cd1a55413c0", + "IdentifiedObject.name": "source", + "EnergySource.nominalVoltage": 400.0, + "EnergySource.voltageMagnitude": 398.36, + "EnergySource.voltageAngle": 0.0, + "EnergySource.r": 3.880570000581328e-08, + "EnergySource.x": 1.5522280002325312e-07, + "EnergySource.r0": 5.069596039676399e-08, + "EnergySource.x0": 1.5208788119029196e-07, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "327a6ba6-06c2-40ff-a0cc-550dd50d824d", + "IdentifiedObject.name": "source_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + } + ] + } + }, + "EnergyConsumer": { + "l2": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "f227af26-b8ae-47b3-97cc-4d1e5d6bbfd3", + "IdentifiedObject.name": "l2", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "9f8d612e-85f8-4757-9ff8-f9ae5947ddd8", + "IdentifiedObject.name": "l2_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.B", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "f3cd189c-bd31-4fd4-beed-8967142aa0ea", + "IdentifiedObject.name": "l2_B", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.B" + } + ] + }, + "l1": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "8bff0407-deee-4f99-92fa-1dee4047621e", + "IdentifiedObject.name": "l1", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "4c93404d-1381-4fb2-b2db-36da5d6a0583", + "IdentifiedObject.name": "l1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.A", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "d4f8dc3a-8a95-4361-968a-1d841de4d7d1", + "IdentifiedObject.name": "l1_A", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.A" + } + ] + }, + "l3": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "f8e9430c-56a5-44c3-8b53-98464182dec3", + "IdentifiedObject.name": "l3", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "ec5de9d0-8f3a-409c-afaa-5dd15969842f", + "IdentifiedObject.name": "l3_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.C", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "cdb85d03-72cd-4c1a-aa27-ee985895d65c", + "IdentifiedObject.name": "l3_C", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.C" + } + ] + } + } + }, + "Conductor": { + "ACLineSegment": { + "ohline": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "357e3f68-a996-4ef9-8e29-5a9701da50f5", + "IdentifiedObject.name": "ohline", + "Conductor.length": 1.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "262a28c0-79c8-46f8-be2f-48baba94b09b", + "IdentifiedObject.name": "ohline_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "20c1e2b3-faab-4f16-9d28-1438cf5adc31", + "IdentifiedObject.name": "ohline_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + } + ], + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "43a9f788-638f-48c5-9211-437795fad9da", + "IdentifiedObject.name": "ohline_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "939db8dd-1631-44e8-aa9d-cb391f06136d", + "IdentifiedObject.name": "ohline_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "8a764636-52d0-470f-abcd-9cee75f114de", + "IdentifiedObject.name": "ohline_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ] + }, + "quad": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "b0c876f2-8724-4b1d-9bb8-16ad6dc08866", + "IdentifiedObject.name": "quad", + "Conductor.length": 1.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "fba92277-7b25-42e3-8782-10e01ebf3ccf", + "IdentifiedObject.name": "quad_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "7a7bd627-5599-4139-bd71-a659a313fafc", + "IdentifiedObject.name": "quad_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "06ccbe19-290d-4808-8edb-40afc7e7c41e", + "IdentifiedObject.name": "quad_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "79df9209-3379-4ce7-bd5b-2f927daccd8a", + "IdentifiedObject.name": "quad_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "27dfc4e3-829a-4c4a-abb2-dab081e599c7", + "IdentifiedObject.name": "quad_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ] + } + } + } + } + } + }, + "EnergyConnectionProfile": { + "Ravens.CimObjectType": "EnergyConnectionProfile", + "IdentifiedObject.mRID": "b1c858fa-9961-4915-ac2b-6c40546f4e55", + "IdentifiedObject.name": "Load::::::defaultload", + "EnergyConnectionProfile.dssSpectrum": "defaultload" + }, + "OperationalLimitSet": { + "OpLimV_360.00000000000006-440.00000000000006": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "1fd3801e-4bc9-4995-a833-b8a934a51856", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "e2cbc64e-5a29-4df5-b214-f9ed9aa5cb5d", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAlow", + "VoltageLimit.value": 360.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "27d3baf8-3d5e-4465-9e84-3e52708211f1", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAhigh", + "VoltageLimit.value": 440.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + } + ] + }, + "OpLimV_380.0-420.00000000000006": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "35e30ea0-641e-43b7-a1e4-0e15e42334e1", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "cce047bb-3dc5-4f08-85ae-401c93562f34", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAhigh", + "VoltageLimit.value": 420.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "88c7ce0d-859b-4dda-bb25-64d33ba36831", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAlow", + "VoltageLimit.value": 380.0, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + } + ] + }, + "OpLimI_400.0_600.0": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "47ba5a2e-b0e0-469d-b456-b74d90a89598", + "IdentifiedObject.name": "OpLimI_400.0_600.0", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "ce6d7dcd-e426-44cb-ab33-9e8a6de1b60f", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", + "CurrentLimit.value": 600.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" + }, + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "a301065e-a50e-4dd7-856b-c7035e9ea52f", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", + "CurrentLimit.value": 400.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" + } + ] + } + }, + "Location": { + "primary_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "db2f0d86-da66-46ac-adc1-6eec717cf555", + "IdentifiedObject.name": "primary_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + }, + "loadbus_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "76056310-0c84-49e6-9d92-c0a3cce574e4", + "IdentifiedObject.name": "loadbus_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + }, + "sourcebus_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "4c73c3dd-7250-4f6a-af69-d203960b0a34", + "IdentifiedObject.name": "sourcebus_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + } + }, + "Versions": { + "IEC61970CIMVersion": { + "Ravens.CimObjectType": "IEC61970CIMVersion", + "IEC61970CIMVersion.version": "IEC61970CIM100", + "IEC61970CIMVersion.date": "2019-04-01" + } + }, + "ConnectivityNode": { + "loadbus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "4ac8da05-a223-4bf6-b372-12c9479c495a", + "IdentifiedObject.name": "loadbus", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_360.00000000000006-440.00000000000006'" + }, + "primary": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "3e877b8a-ef33-4e18-8c80-1b05050bfc40", + "IdentifiedObject.name": "primary", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_360.00000000000006-440.00000000000006'" + }, + "sourcebus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "d192d550-1fc0-489f-8e47-72209fa989e7", + "IdentifiedObject.name": "sourcebus" + } + }, + "OperationalLimitType": { + "absoluteValueType_86400.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "d60da1eb-6a60-41ba-99df-7313cad312fa", + "IdentifiedObject.name": "absoluteValueType_86400.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 86400.0 + }, + "highType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "a1a82ad0-e426-4ecb-816a-5a58f034756b", + "IdentifiedObject.name": "highType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "lowType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "1eaf0044-6272-4146-bf43-5c5310023469", + "IdentifiedObject.name": "lowType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "absoluteValueType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "1a39544c-2df7-46a9-a6c0-cfb28ab6eaab", + "IdentifiedObject.name": "absoluteValueType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 5000000000.0 + } + }, + "LoadResponseCharacteristic": { + "Constant kVA": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "777f5c7c-dea1-4a88-8db0-e5bd71a2fd4b", + "IdentifiedObject.name": "Constant kVA", + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantPower": 100 + } + }, + "BaseVoltage": { + "BaseV_0.4": { + "Ravens.CimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "93c27318-44cd-41b7-a873-f9001d1b831f", + "IdentifiedObject.name": "BaseV_0.4", + "BaseVoltage.nominalVoltage": 400.0 + } + } +} \ No newline at end of file diff --git a/test/data/ravens/ravens_case3_withpvandstorage.json b/test/data/ravens/ravens_case3_withpvandstorage.json new file mode 100644 index 000000000..73b959d88 --- /dev/null +++ b/test/data/ravens/ravens_case3_withpvandstorage.json @@ -0,0 +1,621 @@ +{ + "OperationalLimitSet": { + "OpLimI_400.0_600.0": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "1e3d77af-8a23-466a-bdd9-39cee9f9fe92", + "IdentifiedObject.name": "OpLimI_400.0_600.0", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "fc496404-0ea3-49ad-a418-fb8b10aa2724", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", + "CurrentLimit.value": 600.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" + }, + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "33f3b868-cb9b-4223-b83c-e050cd47a7d0", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", + "CurrentLimit.value": 400.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" + } + ] + }, + "OpLimV_360.00000000000006-440.00000000000006": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "514c489d-6957-4739-bb9d-ff5da50e8f4e", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "513ecee1-8a86-4ced-b436-e4def25953cc", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAhigh", + "VoltageLimit.value": 440.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "e22b44ed-3b12-4bf9-8be3-a591a3cf732b", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAlow", + "VoltageLimit.value": 360.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + } + ] + }, + "OpLimV_380.0-420.00000000000006": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "5c5e7910-bdea-408b-9cba-c96967e39939", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "5f98e299-22cb-48a5-acd0-ba5404111eed", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAlow", + "VoltageLimit.value": 380.0, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "43fb3ee9-3b9a-4a7b-ace5-5ddcac6d59d5", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAhigh", + "VoltageLimit.value": 420.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + } + ] + } + }, + "PowerSystemResource": { + "Equipment": { + "ConductingEquipment": { + "Conductor": { + "ACLineSegment": { + "ohline": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "e9c718d0-d75c-41cf-b31e-5d1467780362", + "IdentifiedObject.name": "ohline", + "Conductor.length": 1.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "350fed0a-7395-4736-aa12-ac2d7e87ac92", + "IdentifiedObject.name": "ohline_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "3b5406ff-4fb5-4a30-8e2c-4f09db60a544", + "IdentifiedObject.name": "ohline_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "8d10892c-1893-4a48-8f5b-615fcb4c0d55", + "IdentifiedObject.name": "ohline_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ], + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "37415ad4-1071-481c-b741-06e6b8ca05d4", + "IdentifiedObject.name": "ohline_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "3bd4d2fc-d02b-4238-9630-83fe0b294662", + "IdentifiedObject.name": "ohline_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + } + ] + }, + "quad": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "edba552d-daee-40f3-9488-336f9c9231dc", + "IdentifiedObject.name": "quad", + "Conductor.length": 1.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "c087897c-8221-477a-b33b-59ed2ff423c7", + "IdentifiedObject.name": "quad_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "57c71971-b70b-49a2-868b-a64aceb3b031", + "IdentifiedObject.name": "quad_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "732aea91-11c1-4dcb-a9ed-45de010dde2f", + "IdentifiedObject.name": "quad_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ], + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "82cce1dc-5fc1-4a98-9f53-2b347ed1d3b5", + "IdentifiedObject.name": "quad_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "f0e02033-fa13-4ac4-b6cf-0e0444d72d18", + "IdentifiedObject.name": "quad_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ] + } + } + }, + "EnergyConnection": { + "EnergyConsumer": { + "l2": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "09b604b2-00d7-4a4e-994d-2f189ee9642b", + "IdentifiedObject.name": "l2", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "9b397420-cdcf-4127-85ae-73559a000953", + "IdentifiedObject.name": "l2_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.B", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "03858c77-6453-407c-8119-da6a76508b59", + "IdentifiedObject.name": "l2_B", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.B" + } + ] + }, + "l3": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "f9667c10-e77a-4409-8099-072bfdce24e0", + "IdentifiedObject.name": "l3", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "18771bf2-42eb-4758-a101-0a92cb9508e5", + "IdentifiedObject.name": "l3_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.C", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "dbfde1f4-2422-4e65-933b-7b9d43a22cc7", + "IdentifiedObject.name": "l3_C", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.C" + } + ] + }, + "l1": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "089386b2-ecab-4d6f-ab32-12c2c5527ee5", + "IdentifiedObject.name": "l1", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "8db69196-5be7-4038-a656-c345313d6dcc", + "IdentifiedObject.name": "l1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.A", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "445afb26-9fca-40ff-9161-1fae6c0c1619", + "IdentifiedObject.name": "l1_A", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.A" + } + ] + } + }, + "EnergySource": { + "source": { + "Ravens.CimObjectType": "EnergySource", + "IdentifiedObject.mRID": "5181f211-4f84-4220-905d-ce5a2136c86b", + "IdentifiedObject.name": "source", + "EnergySource.nominalVoltage": 400.0, + "EnergySource.voltageMagnitude": 398.36, + "EnergySource.voltageAngle": 0.0, + "EnergySource.r": 3.880570000581328e-08, + "EnergySource.x": 1.5522280002325312e-07, + "EnergySource.r0": 5.069596039676399e-08, + "EnergySource.x0": 1.5208788119029196e-07, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "f67ae006-bbc4-408b-90bc-ac62d33ce9d5", + "IdentifiedObject.name": "source_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + } + ] + } + }, + "RegulatingCondEq": { + "PowerElectronicsConnection": { + "pv1": { + "Ravens.CimObjectType": "PowerElectronicsConnection", + "IdentifiedObject.mRID": "997cec18-9472-4c89-8fb7-6e7d8ca4d377", + "IdentifiedObject.name": "pv1", + "PowerElectronicsConnection.maxIFault": 1.1111111111111112, + "PowerElectronicsConnection.p": 9999.997590992734, + "PowerElectronicsConnection.q": -0.0016831415801767946, + "PowerElectronicsConnection.ratedS": 10000.0, + "PowerElectronicsConnection.ratedU": 400.0, + "PowerElectronicsConnection.maxQ": 10000.0, + "PowerElectronicsConnection.minQ": -10000.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "a1d1a18a-5c36-4804-8fc0-13f756823d19", + "IdentifiedObject.name": "pv1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "PowerElectronicsConnection.PowerElectronicsUnit": { + "Ravens.CimObjectType": "PhotoVoltaicUnit", + "IdentifiedObject.mRID": "24872726-129e-491f-83cc-74135a8432b4", + "IdentifiedObject.name": "pv1_PVPanels", + "PowerElectronicsUnit.minP": 2000.0, + "PowerElectronicsUnit.maxP": 500000.0 + } + }, + "s1": { + "Ravens.CimObjectType": "PowerElectronicsConnection", + "IdentifiedObject.mRID": "cb0d7d2e-e799-4aaf-bb04-5daf2bfb9a00", + "IdentifiedObject.name": "s1", + "PowerElectronicsConnection.maxIFault": 1.1111111111111112, + "PowerElectronicsConnection.p": -0.0, + "PowerElectronicsConnection.q": -0.0, + "PowerElectronicsConnection.ratedS": 60000.0, + "PowerElectronicsConnection.ratedU": 400.0, + "PowerElectronicsConnection.maxQ": 25000.0, + "PowerElectronicsConnection.minQ": -25000.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "6f75e791-02dc-496f-8117-106bef0e0700", + "IdentifiedObject.name": "s1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "PowerElectronicsConnection.PowerElectronicsUnit": { + "Ravens.CimObjectType": "BatteryUnit", + "IdentifiedObject.mRID": "09908453-5eb9-4927-817a-0dd0a84e0f95", + "IdentifiedObject.name": "s1_Cells", + "PowerElectronicsUnit.minP": -60000.0, + "PowerElectronicsUnit.maxP": 60000.0, + "BatteryUnit.storedE": 6000.0, + "BatteryUnit.ratedE": 60000.0, + "InefficientBatteryUnit.reserveEnery": 20.0, + "InefficientBatteryUnit.limitEnergy": 100.0, + "InefficientBatteryUnit.efficiencyDischarge": 98.0, + "InefficientBatteryUnit.efficiencyCharge": 95.0 + } + } + } + } + } + } + } + }, + "Versions": { + "IEC61970CIMVersion": { + "Ravens.CimObjectType": "IEC61970CIMVersion", + "IEC61970CIMVersion.version": "IEC61970CIM100", + "IEC61970CIMVersion.date": "2019-04-01" + } + }, + "PerLengthLineParameter": { + "PerLengthImpedance": { + "PerLengthPhaseImpedance": { + "4/0quad": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "a2ccef36-6f66-45e7-8db4-fdd9766d8c8d", + "IdentifiedObject.name": "4/0quad", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + } + ] + }, + "556mcm": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "8a93bb2a-3217-48d0-b19b-ae8354399310", + "IdentifiedObject.name": "556mcm", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + } + ] + } + } + } + }, + "Location": { + "primary_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "cd4c22b1-390a-48b4-ba9b-c5b0a6a13e79", + "IdentifiedObject.name": "primary_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + }, + "loadbus_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "1f628e25-f631-49b3-b43c-b8618559661c", + "IdentifiedObject.name": "loadbus_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + }, + "sourcebus_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "17d93d69-c091-40d2-8292-e9800154e3f9", + "IdentifiedObject.name": "sourcebus_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + } + }, + "EnergyConnectionProfile": { + "Ravens.CimObjectType": "EnergyConnectionProfile", + "IdentifiedObject.mRID": "a7098736-cc57-4a69-b250-3101ae6dd9f5", + "IdentifiedObject.name": "Load::::::defaultload", + "EnergyConnectionProfile.dssSpectrum": "defaultload" + }, + "BaseVoltage": { + "BaseV_0.4": { + "Ravens.CimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "270f81bf-ab58-46e9-863a-08744d924604", + "IdentifiedObject.name": "BaseV_0.4", + "BaseVoltage.nominalVoltage": 400.0 + } + }, + "OperationalLimitType": { + "highType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "48f1510a-52d8-4c04-a0e7-59a8876eafa2", + "IdentifiedObject.name": "highType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "absoluteValueType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "faf34841-2190-4133-bf8d-cf31f35a80a0", + "IdentifiedObject.name": "absoluteValueType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "absoluteValueType_86400.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "14a68643-2417-4e41-b809-940b9b1856d1", + "IdentifiedObject.name": "absoluteValueType_86400.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 86400.0 + }, + "lowType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "33ce2fce-d1cb-4df3-924f-0399aa127edd", + "IdentifiedObject.name": "lowType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low", + "OperationalLimitType.acceptableDuration": 5000000000.0 + } + }, + "ConnectivityNode": { + "loadbus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "0f25fa64-77ce-4721-ad73-ecad9127fa2e", + "IdentifiedObject.name": "loadbus", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" + }, + "sourcebus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "e4ff4b6e-79fe-40b2-af40-e0226cf5f4a4", + "IdentifiedObject.name": "sourcebus" + }, + "primary": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "cc97ba78-4f37-4d8f-8044-55f023a74a28", + "IdentifiedObject.name": "primary" + } + }, + "LoadResponseCharacteristic": { + "Constant kVA": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "141f856d-53fd-4d9b-b71b-464b1db94318", + "IdentifiedObject.name": "Constant kVA", + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantPower": 100 + } + } +} diff --git a/test/data/ravens/ravens_case3_withsubxf.json b/test/data/ravens/ravens_case3_withsubxf.json new file mode 100644 index 000000000..7f2ec6db4 --- /dev/null +++ b/test/data/ravens/ravens_case3_withsubxf.json @@ -0,0 +1,836 @@ +{ + "OperationalLimitSet": { + "OpLimI_400.0_600.0": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "1e3d77af-8a23-466a-bdd9-39cee9f9fe92", + "IdentifiedObject.name": "OpLimI_400.0_600.0", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "fc496404-0ea3-49ad-a418-fb8b10aa2724", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", + "CurrentLimit.value": 600.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" + }, + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "33f3b868-cb9b-4223-b83c-e050cd47a7d0", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", + "CurrentLimit.value": 400.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" + } + ] + }, + "OpLimV_360.00000000000006-440.00000000000006": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "514c489d-6957-4739-bb9d-ff5da50e8f4e", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "513ecee1-8a86-4ced-b436-e4def25953cc", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAhigh", + "VoltageLimit.value": 440.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "e22b44ed-3b12-4bf9-8be3-a591a3cf732b", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAlow", + "VoltageLimit.value": 360.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + } + ] + }, + "OpLimV_380.0-420.00000000000006": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "5c5e7910-bdea-408b-9cba-c96967e39939", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "5f98e299-22cb-48a5-acd0-ba5404111eed", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAlow", + "VoltageLimit.value": 380.0, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "43fb3ee9-3b9a-4a7b-ace5-5ddcac6d59d5", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAhigh", + "VoltageLimit.value": 420.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + } + ] + }, + "OpLimV_7.2000": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "_665DF148-4555-4F76-BFD4-71BA3D55F876", + "IdentifiedObject.name": "OpLimV_7.2000", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "_69C733F4-2D96-47C2-B6AE-D7593EDAD548", + "IdentifiedObject.name": "OpLimV_7.2000_RangeAHi", + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'case3_balanced_RangeAHiType'", + "VoltageLimit.value": 7560, + "VoltageLimit.normalValue": 7200.0 + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "_8133C550-DC0B-482E-ABCA-DA0038702079", + "IdentifiedObject.name": "OpLimV_7.2000_RangeALo", + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'case3_balanced_RangeALoType'", + "VoltageLimit.value": 6840, + "VoltageLimit.normalValue": 7200.0 + } + ] + }, + "OpLimI_1323.1_1804.2": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "_433D75D6-4693-4413-9564-12E93A04ECC3", + "IdentifiedObject.name": "OpLimI_1323.1_1804.2", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "_4180E9E9-AB79-4F18-8076-16E6FA4BB993", + "IdentifiedObject.name": "OpLimI_1323.1_1804.2_Norm", + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'case3_balanced_NormAmpsType'", + "CurrentLimit.value": 1323.0944, + "CurrentLimit.normalValue": 1323.0944 + }, + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "_9102C72B-FAE2-4BB2-925E-36A755252B0A", + "IdentifiedObject.name": "OpLimI_1323.1_1804.2_Emerg", + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'case3_balanced_EmergencyAmpsType'", + "CurrentLimit.value": 1804.2196, + "CurrentLimit.normalValue": 1323.0944 + } + ] + } + }, + "PowerSystemResource": { + "Equipment": { + "ConductingEquipment": { + "Conductor": { + "ACLineSegment": { + "ohline": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "e9c718d0-d75c-41cf-b31e-5d1467780362", + "IdentifiedObject.name": "ohline", + "Conductor.length": 1.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "350fed0a-7395-4736-aa12-ac2d7e87ac92", + "IdentifiedObject.name": "ohline_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "3b5406ff-4fb5-4a30-8e2c-4f09db60a544", + "IdentifiedObject.name": "ohline_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "8d10892c-1893-4a48-8f5b-615fcb4c0d55", + "IdentifiedObject.name": "ohline_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ], + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "37415ad4-1071-481c-b741-06e6b8ca05d4", + "IdentifiedObject.name": "ohline_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'subxfbus'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "3bd4d2fc-d02b-4238-9630-83fe0b294662", + "IdentifiedObject.name": "ohline_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + } + ] + }, + "quad": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "edba552d-daee-40f3-9488-336f9c9231dc", + "IdentifiedObject.name": "quad", + "Conductor.length": 1.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "c087897c-8221-477a-b33b-59ed2ff423c7", + "IdentifiedObject.name": "quad_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "57c71971-b70b-49a2-868b-a64aceb3b031", + "IdentifiedObject.name": "quad_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "732aea91-11c1-4dcb-a9ed-45de010dde2f", + "IdentifiedObject.name": "quad_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ], + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "82cce1dc-5fc1-4a98-9f53-2b347ed1d3b5", + "IdentifiedObject.name": "quad_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "f0e02033-fa13-4ac4-b6cf-0e0444d72d18", + "IdentifiedObject.name": "quad_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ] + } + } + }, + "EnergyConnection": { + "EnergyConsumer": { + "l2": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "09b604b2-00d7-4a4e-994d-2f189ee9642b", + "IdentifiedObject.name": "l2", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "9b397420-cdcf-4127-85ae-73559a000953", + "IdentifiedObject.name": "l2_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.B", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "03858c77-6453-407c-8119-da6a76508b59", + "IdentifiedObject.name": "l2_B", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.B" + } + ] + }, + "l3": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "f9667c10-e77a-4409-8099-072bfdce24e0", + "IdentifiedObject.name": "l3", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "18771bf2-42eb-4758-a101-0a92cb9508e5", + "IdentifiedObject.name": "l3_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.C", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "dbfde1f4-2422-4e65-933b-7b9d43a22cc7", + "IdentifiedObject.name": "l3_C", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.C" + } + ] + }, + "l1": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "089386b2-ecab-4d6f-ab32-12c2c5527ee5", + "IdentifiedObject.name": "l1", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "8db69196-5be7-4038-a656-c345313d6dcc", + "IdentifiedObject.name": "l1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.A", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "445afb26-9fca-40ff-9161-1fae6c0c1619", + "IdentifiedObject.name": "l1_A", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.A" + } + ] + } + }, + "EnergySource": { + "source": { + "Ravens.CimObjectType": "EnergySource", + "IdentifiedObject.mRID": "5181f211-4f84-4220-905d-ce5a2136c86b", + "IdentifiedObject.name": "source", + "EnergySource.nominalVoltage": 7200, + "EnergySource.voltageMagnitude": 7170.48, + "EnergySource.voltageAngle": 0.0, + "EnergySource.r": 1.2573047e-05, + "EnergySource.x": 5.0292187e-05, + "EnergySource.r0": 1.6425491e-05, + "EnergySource.x0": 4.9276474e-05, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_7.2000'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "f67ae006-bbc4-408b-90bc-ac62d33ce9d5", + "IdentifiedObject.name": "source_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + } + ] + } + }, + "RegulatingCondEq": { + "PowerElectronicsConnection": { + "pv1": { + "Ravens.CimObjectType": "PowerElectronicsConnection", + "IdentifiedObject.mRID": "997cec18-9472-4c89-8fb7-6e7d8ca4d377", + "IdentifiedObject.name": "pv1", + "PowerElectronicsConnection.maxIFault": 1.1111111111111112, + "PowerElectronicsConnection.p": 9999.997590992734, + "PowerElectronicsConnection.q": -0.0016831415801767946, + "PowerElectronicsConnection.ratedS": 10000.0, + "PowerElectronicsConnection.ratedU": 400.0, + "PowerElectronicsConnection.maxQ": 10000.0, + "PowerElectronicsConnection.minQ": -10000.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "a1d1a18a-5c36-4804-8fc0-13f756823d19", + "IdentifiedObject.name": "pv1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "PowerElectronicsConnection.PowerElectronicsUnit": { + "Ravens.CimObjectType": "PhotoVoltaicUnit", + "IdentifiedObject.mRID": "24872726-129e-491f-83cc-74135a8432b4", + "IdentifiedObject.name": "pv1_PVPanels", + "PowerElectronicsUnit.minP": 2000.0, + "PowerElectronicsUnit.maxP": 500000.0 + } + }, + "s1": { + "Ravens.CimObjectType": "PowerElectronicsConnection", + "IdentifiedObject.mRID": "cb0d7d2e-e799-4aaf-bb04-5daf2bfb9a00", + "IdentifiedObject.name": "s1", + "PowerElectronicsConnection.maxIFault": 1.1111111111111112, + "PowerElectronicsConnection.p": -0.0, + "PowerElectronicsConnection.q": -0.0, + "PowerElectronicsConnection.ratedS": 60000.0, + "PowerElectronicsConnection.ratedU": 400.0, + "PowerElectronicsConnection.maxQ": 25000.0, + "PowerElectronicsConnection.minQ": -25000.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "6f75e791-02dc-496f-8117-106bef0e0700", + "IdentifiedObject.name": "s1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "PowerElectronicsConnection.PowerElectronicsUnit": { + "Ravens.CimObjectType": "BatteryUnit", + "IdentifiedObject.mRID": "09908453-5eb9-4927-817a-0dd0a84e0f95", + "IdentifiedObject.name": "s1_Cells", + "PowerElectronicsUnit.minP": -60000.0, + "PowerElectronicsUnit.maxP": 60000.0, + "BatteryUnit.storedE": 6000.0, + "BatteryUnit.ratedE": 60000.0, + "InefficientBatteryUnit.reserveEnery": 20.0, + "InefficientBatteryUnit.limitEnergy": 100.0, + "InefficientBatteryUnit.efficiencyDischarge": 98.0, + "InefficientBatteryUnit.efficiencyCharge": 95.0 + } + } + } + } + }, + "PowerTransformer": { + "subxf": { + "Ravens.CimObjectType": "PowerTransformer", + "IdentifiedObject.mRID": "_B626B2F6-EC37-4A57-AF79-1DFC2973CC62", + "IdentifiedObject.name": "subxf", + "PowerTransformer.vectorGroup": "Yy", + "PowerSystemResource.Location": "Location::'subxf_Loc'", + "PowerTransformer.PowerTransformerEnd": [ + { + "Ravens.CimObjectType": "PowerTransformerEnd", + "IdentifiedObject.mRID": "_11C98A2D-4F3B-499F-9C93-997F5E6B6050", + "IdentifiedObject.name": "subxf_End_1", + "PowerTransformerEnd.ratedS": 15000000, + "PowerTransformerEnd.ratedU": 7200, + "PowerTransformerEnd.r": 1.728e-05, + "PowerTransformerEnd.connectionKind": "WindingConnection.Y", + "PowerTransformerEnd.phaseAngleClock": 0, + "TransformerEnd.endNumber": 1, + "TransformerEnd.grounded": "true", + "TransformerEnd.rground": 0, + "TransformerEnd.xground": 0, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_7.2000'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_16ECD631-0E7C-4CF8-BFBE-47B70741FBB5", + "IdentifiedObject.name": "subxf_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + } + ], + "TransformerEnd.CoreAdmittance": { + "Ravens.CimObjectType": "TransformerCoreAdmittance", + "IdentifiedObject.mRID": "_82EF01DC-693A-456D-80B7-88480B854940", + "IdentifiedObject.name": "subxf_Yc", + "TransformerCoreAdmittance.g": 0, + "TransformerCoreAdmittance.g0": 0, + "TransformerCoreAdmittance.b": 0, + "TransformerCoreAdmittance.b0": 0 + }, + "TransformerEnd.MeshImpedance": { + "Ravens.CimObjectType": "TransformerMeshImpedance", + "IdentifiedObject.mRID": "_C7842810-3C4F-495F-AD46-C3B29FF7727F", + "IdentifiedObject.name": "subxf_Zsc_1", + "TransformerMeshImpedance.r": 3.456e-05, + "TransformerMeshImpedance.r0": 3.456e-05, + "TransformerMeshImpedance.x": 0.0003456, + "TransformerMeshImpedance.x0": 0.0003456 + } + }, + { + "Ravens.CimObjectType": "PowerTransformerEnd", + "IdentifiedObject.mRID": "_A96426D2-9C2C-43D9-964F-A2F37B45368C", + "IdentifiedObject.name": "subxf_End_2", + "PowerTransformerEnd.ratedS": 15000000, + "PowerTransformerEnd.ratedU": 400, + "PowerTransformerEnd.r": 5.3333333e-08, + "PowerTransformerEnd.connectionKind": "WindingConnection.Y", + "PowerTransformerEnd.phaseAngleClock": 0, + "TransformerEnd.endNumber": 2, + "TransformerEnd.grounded": "true", + "TransformerEnd.rground": 0, + "TransformerEnd.xground": 0, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4000'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_7D0ABC1E-3EA3-4532-8122-DA10A6B933FB", + "IdentifiedObject.name": "subxf_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'subxfbus'" + } + ], + "TransformerEnd.MeshImpedance": { + "Ravens.CimObjectType": "TransformerMeshImpedance", + "IdentifiedObject.mRID": "_C7842810-3C4F-495F-AD46-C3B29FF7727F", + "IdentifiedObject.name": "subxf_Zsc_1", + "TransformerMeshImpedance.r": 3.456e-05, + "TransformerMeshImpedance.r0": 3.456e-05, + "TransformerMeshImpedance.x": 0.0003456, + "TransformerMeshImpedance.x0": 0.0003456 + } + } + ] + } + } + } + } + }, + "Versions": { + "IEC61970CIMVersion": { + "Ravens.CimObjectType": "IEC61970CIMVersion", + "IEC61970CIMVersion.version": "IEC61970CIM100", + "IEC61970CIMVersion.date": "2019-04-01" + } + }, + "PerLengthLineParameter": { + "PerLengthImpedance": { + "PerLengthPhaseImpedance": { + "4/0quad": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "a2ccef36-6f66-45e7-8db4-fdd9766d8c8d", + "IdentifiedObject.name": "4/0quad", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + } + ] + }, + "556mcm": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "8a93bb2a-3217-48d0-b19b-ae8354399310", + "IdentifiedObject.name": "556mcm", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + } + ] + } + } + } + }, + "Location": { + "primary_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "cd4c22b1-390a-48b4-ba9b-c5b0a6a13e79", + "IdentifiedObject.name": "primary_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + }, + "loadbus_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "1f628e25-f631-49b3-b43c-b8618559661c", + "IdentifiedObject.name": "loadbus_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + }, + "sourcebus_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "17d93d69-c091-40d2-8292-e9800154e3f9", + "IdentifiedObject.name": "sourcebus_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + } + }, + "EnergyConnectionProfile": { + "Ravens.CimObjectType": "EnergyConnectionProfile", + "IdentifiedObject.mRID": "a7098736-cc57-4a69-b250-3101ae6dd9f5", + "IdentifiedObject.name": "Load::::::defaultload", + "EnergyConnectionProfile.dssSpectrum": "defaultload" + }, + "BaseVoltage": { + "BaseV_0.4": { + "Ravens.CimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "270f81bf-ab58-46e9-863a-08744d924604", + "IdentifiedObject.name": "BaseV_0.4", + "BaseVoltage.nominalVoltage": 400.0 + }, + "BaseV_7.2000": { + "Ravens.CimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "_200EDAAE-4DBD-4A69-9033-B4032B2270FE", + "IdentifiedObject.name": "BaseV_7.2000", + "BaseVoltage.nominalVoltage": 7200 + } + }, + "OperationalLimitType": { + "highType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "48f1510a-52d8-4c04-a0e7-59a8876eafa2", + "IdentifiedObject.name": "highType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "absoluteValueType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "faf34841-2190-4133-bf8d-cf31f35a80a0", + "IdentifiedObject.name": "absoluteValueType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "absoluteValueType_86400.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "14a68643-2417-4e41-b809-940b9b1856d1", + "IdentifiedObject.name": "absoluteValueType_86400.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 86400.0 + }, + "lowType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "33ce2fce-d1cb-4df3-924f-0399aa127edd", + "IdentifiedObject.name": "lowType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "case3_balanced_NormAmpsType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_F8347896-5AFD-4AD3-BDFB-C2B164917AB7", + "IdentifiedObject.name": "case3_balanced_NormAmpsType", + "OperationalLimitType.acceptableDuration": 5000000000.0, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue" + }, + "case3_balanced_EmergencyAmpsType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_65F6EC19-7482-49EA-8064-6F2E06BF9E28", + "IdentifiedObject.name": "case3_balanced_EmergencyAmpsType", + "OperationalLimitType.acceptableDuration": 7200, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue" + }, + "case3_balanced_RangeAHiType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_5B420D61-5A29-40E4-BFB8-7E4B7E0B4215", + "IdentifiedObject.name": "case3_balanced_RangeAHiType", + "OperationalLimitType.acceptableDuration": 5000000000.0, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high" + }, + "case3_balanced_RangeALoType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_C8B99699-7B9D-40AF-AEFB-E862D9A0109B", + "IdentifiedObject.name": "case3_balanced_RangeALoType", + "OperationalLimitType.acceptableDuration": 5000000000.0, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low" + } + }, + "ConnectivityNode": { + "loadbus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "0f25fa64-77ce-4721-ad73-ecad9127fa2e", + "IdentifiedObject.name": "loadbus", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" + }, + "sourcebus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "e4ff4b6e-79fe-40b2-af40-e0226cf5f4a4", + "IdentifiedObject.name": "sourcebus", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_7.2000'" + }, + "primary": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "cc97ba78-4f37-4d8f-8044-55f023a74a28", + "IdentifiedObject.name": "primary", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" + }, + "subxfbus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "_FE727D13-2277-4F78-A5F2-FF1DF2FB8883", + "IdentifiedObject.name": "subxfbus", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" + } + }, + "LoadResponseCharacteristic": { + "Constant kVA": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "141f856d-53fd-4d9b-b71b-464b1db94318", + "IdentifiedObject.name": "Constant kVA", + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantPower": 100 + } + }, + "CoordinateSystem": { + "case3_balanced_CrsUrn": { + "Ravens.CimObjectType": "CoordinateSystem", + "IdentifiedObject.mRID": "_6FD1030A-4977-4961-A980-0E5A7F46D48A", + "IdentifiedObject.name": "case3_balanced_CrsUrn", + "CoordinateSystem.crsUrn": "OpenDSSLocalBusCoordinates" + } + }, + "Group": { + "GeographicalRegion": { + "case3_balanced_Region": { + "Ravens.CimObjectType": "GeographicalRegion", + "IdentifiedObject.mRID": "_2A0B22A1-CCB4-46F8-8F42-9090CA3B29AC", + "IdentifiedObject.name": "case3_balanced_Region" + } + }, + "SubGeographicalRegion": { + "case3_balanced_SubRegion": { + "Ravens.CimObjectType": "SubGeographicalRegion", + "IdentifiedObject.mRID": "_62CD9221-3F2B-4741-AF1B-16DED6354EEA", + "IdentifiedObject.name": "case3_balanced_SubRegion", + "SubGeographicalRegion.Region": "GeographicalRegion::'case3_balanced_Region'" + } + }, + "EquipmentContainer": { + "Ravens.CimObjectType": "Substation", + "IdentifiedObject.mRID": "_745276ED-1EDC-499C-9E0D-C9C138A9C49E", + "IdentifiedObject.name": "case3_balanced_Substation", + "PowerSystemResource.Location": "Location::'case3_balanced_Location'", + "Substation.Region": "SubGeographicalRegion::'case3_balanced_SubRegion'" + }, + "TopologicalIsland": { + "case3_balanced_Island": { + "Ravens.CimObjectType": "TopologicalIsland", + "IdentifiedObject.mRID": "_6A44C429-666A-4200-B3AE-10FCFDF8A04A", + "IdentifiedObject.name": "case3_balanced_Island" + } + } + } +} diff --git a/test/data/ravens/ravens_test_switch_1w.json b/test/data/ravens/ravens_test_switch_1w.json new file mode 100644 index 000000000..0c177322a --- /dev/null +++ b/test/data/ravens/ravens_test_switch_1w.json @@ -0,0 +1,554 @@ +{ + "Versions": { + "IEC61970CIMVersion": { + "Ravens.CimObjectType": "IEC61970CIMVersion", + "IEC61970CIMVersion.version": "IEC61970CIM100", + "IEC61970CIMVersion.date": "2019-04-01" + } + }, + "CoordinateSystem": { + "test_CrsUrn": { + "Ravens.CimObjectType": "CoordinateSystem", + "IdentifiedObject.mRID": "_9EF37BD9-0C2D-4AE1-AE0F-B7B851E66544", + "IdentifiedObject.name": "test_CrsUrn", + "CoordinateSystem.crsUrn": "OpenDSSLocalBusCoordinates" + } + }, + "Group": { + "GeographicalRegion": { + "test_Region": { + "Ravens.CimObjectType": "GeographicalRegion", + "IdentifiedObject.mRID": "_90228F7F-5927-47CB-8796-8489A7068FC1", + "IdentifiedObject.name": "test_Region" + } + }, + "SubGeographicalRegion": { + "test_SubRegion": { + "Ravens.CimObjectType": "SubGeographicalRegion", + "IdentifiedObject.mRID": "_424DAD1E-F5F9-4573-B62A-6FDE7CD692C9", + "IdentifiedObject.name": "test_SubRegion", + "SubGeographicalRegion.Region": "GeographicalRegion::'test_Region'" + } + }, + "EquipmentContainer": { + "Ravens.CimObjectType": "Substation", + "IdentifiedObject.mRID": "_AD96408A-13FD-44CD-8441-D474E3744E1F", + "IdentifiedObject.name": "test_Substation", + "PowerSystemResource.Location": "Location::'test_Location'", + "Substation.Region": "SubGeographicalRegion::'test_SubRegion'" + }, + "TopologicalIsland": { + "test_Island": { + "Ravens.CimObjectType": "TopologicalIsland", + "IdentifiedObject.mRID": "_62B53E99-C000-4FEE-80CE-6F29110E1873", + "IdentifiedObject.name": "test_Island" + } + } + }, + "Location": { + "test_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_2B41D90F-6E55-496B-8BEA-23C7CD041DBF", + "IdentifiedObject.name": "test_Location", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'" + }, + "source_Loc": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_44C707B5-0B86-4815-9F65-A2D2F7BB0243", + "IdentifiedObject.name": "source_Loc", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + } + ] + }, + "line1_Loc": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_52FB75B7-56B0-4F20-B2E2-6BF70AFB5E41", + "IdentifiedObject.name": "line1_Loc", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + }, + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 2, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + } + ] + }, + "switch_Loc": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_1E0CF052-B39C-424B-B945-BF89267A5411", + "IdentifiedObject.name": "switch_Loc", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + }, + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 2, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + } + ] + }, + "load1_Loc": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_2B553B02-E33C-4527-9A2C-FAF6741A8C90", + "IdentifiedObject.name": "load1_Loc", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + } + ] + } + }, + "OperationalLimitSet": { + "OpLimI_400.0_600.0": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "_89FAB3C8-F3EA-42D6-9FFB-C7218A5B700C", + "IdentifiedObject.name": "OpLimI_400.0_600.0", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "_CCAE60BA-5D56-4F8F-8400-9A21902C2A9D", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", + "CurrentLimit.value": 400, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_3F1940AC-91FD-4679-B727-9275063CCC2E", + "IdentifiedObject.name": "test_NormAmpsType", + "OperationalLimitType.acceptableDuration": 5000000000.0, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue" + } + }, + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "_1AB18FDA-00CF-4A84-AB9E-D3EFF39464A5", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", + "CurrentLimit.value": 600, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_51A01C28-E11F-4684-8137-15D0140100D1", + "IdentifiedObject.name": "test_EmergencyAmpsType", + "OperationalLimitType.acceptableDuration": 7200, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue" + } + } + ] + }, + "OpLimV_0.4000": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "_DC0A7C69-F8A9-4A07-B4B6-AA56A138CFED", + "IdentifiedObject.name": "OpLimV_0.4000", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "_860EBBB7-81B5-45D5-9D15-EBDADB0903F9", + "IdentifiedObject.name": "OpLimV_0.4000_RangeAHi", + "VoltageLimit.value": 420, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_1CBA95F9-4F8F-4930-8376-94867399492F", + "IdentifiedObject.name": "test_RangeAHiType", + "OperationalLimitType.acceptableDuration": 5000000000.0, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high" + } + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "_36431E54-2475-4280-8443-827DFD546DEC", + "IdentifiedObject.name": "OpLimV_0.4000_RangeALo", + "VoltageLimit.value": 380, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_EEBC518E-8B78-4C6B-8F85-2DF8C9C53C71", + "IdentifiedObject.name": "test_RangeALoType", + "OperationalLimitType.acceptableDuration": 5000000000.0, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low" + } + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "_97FB217B-7289-4DCF-B690-67F2451EF298", + "IdentifiedObject.name": "OpLimV_0.4000_RangeBHi", + "VoltageLimit.value": 423.33332, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_FDABBB3E-12E8-4AD3-B1C9-43B35C5C57B3", + "IdentifiedObject.name": "test_RangeBHiType", + "OperationalLimitType.acceptableDuration": 86400, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high" + } + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "_8106713D-D130-4A5D-80C2-42A8374B5BC3", + "IdentifiedObject.name": "OpLimV_0.4000_RangeBLo", + "VoltageLimit.value": 366.66668, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_BCFA3B34-0937-4455-B154-7233DAEE4310", + "IdentifiedObject.name": "test_RangeBLoType", + "OperationalLimitType.acceptableDuration": 86400, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low" + } + } + ] + } + }, + "BaseVoltage": { + "BaseV_0.4000": { + "Ravens.CimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "_46C78529-FF4F-40A8-841D-418D7D52BEFD", + "IdentifiedObject.name": "BaseV_0.4000", + "BaseVoltage.nominalVoltage": 400 + } + }, + "TopologicalNode": { + "b1": { + "Ravens.CimObjectType": "TopologicalNode", + "IdentifiedObject.mRID": "_1D7153A2-9354-4542-8A08-F6FCF43002D1", + "IdentifiedObject.name": "b1", + "TopologicalNode.TopologicalIsland": "TopologicalIsland::'test_Island'" + }, + "x1": { + "Ravens.CimObjectType": "TopologicalNode", + "IdentifiedObject.mRID": "_B764BFB0-EEB1-4CFF-9BA5-894D76A00B8E", + "IdentifiedObject.name": "x1", + "TopologicalNode.TopologicalIsland": "TopologicalIsland::'test_Island'" + }, + "x2": { + "Ravens.CimObjectType": "TopologicalNode", + "IdentifiedObject.mRID": "_DE499DAA-E9D0-4EEC-8BAE-FB7E9A439230", + "IdentifiedObject.name": "x2", + "TopologicalNode.TopologicalIsland": "TopologicalIsland::'test_Island'" + } + }, + "ConnectivityNode": { + "b1": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "_DB090751-3E13-456A-A662-CF7D7C528C94", + "IdentifiedObject.name": "b1", + "ConnectivityNode.TopologicalNode": "TopologicalNode::'b1'", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_0.4000'" + }, + "x1": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "_6E6F3550-3BFB-4009-B76F-6693D5604960", + "IdentifiedObject.name": "x1", + "ConnectivityNode.TopologicalNode": "TopologicalNode::'x1'", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_0.4000'" + }, + "x2": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "_B1CC7BCB-0E9C-4246-8AC9-4BB6B0453256", + "IdentifiedObject.name": "x2", + "ConnectivityNode.TopologicalNode": "TopologicalNode::'x2'", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_0.4000'" + } + }, + "PowerSystemResource": { + "Equipment": { + "ConductingEquipment": { + "EnergyConnection": { + "EnergySource": { + "source": { + "Ravens.CimObjectType": "EnergySource", + "IdentifiedObject.mRID": "_5CF553FD-BC94-4E9D-8B6D-D928BCF554A3", + "IdentifiedObject.name": "source", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4000'", + "EnergySource.nominalVoltage": 400, + "EnergySource.voltageMagnitude": 400, + "EnergySource.voltageAngle": 0, + "EnergySource.r": 3.88057e-10, + "EnergySource.x": 1.552228e-09, + "EnergySource.r0": 5.069596e-10, + "EnergySource.x0": 1.5208788e-09, + "PowerSystemResource.Location": "Location::'source_Loc'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_BB8461F8-A1E9-4D73-94E2-EB857395A8DF", + "IdentifiedObject.name": "source_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.ConnectivityNode": "ConnectivityNode::'b1'" + } + ] + } + }, + "EnergyConsumer": { + "load1": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "_D322D86C-C523-48E9-B2AE-A5F57975536B", + "IdentifiedObject.name": "load1", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4000'", + "EnergyConsumer.p": 4500, + "EnergyConsumer.q": 2179.4495, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.grounded": "true", + "PowerSystemResource.Location": "Location::'load1_Loc'", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_37E125ED-75BE-4C31-8CFE-AC4A3C9E19D7", + "IdentifiedObject.name": "load1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.ConnectivityNode": "ConnectivityNode::'x2'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "_C8574EA9-6EB0-40F9-B051-3807FB0196FD", + "IdentifiedObject.name": "load1_B", + "EnergyConsumerPhase.phase": "SinglePhaseKind.B", + "EnergyConsumerPhase.p": 4500, + "EnergyConsumerPhase.q": 2179.4495, + "PowerSystemResource.Location": "Location::'load1_Loc'" + } + ] + } + } + }, + "Conductor": { + "ACLineSegment": { + "line1": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "_6B5FF69A-404A-4389-9FA1-F43943464A66", + "IdentifiedObject.name": "line1", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4000'", + "Conductor.length": 500, + "PowerSystemResource.Location": "Location::'line1_Loc'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'z'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_B2950608-195A-4420-97AE-425C0B09A2C1", + "IdentifiedObject.name": "line1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.ConnectivityNode": "ConnectivityNode::'b1'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_F1E9D575-D53F-4386-A904-929F0D7A44CE", + "IdentifiedObject.name": "line1_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.ConnectivityNode": "ConnectivityNode::'x1'" + } + ], + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "_B59AC09D-9E51-4585-B330-3A24C685CB8A", + "IdentifiedObject.name": "line1_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1, + "PowerSystemResource.Location": "Location::'line1_Loc'" + } + ] + } + } + }, + "Switch": { + "switch": { + "Ravens.CimObjectType": "LoadBreakSwitch", + "IdentifiedObject.mRID": "_25E1438A-99DB-46BB-B727-26C74AE79D60", + "IdentifiedObject.name": "switch", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4000'", + "ProtectedSwitch.breakingCapacity": 400, + "Switch.ratedCurrent": 400, + "Switch.normalOpen": "false", + "Switch.open": "false", + "Switch.retained": "true", + "PowerSystemResource.Location": "Location::'switch_Loc'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_9294CBC6-783E-4840-8196-357BFF6BA45A", + "IdentifiedObject.name": "switch_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.ConnectivityNode": "ConnectivityNode::'x1'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_E1443DD5-526D-47E3-A87A-0C1F0A9B2DDC", + "IdentifiedObject.name": "switch_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.ConnectivityNode": "ConnectivityNode::'x2'" + } + ], + "Switch.SwitchPhase": [ + { + "Ravens.CimObjectType": "SwitchPhase", + "IdentifiedObject.mRID": "_B7162222-1F35-4713-9A3A-8360A2205C64", + "IdentifiedObject.name": "switch_A", + "SwitchPhase.closed": "true", + "SwitchPhase.normalOpen": "false", + "SwitchPhase.phaseSide1": "SinglePhaseKind.A", + "SwitchPhase.phaseSide2": "SinglePhaseKind.B", + "PowerSystemResource.Location": "Location::'switch_Loc'" + } + ] + } + } + } + } + }, + "LoadResponseCharacteristic": { + "Constant kVA": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_289E6326-E370-4C24-A190-53BFCC2C8848", + "IdentifiedObject.name": "Constant kVA", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantImpedance": 0, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 100, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Constant Z": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_A48E7B14-EF00-4F4D-A66E-0A92D0D5FD79", + "IdentifiedObject.name": "Constant Z", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 100, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 0, + "LoadResponseCharacteristic.qConstantImpedance": 100, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 0, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Motor": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_F9289DA6-1EE6-4075-A5BE-BA990ABA3B40", + "IdentifiedObject.name": "Motor", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantImpedance": 100, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 0, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Mix Motor/Res": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_EDC6EAFB-A22C-45F1-AF5C-9DE0CCAA51EC", + "IdentifiedObject.name": "Mix Motor/Res", + "LoadResponseCharacteristic.exponentModel": "true", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 0, + "LoadResponseCharacteristic.qConstantImpedance": 0, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 0, + "LoadResponseCharacteristic.pVoltageExponent": 1, + "LoadResponseCharacteristic.qVoltageExponent": 2, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Constant I": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_585ED09B-E47D-4EB9-9DB5-FD74719C3125", + "IdentifiedObject.name": "Constant I", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 100, + "LoadResponseCharacteristic.pConstantPower": 0, + "LoadResponseCharacteristic.qConstantImpedance": 0, + "LoadResponseCharacteristic.qConstantCurrent": 100, + "LoadResponseCharacteristic.qConstantPower": 0, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Variable P, Fixed Q": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_72B0F5AF-3B37-4467-82B5-C425210463B1", + "IdentifiedObject.name": "Variable P, Fixed Q", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantImpedance": 0, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 100, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Variable P, Fixed X": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_A5CAED93-49D2-4F4F-AD82-524C76A76AC5", + "IdentifiedObject.name": "Variable P, Fixed X", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantImpedance": 100, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 0, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + } + }, + "PerLengthLineParameter": { + "PerLengthImpedance": { + "PerLengthPhaseImpedance": { + "z": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "_BF7B98AF-6218-4723-B7CA-A9F210A42553", + "IdentifiedObject.name": "z", + "PerLengthPhaseImpedance.conductorCount": 1, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.00022721762, + "PhaseImpedanceData.x": 0.00087932601, + "PhaseImpedanceData.b": 0 + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/test/data/ravens/ravens_test_switch_3w.json b/test/data/ravens/ravens_test_switch_3w.json new file mode 100644 index 000000000..ae7c35260 --- /dev/null +++ b/test/data/ravens/ravens_test_switch_3w.json @@ -0,0 +1,785 @@ +{ + "Versions": { + "IEC61970CIMVersion": { + "Ravens.CimObjectType": "IEC61970CIMVersion", + "IEC61970CIMVersion.version": "IEC61970CIM100", + "IEC61970CIMVersion.date": "2019-04-01" + } + }, + "CoordinateSystem": { + "test_CrsUrn": { + "Ravens.CimObjectType": "CoordinateSystem", + "IdentifiedObject.mRID": "_9EF37BD9-0C2D-4AE1-AE0F-B7B851E66544", + "IdentifiedObject.name": "test_CrsUrn", + "CoordinateSystem.crsUrn": "OpenDSSLocalBusCoordinates" + } + }, + "Group": { + "GeographicalRegion": { + "test_Region": { + "Ravens.CimObjectType": "GeographicalRegion", + "IdentifiedObject.mRID": "_90228F7F-5927-47CB-8796-8489A7068FC1", + "IdentifiedObject.name": "test_Region" + } + }, + "SubGeographicalRegion": { + "test_SubRegion": { + "Ravens.CimObjectType": "SubGeographicalRegion", + "IdentifiedObject.mRID": "_424DAD1E-F5F9-4573-B62A-6FDE7CD692C9", + "IdentifiedObject.name": "test_SubRegion", + "SubGeographicalRegion.Region": "GeographicalRegion::'test_Region'" + } + }, + "EquipmentContainer": { + "Ravens.CimObjectType": "Substation", + "IdentifiedObject.mRID": "_AD96408A-13FD-44CD-8441-D474E3744E1F", + "IdentifiedObject.name": "test_Substation", + "PowerSystemResource.Location": "Location::'test_Location'", + "Substation.Region": "SubGeographicalRegion::'test_SubRegion'" + }, + "TopologicalIsland": { + "test_Island": { + "Ravens.CimObjectType": "TopologicalIsland", + "IdentifiedObject.mRID": "_62B53E99-C000-4FEE-80CE-6F29110E1873", + "IdentifiedObject.name": "test_Island" + } + } + }, + "Location": { + "test_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_2B41D90F-6E55-496B-8BEA-23C7CD041DBF", + "IdentifiedObject.name": "test_Location", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'" + }, + "source_Loc": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_44C707B5-0B86-4815-9F65-A2D2F7BB0243", + "IdentifiedObject.name": "source_Loc", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + } + ] + }, + "line1_Loc": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_52FB75B7-56B0-4F20-B2E2-6BF70AFB5E41", + "IdentifiedObject.name": "line1_Loc", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + }, + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 2, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + } + ] + }, + "line2_Loc": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_BAD30397-D375-41B3-9540-9EEE6348178B", + "IdentifiedObject.name": "line2_Loc", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + }, + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 2, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + } + ] + }, + "switch_Loc": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_1E0CF052-B39C-424B-B945-BF89267A5411", + "IdentifiedObject.name": "switch_Loc", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + }, + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 2, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + } + ] + }, + "load1_Loc": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "_2B553B02-E33C-4527-9A2C-FAF6741A8C90", + "IdentifiedObject.name": "load1_Loc", + "Location.CoordinateSystem": "CoordinateSystem::'test_CrsUrn'", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0, + "PositionPoint.yPosition": 0 + } + ] + } + }, + "OperationalLimitSet": { + "OpLimI_400.0_600.0": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "_89FAB3C8-F3EA-42D6-9FFB-C7218A5B700C", + "IdentifiedObject.name": "OpLimI_400.0_600.0", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "_CCAE60BA-5D56-4F8F-8400-9A21902C2A9D", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", + "CurrentLimit.value": 400, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_3F1940AC-91FD-4679-B727-9275063CCC2E", + "IdentifiedObject.name": "test_NormAmpsType", + "OperationalLimitType.acceptableDuration": 5000000000.0, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue" + } + }, + { + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_51A01C28-E11F-4684-8137-15D0140100D1", + "IdentifiedObject.name": "test_EmergencyAmpsType", + "OperationalLimitType.acceptableDuration": 7200, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue" + } + } + ] + }, + "OpLimI_325.0_600.0": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "_16C3AE1B-6C4F-4EFF-82F5-320881E41F05", + "IdentifiedObject.name": "OpLimI_325.0_600.0", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "_E570FFBB-3E31-4A1A-B409-276C80B48F06", + "IdentifiedObject.name": "OpLimI_325.0_600.0_Norm", + "CurrentLimit.value": 325, + "OperationalLimitSet": { + "OpLimI_400.0_600.0": { + "OperationalLimitSet.OperationalLimitValue": [ + { + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_3F1940AC-91FD-4679-B727-9275063CCC2E", + "IdentifiedObject.name": "test_NormAmpsType", + "OperationalLimitType.acceptableDuration": 5000000000.0, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue" + } + } + ] + } + } + }, + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "_D1958AB8-9E7F-49E2-B1C9-891DC6F438C4", + "IdentifiedObject.name": "OpLimI_325.0_600.0_Emerg", + "CurrentLimit.value": 600, + "OperationalLimitSet": { + "OpLimI_400.0_600.0": { + "OperationalLimitSet.OperationalLimitValue": [ + { + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_51A01C28-E11F-4684-8137-15D0140100D1", + "IdentifiedObject.name": "test_EmergencyAmpsType", + "OperationalLimitType.acceptableDuration": 7200, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue" + } + } + ] + } + } + } + ] + }, + "OpLimV_0.4000": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "_DC0A7C69-F8A9-4A07-B4B6-AA56A138CFED", + "IdentifiedObject.name": "OpLimV_0.4000", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "_860EBBB7-81B5-45D5-9D15-EBDADB0903F9", + "IdentifiedObject.name": "OpLimV_0.4000_RangeAHi", + "VoltageLimit.value": 420, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_1CBA95F9-4F8F-4930-8376-94867399492F", + "IdentifiedObject.name": "test_RangeAHiType", + "OperationalLimitType.acceptableDuration": 5000000000.0, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high" + } + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "_36431E54-2475-4280-8443-827DFD546DEC", + "IdentifiedObject.name": "OpLimV_0.4000_RangeALo", + "VoltageLimit.value": 380, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_EEBC518E-8B78-4C6B-8F85-2DF8C9C53C71", + "IdentifiedObject.name": "test_RangeALoType", + "OperationalLimitType.acceptableDuration": 5000000000.0, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low" + } + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "_97FB217B-7289-4DCF-B690-67F2451EF298", + "IdentifiedObject.name": "OpLimV_0.4000_RangeBHi", + "VoltageLimit.value": 423.33332, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_FDABBB3E-12E8-4AD3-B1C9-43B35C5C57B3", + "IdentifiedObject.name": "test_RangeBHiType", + "OperationalLimitType.acceptableDuration": 86400, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high" + } + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "_8106713D-D130-4A5D-80C2-42A8374B5BC3", + "IdentifiedObject.name": "OpLimV_0.4000_RangeBLo", + "VoltageLimit.value": 366.66668, + "OperationalLimit.OperationalLimitType": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "_BCFA3B34-0937-4455-B154-7233DAEE4310", + "IdentifiedObject.name": "test_RangeBLoType", + "OperationalLimitType.acceptableDuration": 86400, + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low" + } + } + ] + } + }, + "BaseVoltage": { + "BaseV_0.4000": { + "Ravens.CimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "_46C78529-FF4F-40A8-841D-418D7D52BEFD", + "IdentifiedObject.name": "BaseV_0.4000", + "BaseVoltage.nominalVoltage": 400 + } + }, + "TopologicalNode": { + "b1": { + "Ravens.CimObjectType": "TopologicalNode", + "IdentifiedObject.mRID": "_1D7153A2-9354-4542-8A08-F6FCF43002D1", + "IdentifiedObject.name": "b1", + "TopologicalNode.TopologicalIsland": "TopologicalIsland::'test_Island'" + }, + "x1": { + "Ravens.CimObjectType": "TopologicalNode", + "IdentifiedObject.mRID": "_B764BFB0-EEB1-4CFF-9BA5-894D76A00B8E", + "IdentifiedObject.name": "x1", + "TopologicalNode.TopologicalIsland": "TopologicalIsland::'test_Island'" + }, + "x2": { + "Ravens.CimObjectType": "TopologicalNode", + "IdentifiedObject.mRID": "_DE499DAA-E9D0-4EEC-8BAE-FB7E9A439230", + "IdentifiedObject.name": "x2", + "TopologicalNode.TopologicalIsland": "TopologicalIsland::'test_Island'" + }, + "b2": { + "Ravens.CimObjectType": "TopologicalNode", + "IdentifiedObject.mRID": "_6D31F0A7-328F-482B-B800-E86BFE69E9F1", + "IdentifiedObject.name": "b2", + "TopologicalNode.TopologicalIsland": "TopologicalIsland::'test_Island'" + } + }, + "ConnectivityNode": { + "b1": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "_3C23D8DF-C749-40CE-AB59-E9BCB6A51F6B", + "IdentifiedObject.name": "b1", + "ConnectivityNode.TopologicalNode": "TopologicalNode::'b1'", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_0.4000'" + }, + "x1": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "_3626FADA-426C-484F-8B69-5371B1EFF327", + "IdentifiedObject.name": "x1", + "ConnectivityNode.TopologicalNode": "TopologicalNode::'x1'", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_0.4000'" + }, + "x2": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "_59C1D3CF-5E4E-49CD-AEB3-4799F2383036", + "IdentifiedObject.name": "x2", + "ConnectivityNode.TopologicalNode": "TopologicalNode::'x2'", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_0.4000'" + }, + "b2": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "_58F5C3B9-8A22-4B99-BF8A-CF781597CAD5", + "IdentifiedObject.name": "b2", + "ConnectivityNode.TopologicalNode": "TopologicalNode::'b2'", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_0.4000'" + } + }, + "PowerSystemResource": { + "Equipment": { + "ConductingEquipment": { + "EnergyConnection": { + "EnergySource": { + "source": { + "Ravens.CimObjectType": "EnergySource", + "IdentifiedObject.mRID": "_358FCE15-BEE2-42A8-A2EA-AD2BE89D86E5", + "IdentifiedObject.name": "source", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4000'", + "EnergySource.nominalVoltage": 400, + "EnergySource.voltageMagnitude": 400, + "EnergySource.voltageAngle": 0, + "EnergySource.r": 3.88057e-10, + "EnergySource.x": 1.552228e-09, + "EnergySource.r0": 5.069596e-10, + "EnergySource.x0": 1.5208788e-09, + "PowerSystemResource.Location": "Location::'source_Loc'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_BB8461F8-A1E9-4D73-94E2-EB857395A8DF", + "IdentifiedObject.name": "source_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.ConnectivityNode": "ConnectivityNode::'b1'" + } + ] + } + }, + "EnergyConsumer": { + "load1": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "_E8F49CFB-ECE7-4059-A6EE-4825FE7FFEFD", + "IdentifiedObject.name": "load1", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4000'", + "EnergyConsumer.p": 4500, + "EnergyConsumer.q": 2179.4495, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.grounded": "true", + "PowerSystemResource.Location": "Location::'load1_Loc'", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_37E125ED-75BE-4C31-8CFE-AC4A3C9E19D7", + "IdentifiedObject.name": "load1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.ConnectivityNode": "ConnectivityNode::'b2'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "_D358F738-0512-45C7-BFAC-10639DD0CE55", + "IdentifiedObject.name": "load1_A", + "EnergyConsumerPhase.phase": "SinglePhaseKind.A", + "EnergyConsumerPhase.p": 4500, + "EnergyConsumerPhase.q": 2179.4495, + "PowerSystemResource.Location": "Location::'load1_Loc'" + } + ] + } + } + }, + "Conductor": { + "ACLineSegment": { + "line1": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "_7172CC52-4D06-433D-A057-3CD4899F1162", + "IdentifiedObject.name": "line1", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4000'", + "Conductor.length": 500, + "PowerSystemResource.Location": "Location::'line1_Loc'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'zabc'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_B2950608-195A-4420-97AE-425C0B09A2C1", + "IdentifiedObject.name": "line1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.ConnectivityNode": "ConnectivityNode::'b1'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_F1E9D575-D53F-4386-A904-929F0D7A44CE", + "IdentifiedObject.name": "line1_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.ConnectivityNode": "ConnectivityNode::'x1'" + } + ], + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "_B59AC09D-9E51-4585-B330-3A24C685CB8A", + "IdentifiedObject.name": "line1_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1, + "PowerSystemResource.Location": "Location::'line1_Loc'" + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "_E93F91B2-E00F-417A-855A-B203615EF628", + "IdentifiedObject.name": "line1_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2, + "PowerSystemResource.Location": "Location::'line1_Loc'" + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "_29601914-BE61-417C-A333-0AD243A0A9C2", + "IdentifiedObject.name": "line1_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3, + "PowerSystemResource.Location": "Location::'line1_Loc'" + } + ] + }, + "line2": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "_4BFECD8D-AB5A-4D82-BB7D-6AEAE0378878", + "IdentifiedObject.name": "line2", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4000'", + "Conductor.length": 500, + "PowerSystemResource.Location": "Location::'line2_Loc'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'zabc'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_4308397E-D8AA-4109-9F42-AFB3095DEF49", + "IdentifiedObject.name": "line2_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.ConnectivityNode": "ConnectivityNode::'x2'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_1FE3FC50-F1F6-4359-A291-27F931567289", + "IdentifiedObject.name": "line2_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.ConnectivityNode": "ConnectivityNode::'b2'" + } + ], + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "_E7299BD3-2968-4C64-B698-F3E551AA8DC5", + "IdentifiedObject.name": "line2_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1, + "PowerSystemResource.Location": "Location::'line2_Loc'" + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "_9156496B-AEBC-4632-81FB-D604FE43C564", + "IdentifiedObject.name": "line2_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2, + "PowerSystemResource.Location": "Location::'line2_Loc'" + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "_1CFA79DC-393D-4F62-BE02-23EDA5542A72", + "IdentifiedObject.name": "line2_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3, + "PowerSystemResource.Location": "Location::'line2_Loc'" + } + ] + } + } + }, + "Switch": { + "switch": { + "Ravens.CimObjectType": "LoadBreakSwitch", + "IdentifiedObject.mRID": "_3E3C08FF-B3E1-44E7-B5EA-DB922C485D57", + "IdentifiedObject.name": "switch", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4000'", + "ProtectedSwitch.breakingCapacity": 325, + "Switch.ratedCurrent": 325, + "Switch.normalOpen": "false", + "Switch.open": "false", + "Switch.retained": "true", + "PowerSystemResource.Location": "Location::'switch_Loc'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_9294CBC6-783E-4840-8196-357BFF6BA45A", + "IdentifiedObject.name": "switch_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.ConnectivityNode": "ConnectivityNode::'b1'", + "Terminal.phases": "PhaseCode.ABC" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "_E1443DD5-526D-47E3-A87A-0C1F0A9B2DDC", + "IdentifiedObject.name": "switch_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.ConnectivityNode": "ConnectivityNode::'x2'", + "Terminal.phases": "PhaseCode.ABC" + } + ] + } + } + } + } + }, + "LoadResponseCharacteristic": { + "Constant kVA": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_289E6326-E370-4C24-A190-53BFCC2C8848", + "IdentifiedObject.name": "Constant kVA", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantImpedance": 0, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 100, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Constant Z": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_A48E7B14-EF00-4F4D-A66E-0A92D0D5FD79", + "IdentifiedObject.name": "Constant Z", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 100, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 0, + "LoadResponseCharacteristic.qConstantImpedance": 100, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 0, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Motor": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_F9289DA6-1EE6-4075-A5BE-BA990ABA3B40", + "IdentifiedObject.name": "Motor", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantImpedance": 100, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 0, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Mix Motor/Res": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_EDC6EAFB-A22C-45F1-AF5C-9DE0CCAA51EC", + "IdentifiedObject.name": "Mix Motor/Res", + "LoadResponseCharacteristic.exponentModel": "true", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 0, + "LoadResponseCharacteristic.qConstantImpedance": 0, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 0, + "LoadResponseCharacteristic.pVoltageExponent": 1, + "LoadResponseCharacteristic.qVoltageExponent": 2, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Constant I": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_585ED09B-E47D-4EB9-9DB5-FD74719C3125", + "IdentifiedObject.name": "Constant I", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 100, + "LoadResponseCharacteristic.pConstantPower": 0, + "LoadResponseCharacteristic.qConstantImpedance": 0, + "LoadResponseCharacteristic.qConstantCurrent": 100, + "LoadResponseCharacteristic.qConstantPower": 0, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Variable P, Fixed Q": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_72B0F5AF-3B37-4467-82B5-C425210463B1", + "IdentifiedObject.name": "Variable P, Fixed Q", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantImpedance": 0, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 100, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + }, + "Variable P, Fixed X": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "_A5CAED93-49D2-4F4F-AD82-524C76A76AC5", + "IdentifiedObject.name": "Variable P, Fixed X", + "LoadResponseCharacteristic.exponentModel": "false", + "LoadResponseCharacteristic.pConstantImpedance": 0, + "LoadResponseCharacteristic.pConstantCurrent": 0, + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantImpedance": 100, + "LoadResponseCharacteristic.qConstantCurrent": 0, + "LoadResponseCharacteristic.qConstantPower": 0, + "LoadResponseCharacteristic.pVoltageExponent": 0, + "LoadResponseCharacteristic.qVoltageExponent": 0, + "LoadResponseCharacteristic.pFrequencyExponent": 0, + "LoadResponseCharacteristic.qFrequencyExponent": 0 + } + }, + "PerLengthLineParameter": { + "PerLengthImpedance": { + "PerLengthPhaseImpedance": { + "zabc": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "_6DB02495-150A-479A-A9A5-8429B6E4DA8E", + "IdentifiedObject.name": "zabc", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.00022721762, + "PhaseImpedanceData.x": 0.00087932601, + "PhaseImpedanceData.b": 0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 5.9217624e-05, + "PhaseImpedanceData.x": 0.00054106971, + "PhaseImpedanceData.b": 0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.00022721762, + "PhaseImpedanceData.x": 0.00087932601, + "PhaseImpedanceData.b": 0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 5.9217624e-05, + "PhaseImpedanceData.x": 0.0004755458, + "PhaseImpedanceData.b": 0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 5.9217624e-05, + "PhaseImpedanceData.x": 0.00051653344, + "PhaseImpedanceData.b": 0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.00022721762, + "PhaseImpedanceData.x": 0.00087932601, + "PhaseImpedanceData.b": 0 + } + ] + }, + "goab_disswitch_3_8_3_5": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "_E4EED264-402C-4DF0-A23D-0D289762C4A3", + "IdentifiedObject.name": "goab_disswitch_3_8_3_5", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 1e-06, + "PhaseImpedanceData.x": 1e-06, + "PhaseImpedanceData.b": 1.3193042e-09 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0, + "PhaseImpedanceData.x": 0, + "PhaseImpedanceData.b": -4.1228239e-11 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 1e-06, + "PhaseImpedanceData.x": 1e-06, + "PhaseImpedanceData.b": 1.3193042e-09 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0, + "PhaseImpedanceData.x": 0, + "PhaseImpedanceData.b": -4.1228239e-11 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0, + "PhaseImpedanceData.x": 0, + "PhaseImpedanceData.b": -4.1228239e-11 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 1e-06, + "PhaseImpedanceData.x": 1e-06, + "PhaseImpedanceData.b": 1.3193042e-09 + } + ] + } + } + } + } +} diff --git a/test/opf_ravens.jl b/test/opf_ravens.jl new file mode 100644 index 000000000..4b8a80484 --- /dev/null +++ b/test/opf_ravens.jl @@ -0,0 +1,70 @@ +@info "running optimal power flow (opf) tests using RAVENS data" + +@testset "test opf ravens" begin + + @testset "ravens case 3 with gens" begin + pmd_model = instantiate_mc_model_ravens(ravens_case3_withgens, ACPUPowerModel, build_mc_opf) + result = optimize_model!( + pmd_model, + relax_integrality=false, + optimizer=ipopt_solver, + solution_processors=Function[] + ) + @test result["termination_status"] == LOCALLY_SOLVED + end + + @testset "ravens case 3 with PV and storage" begin + pmd_model = instantiate_mc_model_ravens(ravens_case3_withpvandstorage, ACPUPowerModel, build_mc_opf) + result = optimize_model!( + pmd_model, + relax_integrality=false, + optimizer=ipopt_solver, + solution_processors=Function[] + ) + @test result["termination_status"] == LOCALLY_SOLVED + end + + @testset "ravens case 3 with subxf" begin + pmd_model = instantiate_mc_model_ravens(ravens_case3_withsubxf, ACPUPowerModel, build_mc_opf) + result = optimize_model!( + pmd_model, + relax_integrality=false, + optimizer=ipopt_solver, + solution_processors=Function[] + ) + @test result["termination_status"] == LOCALLY_SOLVED + end + + @testset "ravens case 3 with capacitor" begin + pmd_model = instantiate_mc_model_ravens(ravens_case3_withcap, ACPUPowerModel, build_mc_opf) + result = optimize_model!( + pmd_model, + relax_integrality=false, + optimizer=ipopt_solver, + solution_processors=Function[] + ) + @test result["termination_status"] == LOCALLY_SOLVED + end + + @testset "ravens test with switches 3w" begin + pmd_model = instantiate_mc_model_ravens(ravens_test_switch_3w, ACPUPowerModel, build_mc_opf) + result = optimize_model!( + pmd_model, + relax_integrality=false, + optimizer=ipopt_solver, + solution_processors=Function[] + ) + @test result["termination_status"] == LOCALLY_SOLVED + end + + # @testset "ravens test with switches 1w" begin + # pmd_model = instantiate_mc_model_ravens(ravens_test_switch_1w, ACPUPowerModel, build_mc_opf) + # result = optimize_model!( + # pmd_model, + # relax_integrality=false, + # optimizer=ipopt_solver, + # solution_processors=Function[] + # ) + # @test result["termination_status"] == LOCALLY_SOLVED + # end +end diff --git a/test/runtests.jl b/test/runtests.jl index 167b4f52b..405ce41dd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -66,4 +66,6 @@ include("test_cases.jl") include("en_pf_native_validation.jl") include("line_constants.jl") + + include("opf_ravens.jl") end diff --git a/test/test_cases.jl b/test/test_cases.jl index 1d3e03cb6..a6a476a9a 100644 --- a/test/test_cases.jl +++ b/test/test_cases.jl @@ -68,3 +68,11 @@ dist_transformer = parse_file("../test/data/opendss/dist_transformer.dss") # IEEE13 Feeder IEEE13_Feeder_engr = parse_file("../test/data/opendss/ieee13_feeder.dss", multinetwork=true, time_series="daily", transformations=[remove_line_limits!, remove_transformer_limits!]) + +# RAVENS +ravens_case3_withgens = parse_file("../test/data/ravens/ravens_case3_withgens.json") +ravens_case3_withpvandstorage = parse_file("../test/data/ravens/ravens_case3_withpvandstorage.json") +ravens_case3_withsubxf = parse_file("../test/data/ravens/ravens_case3_withsubxf.json") +ravens_case3_withcap = parse_file("../test/data/ravens/ravens_case3_withcap.json") +ravens_test_switch_3w = parse_file("../test/data/ravens/ravens_test_switch_3w.json") +# ravens_test_switch_1w = parse_file("../test/data/ravens/ravens_test_switch_1w.json") From 70b5b74ca37f273cbc11f9b9b20da647b530bb97 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 30 Jan 2025 13:13:43 -0700 Subject: [PATCH 27/99] ADD: support for basic multinetwork functionality using RAVENS schema based on BasicIntervalSchedule. --- src/data_model/transformations/ravens2math.jl | 223 ++++-- src/data_model/utils_ravens.jl | 16 + src/io/common.jl | 30 +- src/prob/common.jl | 2 +- .../data/ravens/ravens_case3_withgens_mn.json | 737 ++++++++++++++++++ test/opf_ravens.jl | 12 + test/test_cases.jl | 1 + 7 files changed, 947 insertions(+), 74 deletions(-) create mode 100644 test/data/ravens/ravens_case3_withgens_mn.json diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index fb56328fb..045a98ddc 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -43,13 +43,9 @@ function transform_data_model_ravens( current_data_model = get(data, "data_model", MATHEMATICAL) - ## TODO - # if multinetwork && !ismultinetwork(data) - # data = make_multinetwork(data; global_keys=global_keys) - # end - data_math = _map_ravens2math( data; + multinetwork=multinetwork, kron_reduce=kron_reduce, phase_project=phase_project, ravens2math_extensions=ravens2math_extensions, @@ -68,6 +64,7 @@ end "base function for converting ravens model to mathematical model" function _map_ravens2math( data_ravens::Dict{String,<:Any}; + multinetwork::Bool=false, kron_reduce::Bool=true, phase_project::Bool=false, ravens2math_extensions::Vector{<:Function}=Function[], @@ -86,24 +83,69 @@ function _map_ravens2math( "vbases_default" => Dict{String,Real}() ) - ## TODO: Multinetwork - if ismultinetwork(data_ravens) + # Multinetwork + if multinetwork data_math = Dict{String,Any}( "name" => get(_data_ravens, "name", ""), "data_model" => MATHEMATICAL, - "nw" => Dict{String,Any}( - n => Dict{String,Any}( - "per_unit" => get(_data_ravens, "per_unit", false), - "is_projected" => get(nw, "is_projected", false), - "is_kron_reduced" => get(nw, "is_kron_reduced", true), # TODO: Kron reduction? - "settings" => deepcopy(_settings), - "time_elapsed" => get(nw, "time_elapsed", 1.0), - ) for (n,nw) in _data_ravens["nw"] - ), - "multinetwork" => ismultinetwork(data_ravens), - [k => data_ravens[k] for k in global_keys if haskey(data_ravens, k)]... + "multinetwork" => multinetwork, + "nw" => Dict{String,Any}() ) - else + + if haskey(data_ravens, "BasicIntervalSchedule") + schdls = get(data_ravens, "BasicIntervalSchedule", Dict{String,Any}()) # Get schedules/timeseries + + # Check for shortest timeseries. Use that length for mn + min_length = Inf + for (name, ravens_obj) in schdls + if haskey(ravens_obj, "EnergyConsumerSchedule.RegularTimePoints") + points = ravens_obj["EnergyConsumerSchedule.RegularTimePoints"] + length_points = length(points) + + if length_points < min_length + min_length = length_points + end + end + end + + # Throw error if no schedule/timeseries is found. + if min_length == Inf + throw("Minimum length is equal to Inf. Cannot do multinetwork with Inf timepoints.") + end + + # Vector to store nws dictionaries + nws_vect = Vector{Dict{String,Any}}(undef, min_length) + + # Multithreaded loop to create each nw dictionary. Store them in vector (to allow multithreading) + Threads.@threads for n=1:1:min_length + nw_dict = Dict{String,Any}( + string(n) => Dict{String,Any}( + "per_unit" => get(_data_ravens, "per_unit", false), + "is_projected" => get(_data_ravens, "is_projected", false), + "is_kron_reduced" => get(_data_ravens, "is_kron_reduced", true), # TODO: Kron reduction? + "settings" => deepcopy(_settings), + "time_elapsed" => get(_data_ravens, "time_elapsed", 1.0), + ) + ) + + # Store nw dict in vector + nws_vect[n] = nw_dict + + # Perform conversion ravens2math + apply_pmd!(_map_ravens2math_nw!, nws_vect[n], _data_ravens; ravens2math_passthrough=ravens2math_passthrough, ravens2math_extensions=ravens2math_extensions, nw=n) + + end + + # Merge dict in vector into data_math dictionary (other for loop to allow multithreading) + for nw_dict in nws_vect + merge!(data_math["nw"], nw_dict) + end + + else + @error("No timeseries and/or multinetwork information detected.") + end + + else # No multinetwork data_math = Dict{String,Any}( "name" => get(_data_ravens, "name", ""), "per_unit" => get(_data_ravens, "per_unit", false), @@ -113,11 +155,11 @@ function _map_ravens2math( "settings" => deepcopy(_settings), "time_elapsed" => get(_data_ravens, "time_elapsed", 1.0), ) + apply_pmd!(_map_ravens2math_nw!, data_math, _data_ravens; ravens2math_passthrough=ravens2math_passthrough, ravens2math_extensions=ravens2math_extensions) end - apply_pmd!(_map_ravens2math_nw!, data_math, _data_ravens; ravens2math_passthrough=ravens2math_passthrough, ravens2math_extensions=ravens2math_extensions) - - if ismultinetwork(data_ravens) + # multinetwork collections + if multinetwork _collect_nw_maps!(data_math) _collect_nw_bus_lookups!(data_math) end @@ -128,32 +170,65 @@ end """ """ -function _map_ravens2math_nw!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; ravens2math_passthrough::Dict{String,Vector{String}}=Dict{String,Vector{String}}(), ravens2math_extensions::Vector{<:Function}=Function[]) - data_math["map"] = Vector{Dict{String,Any}}([ - Dict{String,Any}("unmap_function" => "_map_math2ravens_root!") - ]) - - _init_base_components!(data_math) - - ## TODO - # for property in get(ravens2math_passthrough, "root", String[]) - # if haskey(data_ravens, property) - # data_math[property] = deepcopy(data_ravens[property]) - # end - # end - - for type in pmd_ravens_asset_types - getfield(PowerModelsDistribution, Symbol("_map_ravens2math_$(type)!"))(data_math, data_ravens; pass_props=get(ravens2math_passthrough, type, String[])) - end +function _map_ravens2math_nw!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; ravens2math_passthrough::Dict{String,Vector{String}}=Dict{String,Vector{String}}(), ravens2math_extensions::Vector{<:Function}=Function[], nw::Int=nw_id_default) - # Custom ravens2math transformation functions - for ravens2math_func! in ravens2math_extensions - ravens2math_func!(data_math, data_ravens) - end + if nw==0 - find_conductor_ids!(data_math) - _map_conductor_ids!(data_math) - _map_settings_vbases_default!(data_math) + data_math["map"] = Vector{Dict{String,Any}}([ + Dict{String,Any}("unmap_function" => "_map_math2ravens_root!") + ]) + + _init_base_components!(data_math) + + ## TODO + # for property in get(ravens2math_passthrough, "root", String[]) + # if haskey(data_ravens, property) + # data_math[property] = deepcopy(data_ravens[property]) + # end + # end + + for type in pmd_ravens_asset_types + getfield(PowerModelsDistribution, Symbol("_map_ravens2math_$(type)!"))(data_math, data_ravens; pass_props=get(ravens2math_passthrough, type, String[])) + end + + # Custom ravens2math transformation functions + for ravens2math_func! in ravens2math_extensions + ravens2math_func!(data_math, data_ravens) + end + + find_conductor_ids!(data_math) + _map_conductor_ids!(data_math) + _map_settings_vbases_default!(data_math) + + else + + data_math[string(nw)]["map"] = Vector{Dict{String,Any}}([ + Dict{String,Any}("unmap_function" => "_map_math2ravens_root!") + ]) + + _init_base_components!(data_math[string(nw)]) + + ## TODO + # for property in get(ravens2math_passthrough, "root", String[]) + # if haskey(data_ravens, property) + # data_math[property] = deepcopy(data_ravens[property]) + # end + # end + + for type in pmd_ravens_asset_types + getfield(PowerModelsDistribution, Symbol("_map_ravens2math_$(type)!"))(data_math[string(nw)], data_ravens; pass_props=get(ravens2math_passthrough, type, String[]), nw=nw) + end + + # Custom ravens2math transformation functions + for ravens2math_func! in ravens2math_extensions + ravens2math_func!(data_math[string(nw)], data_ravens) + end + + find_conductor_ids!(data_math[string(nw)]) + _map_conductor_ids!(data_math[string(nw)]) + _map_settings_vbases_default!(data_math[string(nw)]) + + end end @@ -161,7 +236,7 @@ end """ Converts ravens connectivity_node components into mathematical bus components. """ -function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) +function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) voltage_scale_factor_sqrt3 = data_math["settings"]["voltage_scale_factor"] * sqrt(3) connectivity_nodes = get(data_ravens, "ConnectivityNode", Dict{String,Any}()) @@ -206,7 +281,7 @@ end """ Converts ravens conductors (e.g., ACLineSegments) into mathematical branches. """ -function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) +function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) conductors = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["Conductor"] for (name, ravens_obj) in get(conductors, "ACLineSegment", Dict{Any,Dict{String,Any}}()) @@ -276,7 +351,7 @@ end # TODO: Transformers need a lot of changes/refactors!!! "converts ravens n-winding transformers into mathematical ideal 2-winding lossless transformer branches and impedance branches to represent the loss model" -function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) +function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"] power_scale_factor = data_math["settings"]["power_scale_factor"] @@ -467,7 +542,7 @@ end """ Converts ravens load components into mathematical load components. """ -function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) +function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) energy_connections = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] power_scale_factor = data_math["settings"]["power_scale_factor"] voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] @@ -502,9 +577,41 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r math_obj["model"] = POWER end - # Set p and q - math_obj["pd"] = [ravens_obj["EnergyConsumer.p"] / power_scale_factor] - math_obj["qd"] = [ravens_obj["EnergyConsumer.q"] / power_scale_factor] + # Set p and q (w/ multinetwork support) + + if nw==0 + math_obj["pd"] = [ravens_obj["EnergyConsumer.p"] / power_scale_factor] + math_obj["qd"] = [ravens_obj["EnergyConsumer.q"] / power_scale_factor] + else + + # Get timeseries schedule + if haskey(ravens_obj, "EnergyConsumer.LoadForecast") + schdl_name = _extract_name(ravens_obj["EnergyConsumer.LoadForecast"]) + schdl = data_ravens["BasicIntervalSchedule"][schdl_name] + + # TODO: Define other types of timeseries (e.g., multipliers, etc.) + # units and multiplier modifiers + value1_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value1Multiplier"]] + value2_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value2Multiplier"]] + value1_unit = schdl["BasicIntervalSchedule.value1Unit"] + value2_unit = schdl["BasicIntervalSchedule.value2Unit"] + + if value1_unit == "W" + math_obj["pd"] = [schdl["EnergyConsumerSchedule.RegularTimePoints"][nw]["RegularTimePoint.value1"] * value1_multiplier / power_scale_factor] + end + if value1_unit == "VAr" + math_obj["qd"] = [schdl["EnergyConsumerSchedule.RegularTimePoints"][nw]["RegularTimePoint.value1"] * value1_multiplier / power_scale_factor] + end + if value2_unit == "W" + math_obj["pd"] = [schdl["EnergyConsumerSchedule.RegularTimePoints"][nw]["RegularTimePoint.value2"] * value2_multiplier / power_scale_factor] + end + if value2_unit == "VAr" + math_obj["qd"] = [schdl["EnergyConsumerSchedule.RegularTimePoints"][nw]["RegularTimePoint.value2"] * value2_multiplier / power_scale_factor] + end + else + @error("No timeseries, load forecast or multinetwork information found!") + end + end # Set the nominal voltage base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) @@ -597,7 +704,7 @@ end """ Converts ravens voltage sources into mathematical generators and (if needed) impedance branches to represent the loss model. """ -function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) +function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) energy_connections = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] voltage_scale_factor = data_math["settings"]["voltage_scale_factor"] voltage_scale_factor_sqrt3 = voltage_scale_factor * sqrt(3) @@ -734,7 +841,7 @@ end "converts engineering generators into mathematical generators" -function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) +function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) energy_connections = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] if haskey(energy_connections, "RegulatingCondEq") @@ -823,7 +930,7 @@ end "converts ravens power_electronics units such as PVs and Batteries into mathematical components" -function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) +function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) energy_connections = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] if haskey(energy_connections, "RegulatingCondEq") @@ -995,7 +1102,7 @@ end "converts ravens switches into mathematical switches and (if neeed) impedance branches to represent loss model" -function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) +function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) conducting_equipment = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"] for (name, ravens_obj) in get(conducting_equipment, "Switch", Dict{Any,Dict{String,Any}}()) @@ -1074,7 +1181,7 @@ end "converts ravens generic shunt components into mathematical shunt components" -function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[]) +function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) energy_connections = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["EnergyConnection"] if haskey(energy_connections, "RegulatingCondEq") diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 7091e60ae..f3e2e688f 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -9,6 +9,22 @@ const _phasecode_map = Dict( ) +const _multipliers_map = Dict( + "m" => 1e-3, + "c" => 1e-2, + "d" => 1e-1, + "da" => 1e1, + "h" => 1e2, + "k" => 1e3, + "M" => 1e6, + "G" => 1e9, + "T" => 1e12, + "P" => 1e15, + "E" => 1e18, + "Z" => 1e21 +) + + "initializes the base math object of any type" function _init_math_obj_ravens(obj_type::String, eng_id::Any, eng_obj::Dict{String,<:Any}, index::Int; pass_props::Vector{String}=String[])::Dict{String,Any} math_obj = Dict{String,Any}( diff --git a/src/io/common.jl b/src/io/common.jl index 6df3b742d..6a8a72252 100644 --- a/src/io/common.jl +++ b/src/io/common.jl @@ -105,22 +105,22 @@ function parse_file( ) end elseif filetype == "json" - if multinetwork && !ismultinetwork(pmd_data) - pmd_data = make_multinetwork(pmd_data; global_keys=global_keys) - end - if data_model == MATHEMATICAL && !ismath(pmd_data) - pmd_data = transform_data_model(pmd_data; - make_pu=make_pu, - make_pu_extensions=make_pu_extensions, - kron_reduce=kron_reduce, - phase_project=phase_project, - multinetwork=multinetwork, - global_keys=global_keys, - eng2math_extensions=eng2math_extensions, - eng2math_passthrough=eng2math_passthrough, - ) - end + ## TODO: may not be needed + # if data_model == MATHEMATICAL && !ismath(pmd_data) + # pmd_data = transform_data_model(pmd_data; + # make_pu=make_pu, + # make_pu_extensions=make_pu_extensions, + # kron_reduce=kron_reduce, + # phase_project=phase_project, + # multinetwork=multinetwork, + # global_keys=global_keys, + # eng2math_extensions=eng2math_extensions, + # eng2math_passthrough=eng2math_passthrough, + # ) + # end + + else error("only .dss and .json files are supported") end diff --git a/src/prob/common.jl b/src/prob/common.jl index 3ab55c1f6..1d0145694 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -138,7 +138,7 @@ function instantiate_mc_model_ravens( model_type::Type, build_method::Function; ref_extensions::Vector{<:Function}=Function[], - multinetwork::Bool=ismultinetwork(data), + multinetwork::Bool=false, global_keys::Set{String}=Set{String}(), ravens2math_extensions::Vector{<:Function}=Function[], ravens2math_passthrough::Dict{String,<:Vector{<:String}}=Dict{String,Vector{String}}(), diff --git a/test/data/ravens/ravens_case3_withgens_mn.json b/test/data/ravens/ravens_case3_withgens_mn.json new file mode 100644 index 000000000..e1eb5c059 --- /dev/null +++ b/test/data/ravens/ravens_case3_withgens_mn.json @@ -0,0 +1,737 @@ +{ + "PerLengthLineParameter": { + "PerLengthImpedance": { + "PerLengthPhaseImpedance": { + "4/0quad": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "88bc7e59-e9ce-4600-a949-3e2cecbc2fda", + "IdentifiedObject.name": "4/0quad", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + } + ] + }, + "556mcm": { + "Ravens.CimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "d6879f7a-124f-4e82-987a-46f5ba3e2f9d", + "IdentifiedObject.name": "556mcm", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.CimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + } + ] + } + } + } + }, + "PowerSystemResource": { + "Equipment": { + "ConductingEquipment": { + "EnergyConnection": { + "RegulatingCondEq": { + "RotatingMachine": { + "gen2": { + "Ravens.CimObjectType": "SynchronousMachine", + "IdentifiedObject.mRID": "c657d8a1-32c2-402f-8403-9b06c112318a", + "IdentifiedObject.name": "gen2", + "RotatingMachine.p": 1000.0, + "RotatingMachine.q": 484.3221048378525, + "RotatingMachine.ratedS": 1200.0, + "RotatingMachine.ratedU": 461.88021535170066, + "Equipment.inService": "true", + "RotatingMachine.ratedPowerFactor": 0.9, + "GeneratingUnit.minOperatingP": 0.0, + "GeneratingUnit.maxOperatingP": 1080.0, + "SynchronousMachine.maxQ": 523.0678732248807, + "SynchronousMachine.minQ": -523.0678732248807, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "012eb2d2-f4d8-4cc9-825f-b634c66e5d84", + "IdentifiedObject.name": "gen2_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + } + ] + }, + "gen1": { + "Ravens.CimObjectType": "SynchronousMachine", + "IdentifiedObject.mRID": "3f2267a8-4f0c-4ac5-9415-8568d7d414b2", + "IdentifiedObject.name": "gen1", + "RotatingMachine.p": 2000.0, + "RotatingMachine.q": 968.644209675705, + "RotatingMachine.ratedS": 2400.0, + "RotatingMachine.ratedU": 461.88021535170066, + "Equipment.inService": "true", + "RotatingMachine.ratedPowerFactor": 0.9, + "GeneratingUnit.minOperatingP": 0.0, + "GeneratingUnit.maxOperatingP": 2160.0, + "SynchronousMachine.maxQ": 1046.1357464497614, + "SynchronousMachine.minQ": -1046.1357464497614, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "20cd756e-faae-47d9-a177-b605e6ae55fb", + "IdentifiedObject.name": "gen1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ] + } + } + }, + "EnergySource": { + "source": { + "Ravens.CimObjectType": "EnergySource", + "IdentifiedObject.mRID": "494c011a-7640-4ed7-a3d5-2cd1a55413c0", + "IdentifiedObject.name": "source", + "EnergySource.nominalVoltage": 400.0, + "EnergySource.voltageMagnitude": 398.36, + "EnergySource.voltageAngle": 0.0, + "EnergySource.r": 3.880570000581328e-08, + "EnergySource.x": 1.5522280002325312e-07, + "EnergySource.r0": 5.069596039676399e-08, + "EnergySource.x0": 1.5208788119029196e-07, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "327a6ba6-06c2-40ff-a0cc-550dd50d824d", + "IdentifiedObject.name": "source_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + } + ] + } + }, + "EnergyConsumer": { + "l2": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "f227af26-b8ae-47b3-97cc-4d1e5d6bbfd3", + "IdentifiedObject.name": "l2", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadForecast": "EnergyConsumerSchedule::'load_shape'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "9f8d612e-85f8-4757-9ff8-f9ae5947ddd8", + "IdentifiedObject.name": "l2_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.B", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "f3cd189c-bd31-4fd4-beed-8967142aa0ea", + "IdentifiedObject.name": "l2_B", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.B" + } + ] + }, + "l1": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "8bff0407-deee-4f99-92fa-1dee4047621e", + "IdentifiedObject.name": "l1", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadForecast": "EnergyConsumerSchedule::'load_shape'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "4c93404d-1381-4fb2-b2db-36da5d6a0583", + "IdentifiedObject.name": "l1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.A", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "d4f8dc3a-8a95-4361-968a-1d841de4d7d1", + "IdentifiedObject.name": "l1_A", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.A" + } + ] + }, + "l3": { + "Ravens.CimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "f8e9430c-56a5-44c3-8b53-98464182dec3", + "IdentifiedObject.name": "l3", + "EnergyConsumer.p": 6000.0, + "EnergyConsumer.q": 3000.0, + "EnergyConsumer.customerCount": 1, + "EnergyConsumer.grounded": "true", + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadForecast": "EnergyConsumerSchedule::'load_shape'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "ec5de9d0-8f3a-409c-afaa-5dd15969842f", + "IdentifiedObject.name": "l3_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.C", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.CimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "cdb85d03-72cd-4c1a-aa27-ee985895d65c", + "IdentifiedObject.name": "l3_C", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.C" + } + ] + } + } + }, + "Conductor": { + "ACLineSegment": { + "ohline": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "357e3f68-a996-4ef9-8e29-5a9701da50f5", + "IdentifiedObject.name": "ohline", + "Conductor.length": 1.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "262a28c0-79c8-46f8-be2f-48baba94b09b", + "IdentifiedObject.name": "ohline_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "20c1e2b3-faab-4f16-9d28-1438cf5adc31", + "IdentifiedObject.name": "ohline_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + } + ], + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "43a9f788-638f-48c5-9211-437795fad9da", + "IdentifiedObject.name": "ohline_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "939db8dd-1631-44e8-aa9d-cb391f06136d", + "IdentifiedObject.name": "ohline_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "8a764636-52d0-470f-abcd-9cee75f114de", + "IdentifiedObject.name": "ohline_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ] + }, + "quad": { + "Ravens.CimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "b0c876f2-8724-4b1d-9bb8-16ad6dc08866", + "IdentifiedObject.name": "quad", + "Conductor.length": 1.0, + "Equipment.inService": "true", + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", + "ConductingEquipment.Terminals": [ + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "fba92277-7b25-42e3-8782-10e01ebf3ccf", + "IdentifiedObject.name": "quad_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + }, + { + "Ravens.CimObjectType": "Terminal", + "IdentifiedObject.mRID": "7a7bd627-5599-4139-bd71-a659a313fafc", + "IdentifiedObject.name": "quad_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + } + ], + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "06ccbe19-290d-4808-8edb-40afc7e7c41e", + "IdentifiedObject.name": "quad_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "79df9209-3379-4ce7-bd5b-2f927daccd8a", + "IdentifiedObject.name": "quad_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.CimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "27dfc4e3-829a-4c4a-abb2-dab081e599c7", + "IdentifiedObject.name": "quad_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ] + } + } + } + } + } + }, + "OperationalLimitSet": { + "OpLimV_360.00000000000006-440.00000000000006": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "1fd3801e-4bc9-4995-a833-b8a934a51856", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "e2cbc64e-5a29-4df5-b214-f9ed9aa5cb5d", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAlow", + "VoltageLimit.value": 360.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "27d3baf8-3d5e-4465-9e84-3e52708211f1", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAhigh", + "VoltageLimit.value": 440.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + } + ] + }, + "OpLimV_380.0-420.00000000000006": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "35e30ea0-641e-43b7-a1e4-0e15e42334e1", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "cce047bb-3dc5-4f08-85ae-401c93562f34", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAhigh", + "VoltageLimit.value": 420.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + }, + { + "Ravens.CimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "88c7ce0d-859b-4dda-bb25-64d33ba36831", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAlow", + "VoltageLimit.value": 380.0, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + } + ] + }, + "OpLimI_400.0_600.0": { + "Ravens.CimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "47ba5a2e-b0e0-469d-b456-b74d90a89598", + "IdentifiedObject.name": "OpLimI_400.0_600.0", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "ce6d7dcd-e426-44cb-ab33-9e8a6de1b60f", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", + "CurrentLimit.value": 600.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" + }, + { + "Ravens.CimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "a301065e-a50e-4dd7-856b-c7035e9ea52f", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", + "CurrentLimit.value": 400.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" + } + ] + } + }, + "Location": { + "primary_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "db2f0d86-da66-46ac-adc1-6eec717cf555", + "IdentifiedObject.name": "primary_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + }, + "loadbus_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "76056310-0c84-49e6-9d92-c0a3cce574e4", + "IdentifiedObject.name": "loadbus_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + }, + "sourcebus_Location": { + "Ravens.CimObjectType": "Location", + "IdentifiedObject.mRID": "4c73c3dd-7250-4f6a-af69-d203960b0a34", + "IdentifiedObject.name": "sourcebus_Location", + "Location.PositionPoints": [ + { + "Ravens.CimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 1, + "PositionPoint.xPosition": 0.0, + "PositionPoint.yPosition": 0.0 + } + ] + } + }, + "Versions": { + "IEC61970CIMVersion": { + "Ravens.CimObjectType": "IEC61970CIMVersion", + "IEC61970CIMVersion.version": "IEC61970CIM100", + "IEC61970CIMVersion.date": "2019-04-01" + } + }, + "ConnectivityNode": { + "loadbus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "4ac8da05-a223-4bf6-b372-12c9479c495a", + "IdentifiedObject.name": "loadbus", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_360.00000000000006-440.00000000000006'" + }, + "primary": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "3e877b8a-ef33-4e18-8c80-1b05050bfc40", + "IdentifiedObject.name": "primary", + "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_360.00000000000006-440.00000000000006'" + }, + "sourcebus": { + "Ravens.CimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "d192d550-1fc0-489f-8e47-72209fa989e7", + "IdentifiedObject.name": "sourcebus" + } + }, + "OperationalLimitType": { + "absoluteValueType_86400.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "d60da1eb-6a60-41ba-99df-7313cad312fa", + "IdentifiedObject.name": "absoluteValueType_86400.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 86400.0 + }, + "highType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "a1a82ad0-e426-4ecb-816a-5a58f034756b", + "IdentifiedObject.name": "highType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "lowType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "1eaf0044-6272-4146-bf43-5c5310023469", + "IdentifiedObject.name": "lowType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "absoluteValueType_5000000000.0s": { + "Ravens.CimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "1a39544c-2df7-46a9-a6c0-cfb28ab6eaab", + "IdentifiedObject.name": "absoluteValueType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 5000000000.0 + } + }, + "LoadResponseCharacteristic": { + "Constant kVA": { + "Ravens.CimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "777f5c7c-dea1-4a88-8db0-e5bd71a2fd4b", + "IdentifiedObject.name": "Constant kVA", + "LoadResponseCharacteristic.pConstantPower": 100, + "LoadResponseCharacteristic.qConstantPower": 100 + } + }, + "BaseVoltage": { + "BaseV_0.4": { + "Ravens.CimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "93c27318-44cd-41b7-a873-f9001d1b831f", + "IdentifiedObject.name": "BaseV_0.4", + "BaseVoltage.nominalVoltage": 400.0 + } + }, + "BasicIntervalSchedule": { + "load_shape": { + "EnergyConsumerSchedule.startDay": "Monday", + "BasicIntervalSchedule.value2Multiplier": "k", + "BasicIntervalSchedule.value1Multiplier": "k", + "Ravens.cimObjectType": "EnergyConsumerSchedule", + "BasicIntervalSchedule.value2Unit": "VAr", + "BasicIntervalSchedule.value1Unit": "W", + "EnergyConsumerSchedule.RegularTimePoints": [ + { + "RegularTimePoint.sequenceNumber": 1, + "RegularTimePoint.value2": 2.85, + "RegularTimePoint.value1": 6.0 + }, + { + "RegularTimePoint.sequenceNumber": 2, + "RegularTimePoint.value2": 3.19, + "RegularTimePoint.value1": 6.5 + }, + { + "RegularTimePoint.sequenceNumber": 3, + "RegularTimePoint.value2": 2.85, + "RegularTimePoint.value1": 6.0 + }, + { + "RegularTimePoint.sequenceNumber": 4, + "RegularTimePoint.value2": 2.90, + "RegularTimePoint.value1": 5.7 + }, + { + "RegularTimePoint.sequenceNumber": 5, + "RegularTimePoint.value2": 3.10, + "RegularTimePoint.value1": 6.8 + }, + { + "RegularTimePoint.sequenceNumber": 6, + "RegularTimePoint.value2": 2.95, + "RegularTimePoint.value1": 5.9 + }, + { + "RegularTimePoint.sequenceNumber": 7, + "RegularTimePoint.value2": 3.01, + "RegularTimePoint.value1": 6.1 + }, + { + "RegularTimePoint.sequenceNumber": 8, + "RegularTimePoint.value2": 2.89, + "RegularTimePoint.value1": 7.0 + }, + { + "RegularTimePoint.sequenceNumber": 9, + "RegularTimePoint.value2": 3.18, + "RegularTimePoint.value1": 5.6 + }, + { + "RegularTimePoint.sequenceNumber": 10, + "RegularTimePoint.value2": 2.94, + "RegularTimePoint.value1": 7.8 + }, + { + "RegularTimePoint.sequenceNumber": 11, + "RegularTimePoint.value2": 3.05, + "RegularTimePoint.value1": 5.4 + }, + { + "RegularTimePoint.sequenceNumber": 12, + "RegularTimePoint.value2": 2.88, + "RegularTimePoint.value1": 7.3 + }, + { + "RegularTimePoint.sequenceNumber": 13, + "RegularTimePoint.value2": 3.02, + "RegularTimePoint.value1": 6.5 + }, + { + "RegularTimePoint.sequenceNumber": 14, + "RegularTimePoint.value2": 2.92, + "RegularTimePoint.value1": 7.2 + }, + { + "RegularTimePoint.sequenceNumber": 15, + "RegularTimePoint.value2": 3.00, + "RegularTimePoint.value1": 5.8 + }, + { + "RegularTimePoint.sequenceNumber": 16, + "RegularTimePoint.value2": 2.98, + "RegularTimePoint.value1": 7.4 + }, + { + "RegularTimePoint.sequenceNumber": 17, + "RegularTimePoint.value2": 3.03, + "RegularTimePoint.value1": 5.9 + }, + { + "RegularTimePoint.sequenceNumber": 18, + "RegularTimePoint.value2": 2.91, + "RegularTimePoint.value1": 7.1 + }, + { + "RegularTimePoint.sequenceNumber": 19, + "RegularTimePoint.value2": 3.06, + "RegularTimePoint.value1": 5.7 + }, + { + "RegularTimePoint.sequenceNumber": 20, + "RegularTimePoint.value2": 2.99, + "RegularTimePoint.value1": 6.0 + }, + { + "RegularTimePoint.sequenceNumber": 21, + "RegularTimePoint.value2": 3.08, + "RegularTimePoint.value1": 5.6 + }, + { + "RegularTimePoint.sequenceNumber": 22, + "RegularTimePoint.value2": 2.97, + "RegularTimePoint.value1": 7.0 + }, + { + "RegularTimePoint.sequenceNumber": 23, + "RegularTimePoint.value2": 3.09, + "RegularTimePoint.value1": 5.8 + }, + { + "RegularTimePoint.sequenceNumber": 24, + "RegularTimePoint.value2": 2.96, + "RegularTimePoint.value1": 7.2 + } + ], + "IdentifiedObject.mRID": "95941138-5523-4e82-9ffa-d19e6f6acf70", + "EnergyConsumerSchedule.timeStep": 3600 + } + } +} diff --git a/test/opf_ravens.jl b/test/opf_ravens.jl index 4b8a80484..eacd32e8a 100644 --- a/test/opf_ravens.jl +++ b/test/opf_ravens.jl @@ -67,4 +67,16 @@ # ) # @test result["termination_status"] == LOCALLY_SOLVED # end + + @testset "ravens case 3 with gens multinetwork" begin + pmd_model = instantiate_mc_model_ravens(ravens_case3_withgens_mn, ACPUPowerModel, build_mn_mc_opf; multinetwork=true) + result = optimize_model!( + pmd_model, + relax_integrality=false, + optimizer=ipopt_solver, + solution_processors=Function[] + ) + @test result["termination_status"] == LOCALLY_SOLVED + end + end diff --git a/test/test_cases.jl b/test/test_cases.jl index a6a476a9a..3ff2c6436 100644 --- a/test/test_cases.jl +++ b/test/test_cases.jl @@ -76,3 +76,4 @@ ravens_case3_withsubxf = parse_file("../test/data/ravens/ravens_case3_withsubxf. ravens_case3_withcap = parse_file("../test/data/ravens/ravens_case3_withcap.json") ravens_test_switch_3w = parse_file("../test/data/ravens/ravens_test_switch_3w.json") # ravens_test_switch_1w = parse_file("../test/data/ravens/ravens_test_switch_1w.json") +ravens_case3_withgens_mn = parse_file("../test/data/ravens/ravens_case3_withgens_mn.json") From ba64f3be085d587b4a94a69afed97e67c824bf55 Mon Sep 17 00:00:00 2001 From: Juan Ospina Date: Wed, 26 Feb 2025 14:07:15 -0700 Subject: [PATCH 28/99] ADD: TransformerTank support and minor modeling fixes (#3) * WIP: TransformerTanks support. Adding them individually connected to the same fbus is giving errors. * WIP: new version of TransformerTank. Plus - Important Fixes to Conductors, Switches, and EnergySource. * REF: TransformerTanks but as Single-Phase entities. * REF: TransformerTanks per single phase to avoid extra winding/tank loop. * FIX: resistance and reactance for Transformers computations - single-phase * REF: configuration and polarity of transformers based on connections DELTA-WYE, etc. * REF: PowerTransformerEnd to avoid unnecessary calculations and clean code. * REF: TransformerTank parsing. * ADD: feature to combine TransformerTanks into a single transformer mathematical representation. --- src/data_model/transformations/eng2math.jl | 12 + src/data_model/transformations/ravens2math.jl | 873 ++++++++++++++---- src/prob/common.jl | 16 +- 3 files changed, 707 insertions(+), 194 deletions(-) diff --git a/src/data_model/transformations/eng2math.jl b/src/data_model/transformations/eng2math.jl index f82208778..caed4ce4a 100644 --- a/src/data_model/transformations/eng2math.jl +++ b/src/data_model/transformations/eng2math.jl @@ -476,10 +476,19 @@ function _map_eng2math_transformer!(data_math::Dict{String,<:Any}, data_eng::Dic g_sh = g_sh*ratios[1]^2 b_sh = b_sh*ratios[1]^2 + @info "---- NAME --- : $(name)" + @info "RS: $(r_s)" + @info "XSC: $(x_sc)" + @info "GSH: $(g_sh)" + @info "BSH: $(b_sh)" + # convert x_sc from list of upper triangle elements to an explicit dict y_sh = g_sh + im*b_sh z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) + @info "$(y_sh)" + @info "$(z_sc)" + dims = length(eng_obj["tm_set"][1]) transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh,eng_obj["connections"][1]; nphases=dims, status=Int(eng_obj["status"] == ENABLED)) @@ -487,6 +496,9 @@ function _map_eng2math_transformer!(data_math::Dict{String,<:Any}, data_eng::Dic # 2-WINDING TRANSFORMER # make virtual bus and mark it for reduction tm_nom = eng_obj["configuration"][w]==DELTA ? eng_obj["vm_nom"][w]*sqrt(3) : eng_obj["vm_nom"][w] + + @info "TM_NOM: $(tm_nom)" + transformer_2wa_obj = Dict{String,Any}( "name" => "_virtual_transformer.$name.$w", "source_id" => "_virtual_transformer.$(eng_obj["source_id"]).$w", diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 045a98ddc..3dbb8ab7b 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -282,68 +282,72 @@ end Converts ravens conductors (e.g., ACLineSegments) into mathematical branches. """ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) - conductors = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["Conductor"] - for (name, ravens_obj) in get(conductors, "ACLineSegment", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj_ravens("ac_line_segment", name, ravens_obj, length(data_math["branch"]) + 1; pass_props=pass_props) + if haskey(data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"], "Conductor") + conductors = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["Conductor"] - nphases = length(ravens_obj["ACLineSegment.ACLineSegmentPhase"]) - terminals = ravens_obj["ConductingEquipment.Terminals"] + for (name, ravens_obj) in get(conductors, "ACLineSegment", Dict{Any,Dict{String,Any}}()) + math_obj = _init_math_obj_ravens("ac_line_segment", name, ravens_obj, length(data_math["branch"]) + 1; pass_props=pass_props) - f_node = _extract_name(terminals[1]["Terminal.ConnectivityNode"]) - t_node = _extract_name(terminals[2]["Terminal.ConnectivityNode"]) + nphases = length(ravens_obj["ACLineSegment.ACLineSegmentPhase"]) + terminals = ravens_obj["ConductingEquipment.Terminals"] - math_obj["f_bus"] = data_math["bus_lookup"][f_node] - math_obj["t_bus"] = data_math["bus_lookup"][t_node] + f_node = _extract_name(terminals[1]["Terminal.ConnectivityNode"]) + t_node = _extract_name(terminals[2]["Terminal.ConnectivityNode"]) - phase_map = Dict("SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, "SinglePhaseKind.C" => 3) - bus_terminals = nphases >= 3 ? collect(1:nphases) : [phase_map[phase["ACLineSegmentPhase.phase"]] for phase in ravens_obj["ACLineSegment.ACLineSegmentPhase"]] + math_obj["f_bus"] = data_math["bus_lookup"][f_node] + math_obj["t_bus"] = data_math["bus_lookup"][t_node] - for bus in [math_obj["f_bus"], math_obj["t_bus"]] - data_math["bus"][string(bus)]["terminals"] = bus_terminals - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - end + phase_map = Dict("SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, "SinglePhaseKind.C" => 3) + bus_terminals = nphases >= 3 ? collect(1:nphases) : [phase_map[phase["ACLineSegmentPhase.phase"]] for phase in ravens_obj["ACLineSegment.ACLineSegmentPhase"]] - math_obj["f_connections"] = bus_terminals - math_obj["t_connections"] = bus_terminals + for bus in [math_obj["f_bus"], math_obj["t_bus"]] + data_math["bus"][string(bus)]["terminals"] = bus_terminals + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + end - impedance_name = _extract_name(ravens_obj["ACLineSegment.PerLengthImpedance"]) - impedance_data = data_ravens["PerLengthLineParameter"]["PerLengthImpedance"]["PerLengthPhaseImpedance"][impedance_name] + math_obj["f_connections"] = bus_terminals + math_obj["t_connections"] = bus_terminals - math_obj["br_r"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.r") - math_obj["br_x"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.x") + impedance_name = _extract_name(ravens_obj["ACLineSegment.PerLengthImpedance"]) + impedance_data = data_ravens["PerLengthLineParameter"]["PerLengthImpedance"]["PerLengthPhaseImpedance"][impedance_name] - base_freq = data_math["settings"]["base_frequency"] - for (key, param) in [("b_fr", "PhaseImpedanceData.b"), ("b_to", "PhaseImpedanceData.b"), ("g_fr", "PhaseImpedanceData.g"), ("g_to", "PhaseImpedanceData.g")] - math_obj[key] = _admittance_conversion_ravens(impedance_data, ravens_obj, param; freq=base_freq) - end + math_obj["br_r"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.r") + math_obj["br_x"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.x") - math_obj["angmin"] = get(ravens_obj, "vad_lb", fill(-60.0, nphases)) - math_obj["angmax"] = get(ravens_obj, "vad_ub", fill(60.0, nphases)) + base_freq = data_math["settings"]["base_frequency"] + for (key, param) in [("b_fr", "PhaseImpedanceData.b"), ("b_to", "PhaseImpedanceData.b"), ("g_fr", "PhaseImpedanceData.g"), ("g_to", "PhaseImpedanceData.g")] + math_obj[key] = _admittance_conversion_ravens(impedance_data, ravens_obj, param; freq=base_freq) + end - if (haskey(terminals[1], "ACDCTerminal.OperationalLimitSet")) - oplimitset_id = _extract_name(terminals[1]["ACDCTerminal.OperationalLimitSet"]) - oplimitset = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][2] - else - oplimitset = Dict() - end + math_obj["angmin"] = get(ravens_obj, "vad_lb", fill(-60.0, nphases)) + math_obj["angmax"] = get(ravens_obj, "vad_ub", fill(60.0, nphases)) - limit_keys = [("CurrentLimit.value", "c_rating_a"), ("CurrentLimit.value", "c_rating_b"), ("CurrentLimit.value", "c_rating_c"), - ("ApparentPowerLimit.value", "rate_a"), ("ApparentPowerLimit.value", "rate_b"), ("ApparentPowerLimit.value", "rate_c")] + if (haskey(terminals[1], "ACDCTerminal.OperationalLimitSet")) + oplimitset_id = _extract_name(terminals[1]["ACDCTerminal.OperationalLimitSet"]) + oplimitset = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][2] + else + oplimitset = Dict() + end - for (f_key, t_key) in limit_keys - math_obj[t_key] = haskey(oplimitset, f_key) ? fill(oplimitset[f_key], nphases) : fill(Inf, nphases) - end + limit_keys = [("CurrentLimit.value", "c_rating_a"), ("CurrentLimit.value", "c_rating_b"), ("CurrentLimit.value", "c_rating_c"), + ("ApparentPowerLimit.value", "rate_a"), ("ApparentPowerLimit.value", "rate_b"), ("ApparentPowerLimit.value", "rate_c")] - math_obj["br_status"] = get(ravens_obj, "Equipment.inService", "true") == "true" ? 1 : 0 - data_math["branch"]["$(math_obj["index"])"] = math_obj + for (f_key, t_key) in limit_keys + math_obj[t_key] = haskey(oplimitset, f_key) ? fill(oplimitset[f_key], nphases) : fill(Inf, nphases) + end - push!(data_math["map"], Dict{String,Any}( - "from" => name, - "to" => "branch.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_line!", - )) + math_obj["br_status"] = get(ravens_obj, "Equipment.inService", "true") == "true" ? 1 : 0 + data_math["branch"]["$(math_obj["index"])"] = math_obj + + push!(data_math["map"], Dict{String,Any}( + "from" => name, + "to" => "branch.$(math_obj["index"])", + "unmap_function" => "_map_math2ravens_line!", + )) + + end end end @@ -369,171 +373,639 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data to_map = data_math["map"][end]["to"] - # Get nrw: number of windings - wdgs = ravens_obj["PowerTransformer.PowerTransformerEnd"] - nrw = length(wdgs) - - # Loop through Windings - wdg1_data = 0 - wdg2_data = 0 - wdgN_data = 0 - # connections - connections = Vector{Int64}[] - # Nodes - f_node = "" - t_node = "" - - for wdg in wdgs - - # wdg phasecode - wdg_terminals = wdg["ConductingEquipment.Terminals"][1] - wdg_phasecode = wdg_terminals["Terminal.phases"] - - # Connections (based on _phasecode_map) - if haskey(_phasecode_map, wdg_phasecode) - push!(connections, _phasecode_map[wdg_phasecode]) - else - @error("PhaseCode not supported yet!") - end + if haskey(ravens_obj, "PowerTransformer.PowerTransformerEnd") + + # Get nrw: number of windings + wdgs = ravens_obj["PowerTransformer.PowerTransformerEnd"] + nrw = length(wdgs) + + # connections + connections = Vector{Vector{Int64}}(undef, nrw) + + # configurations + wdgs_confs = Vector{ConnConfig}(undef, nrw) + + # Transformer data for each winding + vnom = Vector{Float64}(undef, nrw) + snom = Vector{Float64}(undef, nrw) + zbase = Vector{Float64}(undef, nrw) + x_sc = Vector{Float64}(undef, nrw) + r_s = Vector{Float64}(undef, nrw) + g_sh = zeros(Float64, nrw) + b_sh = zeros(Float64, nrw) + + # Regulator set init + tm_set = Vector{Vector{Float64}}(undef, nrw) + tm_lb = Vector{Vector{Float64}}(undef, nrw) + tm_ub = Vector{Vector{Float64}}(undef, nrw) + tm_fix = Vector{Vector{Bool}}(undef, nrw) + tm_step = Vector{Vector{Float64}}(undef, nrw) + + for wdg_id in 1:nrw + + # wdg phasecode & terminals + wdg_terminals = wdgs[wdg_id]["ConductingEquipment.Terminals"][1] + wdg_phasecode = wdg_terminals["Terminal.phases"] + + # wdg endNumber + wdg_endNumber = wdgs[wdg_id]["TransformerEnd.endNumber"] + + # Connections (based on _phasecode_map) + if haskey(_phasecode_map, wdg_phasecode) + connections[wdg_endNumber] = _phasecode_map[wdg_phasecode] + else + @error("PhaseCode not supported yet!") + end + + # nphases + nphases = length(connections[wdg_endNumber]) + + # add terminals and voltage limits info. if missing + node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) + bus = data_math["bus_lookup"][node] + if !(haskey(data_math["bus"][string(bus)], "terminals")) + data_math["bus"][string(bus)]["terminals"] = connections[wdg_endNumber] + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + end + + # wdgs configurations + if wdgs[wdg_id]["PowerTransformerEnd.connectionKind"] == "WindingConnection.Y" + wdgs_confs[wdg_endNumber] = WYE + elseif wdgs[wdg_id]["PowerTransformerEnd.connectionKind"] == "WindingConnection.D" + wdgs_confs[wdg_endNumber] = DELTA + else + @error("PowerTransformer ConnectionKind not supported yet!") + end + + # Transformer data for each winding + vnom[wdg_id] = wdgs[wdg_id]["PowerTransformerEnd.ratedU"] + snom[wdg_id] = wdgs[wdg_id]["PowerTransformerEnd.ratedS"] + r_s[wdg_id] = wdgs[wdg_id]["PowerTransformerEnd.r"] + if haskey(wdgs[wdg_id], "TransformerEnd.MeshImpedance") + x_sc[wdg_id] = get(wdgs[wdg_id]["TransformerEnd.MeshImpedance"], "TransformerMeshImpedance.x", 0.0) + end + if haskey(wdgs[wdg_id], "TransformerEnd.CoreAdmittance") + g_sh[wdg_id] = get(wdgs[wdg_id]["TransformerEnd.CoreAdmittance"], "TransformerCoreAdmittance.g", 0.0) + b_sh[wdg_id] = - get(wdgs[wdg_id]["TransformerEnd.CoreAdmittance"], "TransformerCoreAdmittance.b", 0.0) + end + + # TODO: RatioTapChanger + if haskey(wdgs[wdg_id], "TransformerEnd.RatioTapChanger") + else # default + tm_set[wdg_id] = fill(1.0, nphases) + tm_lb[wdg_id] = fill(0.9, nphases) + tm_ub[wdg_id] = fill(1.1, nphases) + tm_fix[wdg_id] = ones(Bool, nphases) + tm_step[wdg_id] = fill(1/32, nphases) + end - # wdg endNumber - wdg_endNumber = wdg["TransformerEnd.endNumber"] - - # nphases - nphases = length(connections[1]) - - # Get Winding 1 information & create bus - if wdg_endNumber == 1 - wdg1_data = wdg - f_node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) - f_bus = data_math["bus_lookup"][f_node] - data_math["bus"][string(f_bus)]["terminals"] = connections[wdg_endNumber] - data_math["bus"][string(f_bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(f_bus)]["vmax"] = fill(Inf, nphases) - # Get Winding 2 information & create bus - elseif wdg_endNumber == 2 - wdg2_data = wdg - t_node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) - t_bus= data_math["bus_lookup"][t_node] - data_math["bus"][string(t_bus)]["terminals"] = connections[wdg_endNumber] - data_math["bus"][string(t_bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(t_bus)]["vmax"] = fill(Inf, nphases) end - end - # nphases - nphases = length(connections[1]) + # data is measured externally, but we now refer it to the internal side - some values are referred to wdg 1 + ratios = vnom/voltage_scale_factor + x_sc = (x_sc[1]./ratios[1]^2)./100.0 + r_s = r_s./ratios.^2 + g_sh = g_sh[1]*ratios[1]^2 + b_sh = b_sh[1]*ratios[1]^2 - # vnom and snom - vnom = [wdg1_data["PowerTransformerEnd.ratedU"], wdg2_data["PowerTransformerEnd.ratedU"]] - snom = [wdg1_data["PowerTransformerEnd.ratedS"], wdg2_data["PowerTransformerEnd.ratedS"]] + # convert x_sc from list of upper triangle elements to an explicit dict + y_sh = g_sh + im*b_sh + z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) - # calculate zbase in which the data is specified, and convert to SI - zbase = (vnom.^2) ./ snom + # dimesions + dims = length(tm_set[1]) - # x_sc is specified with respect to first winding - x_sc = [wdg1_data["TransformerEnd.MeshImpedance"]["TransformerMeshImpedance.x"]] + # init polarity + polarity = fill(1, nrw) - # rs is specified with respect to each winding - r_s = [wdg1_data["PowerTransformerEnd.r"], wdg2_data["PowerTransformerEnd.r"]] + # Status + status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" + status = status == "true" ? 1 : 0 - g_sh = (wdg1_data["TransformerEnd.CoreAdmittance"]["TransformerCoreAdmittance.g"]) - b_sh = -(wdg1_data["TransformerEnd.CoreAdmittance"]["TransformerCoreAdmittance.b"]) + # Build loss model + transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=dims, status=status) - # data is measured externally, but we now refer it to the internal side - ratios = vnom/voltage_scale_factor - x_sc = x_sc./ratios[1]^2 - r_s = r_s./ratios.^2 - g_sh = g_sh*ratios[1]^2 - b_sh = b_sh*ratios[1]^2 + # Mathematical model for transformer + for wdg_id in 1:nrw - # convert x_sc from list of upper triangle elements to an explicit dict - y_sh = g_sh + im*b_sh - z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) + # 2-WINDING TRANSFORMER + # correct polarity and connections + if wdg_id > 1 + if wdgs_confs[1] == DELTA && wdgs_confs[wdg_id] == WYE + polarity[wdg_id] = -1 + connections[wdg_id] = _barrel_roll(connections[wdg_id][1:end], 1) + end + if wdgs_confs[1] == WYE && wdgs_confs[wdg_id] == DELTA + polarity[wdg_id] = -1 + connections[wdg_id] = _barrel_roll(connections[wdg_id], -1) + end + end - # TODO: RatioTapChanger - if haskey(wdg1_data, "TransformerEnd.RatioTapChanger") || haskey(wdg2_data, "TransformerEnd.RatioTapChanger") - else # default - tm_set = Vector{Vector{Float64}}(fill(fill(1.0, nphases), nrw)) - tm_lb = Vector{Vector{Float64}}(fill(fill(0.9, nphases), nrw)) - tm_ub = Vector{Vector{Float64}}(fill(fill(1.1, nphases), nrw)) - tm_fix = Vector{Vector{Bool}}(fill(ones(Bool, nphases), nrw)) - tm_step = Vector{Vector{Float64}}(fill(fill(1/32, nphases), nrw)) - end + # make virtual bus and mark it for reduction + tm_nom = wdgs_confs[wdg_id]==DELTA ? wdgs[wdg_id]["PowerTransformerEnd.ratedU"]*sqrt(3)/voltage_scale_factor : wdgs[wdg_id]["PowerTransformerEnd.ratedU"]/voltage_scale_factor + + # Get correct f_node for winding + wdg_term = wdgs[wdg_id]["ConductingEquipment.Terminals"][1] + f_node_wdgterm = _extract_name(wdg_term["Terminal.ConnectivityNode"]) + + # Transformer Object + transformer_2wa_obj = Dict{String,Any}( + "name" => "_virtual_transformer.$name.$wdg_id", + "source_id" => "_virtual_transformer.transformer.$name.$wdg_id", + "f_bus" => data_math["bus_lookup"][f_node_wdgterm], + "t_bus" => transformer_t_bus_w[wdg_id], + "tm_nom" => tm_nom, + "f_connections" => connections[wdg_id], + "t_connections" => connections[1], + "configuration" => wdgs_confs[wdg_id], + "polarity" => polarity[wdg_id], + "tm_set" => tm_set[wdg_id], + "tm_fix" => tm_fix[wdg_id], + "sm_ub" => get(wdgs[wdg_id], "PowerTransformerEnd.ratedS", Inf)/power_scale_factor, + "cm_ub" => get(wdgs[wdg_id], "PowerTransformerEnd.ratedI", Inf), + "status" => status, + "index" => length(data_math["transformer"])+1 + ) - dims = length(tm_set[1]) - # TODO: Polarity - polarity = fill(1, nrw) + transformer_2wa_obj["tm_lb"] = tm_lb[wdg_id] + transformer_2wa_obj["tm_ub"] = tm_ub[wdg_id] + transformer_2wa_obj["tm_step"] = tm_step[wdg_id] - # Status - status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" - status = status == "true" ? 1 : 0 + data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj - # Build loss model - transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=dims, status=status) + ## TODO: Regulator Control + # if haskey(eng_obj,"controls") && !all(data_math["transformer"]["$(transformer_2wa_obj["index"])"]["tm_fix"]) + # end - # Mathematical model for transformer - for w in 1:nrw - # 2-WINDING TRANSFORMER + # TODO: Center-Tapped Transformers (3 Windings) + # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start + # end + + push!(to_map, "transformer.$(transformer_2wa_obj["index"])") - # Configuration - if wdgs[w]["PowerTransformerEnd.connectionKind"] == "WindingConnection.Y" - configuration = WYE - elseif wdgs[w]["PowerTransformerEnd.connectionKind"] == "WindingConnection.D" - configuration = DELTA - else - @error("PowerTransformer ConnectionKind not supported yet!") end - # make virtual bus and mark it for reduction - tm_nom = configuration==DELTA ? wdgs[w]["PowerTransformerEnd.ratedU"]*sqrt(3)/voltage_scale_factor : wdgs[w]["PowerTransformerEnd.ratedU"]/voltage_scale_factor - - # Get correct f_node for winding - wdg_term = wdgs[w]["ConductingEquipment.Terminals"][1] - f_node_wdgterm = _extract_name(wdg_term["Terminal.ConnectivityNode"]) - - # Transformer Object - transformer_2wa_obj = Dict{String,Any}( - "name" => "_virtual_transformer.$name.$w", - "source_id" => "_virtual_transformer.transformer.$name.$w", - "f_bus" => data_math["bus_lookup"][f_node_wdgterm], - "t_bus" => transformer_t_bus_w[w], - "tm_nom" => tm_nom, - "f_connections" => connections[w], - "t_connections" => connections[w], - "configuration" => configuration, - "polarity" => polarity[w], - "tm_set" => tm_set[w], - "tm_fix" => tm_fix[w], - "sm_ub" => get(wdgs[w], "PowerTransformerEnd.ratedS", Inf)/power_scale_factor, - "cm_ub" => get(wdgs[w], "PowerTransformerEnd.ratedI", Inf), - "status" => status, - "index" => length(data_math["transformer"])+1 - ) + elseif haskey(ravens_obj, "PowerTransformer.TransformerTank") + + # Get tanks data + tanks = ravens_obj["PowerTransformer.TransformerTank"] + + # TODO: flag for debugging TransformerTanks models + combine_tanks = true + + # Combine tanks into a single transformer model (default) + if (combine_tanks == true) + + # number of tanks + ntanks = length(tanks) + + # TODO: IMPORTANT ASSUMPTIONS + # 1) assume there is at least 1 tank and that all tanks have the same number of windings (i.e., TransformerTankEnds) + # 2) assume the number of phases is equal to the number of tanks + nphases = length(tanks) # assume nphases == ntanks + nrw = length(tanks[1]["TransformerTank.TransformerTankEnd"]) + + # init connections vector for combined transformer windings + connections = [zeros(Int64, nphases) for _ in 1:nrw] + + # init nodes vector for combined transformer windings + nodes = ["" for _ in 1:nrw] + # nodes = [Vector{String}(undef, nphases) for _ in 1:nrw] + + # init rs, x_sc, g_sh, and b_sh data per wdg/tank(phase) + r_s = [zeros(Float64, nphases) for _ in 1:nrw] + x_sc = [zeros(Float64, nphases) for _ in 1:nrw] + g_sh = zeros(Float64, nphases) + b_sh = zeros(Float64, nphases) + + # init sm_ub and cm_ub + sm_ub = zeros(Float64, nrw) + cm_ub = zeros(Float64, nrw) + + # init configuration - default WYE-WYE + configuration = [WYE for _ in 1:nrw] + + # init vnom for all windings + vnom = zeros(Float64, nrw) + + # temp store previous for checking + nodes_prev = [] + configuration_prev = [] + vnom_prev = [] + + for tank_id in 1:ntanks + + # Get wdg data + wdgs = tanks[tank_id]["TransformerTank.TransformerTankEnd"] + + # Tank Asset + tank_asset_name = _extract_name(tanks[tank_id]["PowerSystemResource.AssetDatasheet"]) + tank_asset_data = data_ravens["AssetInfo"]["PowerTransformerInfo"][tank_asset_name] + + for wdg_id in 1:nrw + + # wdg terminals & phasecode + wdg_terminals = wdgs[wdg_id]["ConductingEquipment.Terminals"][1] + wdg_phasecode = wdg_terminals["Terminal.phases"] + + # wdg endNumber + wdg_endNumber = wdgs[wdg_id]["TransformerEnd.endNumber"] + + # from-and-to-nodes for wdgs + nodes[wdg_endNumber] = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) + + # Connections (based on _phasecode_map) + if haskey(_phasecode_map, wdg_phasecode) + phasecode_conns = _phasecode_map[wdg_phasecode] + if !(length(phasecode_conns)>1) + connections[wdg_endNumber][tank_id] = phasecode_conns[1] + else + connections[wdg_endNumber] = phasecode_conns + end + else + @error("PhaseCode not supported yet!") + end + + + # transformer tank end info. + transf_end_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] + vnom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedU"] + snom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedS"] + leak_impedance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] + resistance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.r"] + zbase = (vnom_wdg^2) / snom_wdg + ratios = vnom_wdg/voltage_scale_factor + + # assign vnom_wdg to vnom for transformer + vnom[wdg_endNumber] = vnom_wdg + + # compute r_s, x_sc, g_sh, and b_sh per winding per tank (when needed) + r_s[wdg_endNumber][tank_id] = resistance_wdg # rs is specified with respect to each winding + x_sc[wdg_endNumber][tank_id] = (sqrt((leak_impedance_wdg / zbase)^2 - ((resistance_wdg*100.0 / zbase)*2)^2)/100.0)*zbase + + # data is measured externally, but we now refer it to the internal side + x_sc[wdg_endNumber][tank_id] = (x_sc[wdg_endNumber][tank_id]/ratios^2) + r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios^2 + + # g_sh always with respect to wdg #1 always + if wdg_endNumber == 1 + loss = transf_end_info[1]["TransformerEndInfo.EnergisedEndNoLoadTests"][1]["NoLoadTest.loss"] + g_sh_tank = (loss*snom_wdg)/zbase + exct_current = transf_end_info[1]["TransformerEndInfo.EnergisedEndNoLoadTests"][1]["NoLoadTest.excitingCurrent"] + b_sh_tank = -((sqrt((exct_current)^2 - (loss/(0.01*snom_wdg))^2))/(100.0*zbase)) + + # data is measured externally, but we now refer it to the internal side + g_sh[tank_id] = g_sh_tank*ratios^2 + b_sh[tank_id] = b_sh_tank*ratios^2 + end + + # configuration + conf = transf_end_info[wdg_endNumber]["TransformerEndInfo.connectionKind"] + if conf == "WindingConnection.Y" || conf == "WindingConnection.I" + configuration[wdg_endNumber] = WYE + elseif conf == "WindingConnection.D" + configuration[wdg_endNumber] = DELTA + else + @error("TransformerTank ConnectionKind not supported yet!") + end + + # add sm_ub if greater than existing (assumes the greatest value as the ratings for all phases in wdg) + semerg_wdg = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.emergencyS", Inf) + if semerg_wdg > sm_ub[wdg_endNumber] + sm_ub[wdg_endNumber] = semerg_wdg + end + + # add cm_ub if greater than existing for winding (assumes the greatest value as the ratings for all phases in wdg) + cm_wdg = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.ratedI", Inf) + if cm_wdg > cm_ub[wdg_endNumber] + cm_ub[wdg_endNumber] = cm_wdg + end + + end + + ### --- Consistency checks across tanks --- + # check that nodes are the same after first tank iter + if tank_id != 1 + @assert nodes == nodes_prev "nodes are not the same for all tanks! check ConnectivityNodes." # check if node names are the same as expected + else + nodes_prev = deepcopy(nodes) + end + + # check that configurations across tanks are consistent + if tank_id != 1 + @assert configuration == configuration_prev "Configurations (e.g., WYE, DELTA) are not the same for all tanks and windings! check Configurations." # check if node names are the same as expected + else + configuration_prev = deepcopy(configuration) + end + + # check that vnoms across tanks are consistent for wdgs + if tank_id != 1 + @assert vnom == vnom_prev "rated Voltages are not consistent for all tanks and windings! check TransformerEndInfo.ratedU values." # check if node names are the same as expected + else + vnom_prev = deepcopy(vnom) + end + + ### --------------------- - # TODO: RatioTapChanger - for prop in [pass_props] - if haskey(wdgs[w], prop) - transformer_2wa_obj[prop] = wdgs[w][prop] end - end - transformer_2wa_obj["tm_lb"] = tm_lb[w] - transformer_2wa_obj["tm_ub"] = tm_ub[w] - transformer_2wa_obj["tm_step"] = tm_step[w] - data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj - ## TODO: Regulator Control - # if haskey(eng_obj,"controls") && !all(data_math["transformer"]["$(transformer_2wa_obj["index"])"]["tm_fix"]) - # end + # Add information about bus/node if missing + for i in 1:length(nodes) + n = nodes[i] + bus = data_math["bus_lookup"][n] + if !(haskey(data_math["bus"][string(bus)], "terminals")) + data_math["bus"][string(bus)]["terminals"] = connections[i] + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + end + end + + # wdg i, tank 1 - assumes tank 1 always exists + r_s = [r_s[i][1] for i in 1:nrw] + x_sc = [x_sc[1][1]] # wrt to wdg 1 + g_sh = g_sh[1] # wrt to wdg 1 + b_sh = b_sh[1] # wrt to wdg 1 + + # convert x_sc from list of upper triangle elements to an explicit dict + y_sh = g_sh + im*b_sh + z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) + + # TODO: RatioTapChanger - How to get wdg_Data correctly? + tm_set = Vector{Vector{Float64}}(fill(fill(1.0, nphases), nrw)) + tm_lb = Vector{Vector{Float64}}(fill(fill(0.9, nphases), nrw)) + tm_ub = Vector{Vector{Float64}}(fill(fill(1.1, nphases), nrw)) + tm_fix = Vector{Vector{Bool}}(fill(ones(Bool, nphases), nrw)) + tm_step = Vector{Vector{Float64}}(fill(fill(1/32, nphases), nrw)) + + # TODO: Polarity + polarity = fill(1, nrw) + + # Status + status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" + status = status == "true" ? 1 : 0 + + # Build loss model + transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=nphases, status=status) + + # Mathematical model for transformer + for wdg_id in 1:nrw + # 2-WINDING TRANSFORMER + + # correct polarity and connections + if wdg_id>1 + if configuration[1] == DELTA && configuration[wdg_id] == WYE + polarity[wdg_id] = -1 + connections[wdg_id] = _barrel_roll(connections[wdg_id][1:end], 1) + end + if configuration[1] == WYE && configuration[wdg_id] == DELTA + polarity[wdg_id] = -1 + connections[wdg_id] = _barrel_roll(connections[wdg_id], -1) + end + end + + # tm_nom depending on wdg configuration + tm_nom = configuration[wdg_id]==DELTA ? vnom[wdg_id]*sqrt(3)/voltage_scale_factor : vnom[wdg_id]/voltage_scale_factor + + # Transformer Object + transformer_2wa_obj = Dict{String,Any}( + "name" => "_virtual_transformer.$name.$wdg_id", + "source_id" => "_virtual_transformer.transformer.$name.$wdg_id", + "f_bus" => data_math["bus_lookup"][nodes[wdg_id]], + "t_bus" => transformer_t_bus_w[wdg_id], + "tm_nom" => tm_nom, + "f_connections" => connections[wdg_id], + "t_connections" => connections[1], + "configuration" => configuration[wdg_id], + "polarity" => polarity[wdg_id], + "tm_set" => tm_set[wdg_id], + "tm_fix" => tm_fix[wdg_id], + "sm_ub" => sm_ub[wdg_id]/power_scale_factor, + "cm_ub" => cm_ub[wdg_id], # TODO: this may need scaling + "status" => status, + "index" => length(data_math["transformer"])+1 + ) + + # TODO: RatioTapChanger + transformer_2wa_obj["tm_lb"] = tm_lb[wdg_id] + transformer_2wa_obj["tm_ub"] = tm_ub[wdg_id] + transformer_2wa_obj["tm_step"] = tm_step[wdg_id] - # TODO: Center-Tapped Transformers (3 Windings) - # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start - # end + data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj - push!(to_map, "transformer.$(transformer_2wa_obj["index"])") + ## TODO: Regulator Control + # if haskey(eng_obj,"controls") && !all(data_math["transformer"]["$(transformer_2wa_obj["index"])"]["tm_fix"]) + # end + # TODO: Center-Tapped Transformers (3 Windings) + # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start + # end + + push!(to_map, "transformer.$(transformer_2wa_obj["index"])") + + end + + else # Create a transformer for each tank + for tank_id in 1:length(tanks) + + tank_data = tanks[tank_id] # tank data + wdgs_data = tank_data["TransformerTank.TransformerTankEnd"] # wdgs data + tank_asset_name = _extract_name(tanks[tank_id]["PowerSystemResource.AssetDatasheet"]) # tank asset name + tank_asset_data = data_ravens["AssetInfo"]["PowerTransformerInfo"][tank_asset_name] # tank asset data + nrw = length(tank_data["TransformerTank.TransformerTankEnd"]) # number of windings + nphases = 0 # init nphases var + + # per tank windings connections + connections = Vector{Vector{Int64}}(undef, nrw) + + # wdgs data vectors + vnom_wdgs = Vector{Float64}(undef, nrw) + snom_wdgs = Vector{Float64}(undef, nrw) + leak_impedance = Vector{Float64}(undef, nrw) + resistance = Vector{Float64}(undef, nrw) + + # configurations + wdgs_confs = Vector{ConnConfig}(undef, nrw) + + # Regulator set init + tm_set = Vector{Vector{Float64}}(undef, nrw) + tm_lb = Vector{Vector{Float64}}(undef, nrw) + tm_ub = Vector{Vector{Float64}}(undef, nrw) + tm_fix = Vector{Vector{Bool}}(undef, nrw) + tm_step = Vector{Vector{Float64}}(undef, nrw) + + for wdg_id in 1:nrw + + wdg_terminals = wdgs_data[wdg_id]["ConductingEquipment.Terminals"][1] + wdg_phasecode = wdg_terminals["Terminal.phases"] + wdg_endNumber = wdgs_data[wdg_id]["TransformerEnd.endNumber"] + + # from-and-to-nodes for wdg + node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) + bus = data_math["bus_lookup"][node] + + # connections (based on _phasecode_map) + if haskey(_phasecode_map, wdg_phasecode) + wdg_connections = _phasecode_map[wdg_phasecode] + connections[wdg_id] = wdg_connections + else + @error("PhaseCode not supported yet!") + end + + nphases = length(wdg_connections) + if !(haskey(data_math["bus"][string(bus)], "terminals")) + data_math["bus"][string(bus)]["terminals"] = wdg_connections + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + end + + # transformer tank end info. + transf_end_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] + vnom_wdgs[wdg_id] = transf_end_info[wdg_id]["TransformerEndInfo.ratedU"] + snom_wdgs[wdg_id] = transf_end_info[wdg_id]["TransformerEndInfo.ratedS"] + leak_impedance[wdg_id] = transf_end_info[wdg_id]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] + resistance[wdg_id] = transf_end_info[wdg_id]["TransformerEndInfo.r"] + + # wdgs configurations + wdg_conf = transf_end_info[wdg_id]["TransformerEndInfo.connectionKind"] # extract wdg conf + if wdg_conf == "WindingConnection.Y" || wdg_conf == "WindingConnection.I" + wdgs_confs[wdg_id] = WYE + elseif wdg_conf == "WindingConnection.D" + wdgs_confs[wdg_id] = DELTA + else + @error("PowerTransformer ConnectionKind not supported yet!") + end + + # TODO: RatioTapChanger + if haskey(wdgs_data[wdg_id], "TransformerEnd.RatioTapChanger") + # TODO: default for now, but needs to be corrected! + tm_set[wdg_id] = fill(1.0, nphases) + tm_lb[wdg_id] = fill(0.9, nphases) + tm_ub[wdg_id] = fill(1.1, nphases) + tm_fix[wdg_id] = ones(Bool, nphases) + tm_step[wdg_id] = fill(1/32, nphases) + else # default + tm_set[wdg_id] = fill(1.0, nphases) + tm_lb[wdg_id] = fill(0.9, nphases) + tm_ub[wdg_id] = fill(1.1, nphases) + tm_fix[wdg_id] = ones(Bool, nphases) + tm_step[wdg_id] = fill(1/32, nphases) + end + + end + + # calculate zbase in which the data is specified, and convert to SI + zbase = (vnom_wdgs.^2) ./ snom_wdgs + + # x_sc computed from leak impedance + x_sc = (sqrt.((leak_impedance ./ zbase).^2 - ((resistance.*100.0 ./ zbase)*2).^2)./100.0).*zbase + + # rs is specified with respect to each winding + r_s = resistance + + # g_sh always with respect to wdg #1 + loss = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"][1]["TransformerEndInfo.EnergisedEndNoLoadTests"][1]["NoLoadTest.loss"] + g_sh = (loss*snom_wdgs[1])/zbase[1] + + exct_current = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"][1]["TransformerEndInfo.EnergisedEndNoLoadTests"][1]["NoLoadTest.excitingCurrent"] + b_sh = -((sqrt((exct_current)^2 - (loss/(0.01*snom_wdgs[1]))^2))/(100.0*zbase[1])) + + # data is measured externally, but we now refer it to the internal side + ratios = vnom_wdgs/voltage_scale_factor + x_sc = (x_sc./ratios.^2) + r_s = r_s./ratios.^2 + g_sh = g_sh*ratios[1]^2 + b_sh = b_sh*ratios[1]^2 + + # convert x_sc from list of upper triangle elements to an explicit dict + y_sh = g_sh + im*b_sh + z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) + + # dimensions + dims = length(tm_set[1]) + + # TODO: polarity + polarity = fill(1, nrw) + + # Status + status = haskey(tanks[tank_id], "Equipment.inService") ? tanks[tank_id]["Equipment.inService"] : "true" + status = status == "true" ? 1 : 0 + + # Build loss model + transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=dims, status=status) + + # Mathematical model for transformer + for wdg_id in 1:1:nrw + # 2-WINDING TRANSFORMER + + # correct polarity and connections + if wdg_id>1 + if wdgs_confs[1] == DELTA && wdgs_confs[wdg_id] == WYE + polarity[wdg_id] = -1 + connections[wdg_id] = _barrel_roll(connections[wdg_id][1:end], 1) + end + if wdgs_confs[1] == WYE && wdgs_confs[wdg_id] == DELTA + polarity[wdg_id] = -1 + connections[wdg_id] = _barrel_roll(connections[wdg_id], -1) + end + end + + # tank asset data + wdg_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] + + # make virtual bus and mark it for reduction + tm_nom = wdgs_confs[wdg_id]==DELTA ? vnom_wdgs[wdg_id]*sqrt(3)/voltage_scale_factor : vnom_wdgs[wdg_id]/voltage_scale_factor + + # Get correct f_node for winding + wdg_term = wdgs_data[wdg_id]["ConductingEquipment.Terminals"][1] + f_node_wdgterm = _extract_name(wdg_term["Terminal.ConnectivityNode"]) + + # Transformer Object + transformer_2wa_obj = Dict{String,Any}( + "name" => "_virtual_transformer.$name.$wdg_id.$(connections[wdg_id])", + "source_id" => "_virtual_transformer.transformer.$name.$wdg_id.$(connections[wdg_id])", + "f_bus" => data_math["bus_lookup"][f_node_wdgterm], + "t_bus" => transformer_t_bus_w[wdg_id], + "tm_nom" => tm_nom, + "f_connections" => connections[wdg_id], + "t_connections" => connections[1], + "configuration" => wdgs_confs[wdg_id], + "polarity" => polarity[wdg_id], + "tm_set" => tm_set[wdg_id], + "tm_fix" => tm_fix[wdg_id], + "sm_ub" => get(wdg_info[wdg_id], "TransformerEndInfo.ratedS", Inf)/power_scale_factor, + "cm_ub" => get(wdg_info[wdg_id], "TransformerEndInfo.ratedI", Inf), + "status" => status, + "index" => length(data_math["transformer"])+1 + ) + + # TODO: RatioTapChanger + for prop in [pass_props] + if haskey(wdg_info[wdg_id], prop) + transformer_2wa_obj[prop] = wdg_info[wdg_id][prop] + end + end + transformer_2wa_obj["tm_lb"] = tm_lb[wdg_id] + transformer_2wa_obj["tm_ub"] = tm_ub[wdg_id] + transformer_2wa_obj["tm_step"] = tm_step[wdg_id] + + data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj + + ## TODO: Regulator Control + # if haskey(eng_obj,"controls") && !all(data_math["transformer"]["$(transformer_2wa_obj["index"])"]["tm_fix"]) + # end + + # TODO: Center-Tapped Transformers (3 Windings) + # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start + # end + + push!(to_map, "transformer.$(transformer_2wa_obj["index"])") + + end + end + end end end end @@ -616,7 +1088,8 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r # Set the nominal voltage base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor) / (sqrt(3) / 2) + # math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor) / (sqrt(3) / 2) + math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor_sqrt3) # Set voltage bounds for the bus connected bus_info = string(math_obj["load_bus"]) @@ -770,9 +1243,13 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav # Add generator cost model _add_gen_cost_model!(math_obj, ravens_obj) + + rs = fill(get(ravens_obj, "EnergySource.r", zeros(1, 1)), nconductors, nconductors) + xs = fill(get(ravens_obj, "EnergySource.x", zeros(1, 1)), nconductors, nconductors) + # Check for impedance and adjust bus type if necessary map_to = "gen.$(math_obj["index"])" - if !all(isapprox.(get(ravens_obj, "EnergySource.r", zeros(1, 1)), 0)) && !all(isapprox.(get(ravens_obj, "EnergySource.x", zeros(1, 1)), 0)) + if !all(isapprox.(rs, 0)) && !all(isapprox.(xs, 0)) bus_conn["bus_type"] = 1 # Virtual bus becomes the new slack bus bus_obj = Dict( @@ -783,7 +1260,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav "name" => "_virtual_bus.energy_source.$name", "bus_type" => math_obj["gen_status"] == 0 ? 4 : math_obj["control_mode"] == Int(ISOCHRONOUS) ? 3 : 2, "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), - "va" => rad2deg.(_wrap_to_pi.([-2 * π / nphases * (i - 1) + deg2rad(ravens_obj["EnergySource.voltageAngle"]) for i in 1:nphases])), + "va" => rad2deg.(_wrap_to_pi.([-2 * π / nphases * (i - 1) + ravens_obj["EnergySource.voltageAngle"] for i in 1:nphases])), "vmin" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), "vmax" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), "vm_pair_lb" => deepcopy(get(ravens_obj, "EnergySource.vpairMin", Tuple{Any,Any,Real}[])), @@ -818,14 +1295,13 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav map_to = [map_to, "bus.$(bus_obj["index"])", "branch.$(branch_obj["index"])"] else # Handle bus voltage limits if no impedance is present - vm_lb = math_obj["control_mode"] == Int(ISOCHRONOUS) ? ravens_obj["EnergySource.voltageMagnitude"] : get(ravens_obj, "EnergySource.vMin", fill(0.0, nphases)) - vm_ub = math_obj["control_mode"] == Int(ISOCHRONOUS) ? ravens_obj["EnergySource.voltageMagnitude"] : get(ravens_obj, "EnergySource.vMax", fill(Inf, nphases)) + vm_lb = math_obj["control_mode"] == Int(ISOCHRONOUS) ? fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases) : get(ravens_obj, "EnergySource.vMin", fill(1.0, nphases)) + vm_ub = math_obj["control_mode"] == Int(ISOCHRONOUS) ? fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases) : get(ravens_obj, "EnergySource.vMax", fill(1.0, nphases)) data_math["bus"]["$gen_bus"]["vmin"] = [vm_lb..., fill(0.0, nconductors - nphases)...] data_math["bus"]["$gen_bus"]["vmax"] = [vm_ub..., fill(Inf, nconductors - nphases)...] data_math["bus"]["$gen_bus"]["vm"] = fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases) - data_math["bus"]["$gen_bus"]["va"] = fill(ravens_obj["EnergySource.voltageAngle"], nphases) - + data_math["bus"]["$gen_bus"]["va"] = rad2deg.(_wrap_to_pi.([-2 * π / nphases * (i - 1) + ravens_obj["EnergySource.voltageAngle"] for i in 1:nphases])) data_math["bus"]["$gen_bus"]["bus_type"] = _compute_bus_type(bus_conn["bus_type"], math_obj["gen_status"], math_obj["control_mode"]) end @@ -1146,6 +1622,19 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di math_obj["f_bus"] = data_math["bus_lookup"][f_node] math_obj["t_bus"] = data_math["bus_lookup"][t_node] + # Add vmin/vmax/terminals infor to fbus and tbus if missing + if !(haskey(data_math["bus"][string(math_obj["f_bus"])], "terminals")) + data_math["bus"][string(math_obj["f_bus"])]["terminals"] = f_conns + data_math["bus"][string(math_obj["f_bus"])]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(math_obj["f_bus"])]["vmax"] = fill(Inf, nphases) + end + + if !(haskey(data_math["bus"][string(math_obj["t_bus"])], "terminals")) + data_math["bus"][string(math_obj["t_bus"])]["terminals"] = t_conns + data_math["bus"][string(math_obj["t_bus"])]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(math_obj["t_bus"])]["vmax"] = fill(Inf, nphases) + end + # TODO: Status math_obj["status"] = get(ravens_obj, "Equipment.inService", "true") math_obj["status"] = status = math_obj["status"] == "true" ? 1 : 0 diff --git a/src/prob/common.jl b/src/prob/common.jl index 1d0145694..0800d6ee9 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,7 +116,13 @@ function instantiate_mc_model( ) end - # @info "$(data["transformer"])" + # @info "$(data["bus"])" + + # for i in data["transformer"] + # @info "+++++++++++++++++++++++++++++++++++++++++++++++++++++" + # @info "$(i)" + # end + # DEFINIDOEN_instantiate_mc_model return _IM.instantiate_model( @@ -157,7 +163,13 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - # @info "$(data["transformer"])" + # @info "$(data["bus"])" + + # for i in data["transformer"] + # @info "+++++++++++++++++++++++++++++++++++++++++++++++++++++" + # @info "$(i)" + # end + # DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( From 589ef502b69617349fac22a7e4c033f854d7bfbc Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 26 Feb 2025 14:12:16 -0700 Subject: [PATCH 29/99] RM: print out statements for debugging. --- src/data_model/transformations/eng2math.jl | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/data_model/transformations/eng2math.jl b/src/data_model/transformations/eng2math.jl index caed4ce4a..60e75bf2e 100644 --- a/src/data_model/transformations/eng2math.jl +++ b/src/data_model/transformations/eng2math.jl @@ -476,19 +476,10 @@ function _map_eng2math_transformer!(data_math::Dict{String,<:Any}, data_eng::Dic g_sh = g_sh*ratios[1]^2 b_sh = b_sh*ratios[1]^2 - @info "---- NAME --- : $(name)" - @info "RS: $(r_s)" - @info "XSC: $(x_sc)" - @info "GSH: $(g_sh)" - @info "BSH: $(b_sh)" - # convert x_sc from list of upper triangle elements to an explicit dict y_sh = g_sh + im*b_sh z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) - @info "$(y_sh)" - @info "$(z_sc)" - dims = length(eng_obj["tm_set"][1]) transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh,eng_obj["connections"][1]; nphases=dims, status=Int(eng_obj["status"] == ENABLED)) @@ -497,8 +488,6 @@ function _map_eng2math_transformer!(data_math::Dict{String,<:Any}, data_eng::Dic # make virtual bus and mark it for reduction tm_nom = eng_obj["configuration"][w]==DELTA ? eng_obj["vm_nom"][w]*sqrt(3) : eng_obj["vm_nom"][w] - @info "TM_NOM: $(tm_nom)" - transformer_2wa_obj = Dict{String,Any}( "name" => "_virtual_transformer.$name.$w", "source_id" => "_virtual_transformer.$(eng_obj["source_id"]).$w", From 82d6091c97fa6b30ee4dd225be466603b8bb62b1 Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 26 Feb 2025 14:24:01 -0700 Subject: [PATCH 30/99] FIX: correct max sm for transformertank individual. --- src/data_model/transformations/ravens2math.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 3dbb8ab7b..850f58c9f 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -975,7 +975,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data "polarity" => polarity[wdg_id], "tm_set" => tm_set[wdg_id], "tm_fix" => tm_fix[wdg_id], - "sm_ub" => get(wdg_info[wdg_id], "TransformerEndInfo.ratedS", Inf)/power_scale_factor, + "sm_ub" => get(wdg_info[wdg_id], "TransformerEndInfo.emergencyS", Inf)/power_scale_factor, "cm_ub" => get(wdg_info[wdg_id], "TransformerEndInfo.ratedI", Inf), "status" => status, "index" => length(data_math["transformer"])+1 From cfe3bd0760482e5b0a940ab247d517df08689924 Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 26 Feb 2025 15:16:32 -0700 Subject: [PATCH 31/99] REF: Handle default grounding for buses. --- src/data_model/transformations/ravens2math.jl | 25 ++++++++++++------- src/prob/common.jl | 4 +-- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 850f58c9f..cb16adfd1 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -248,7 +248,6 @@ function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data math_obj["bus_i"] = index math_obj["source_id"] = "bus.$name" math_obj["bus_type"] = 1 # Default bus_type, will be modified as needed - math_obj["grounded"] = Bool[0, 0, 0] math_obj["vm_pair_lb"] = Tuple{Any, Any, Real}[] math_obj["vm_pair_ub"] = Tuple{Any, Any, Real}[] @@ -305,6 +304,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: data_math["bus"][string(bus)]["terminals"] = bus_terminals data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) end math_obj["f_connections"] = bus_terminals @@ -427,6 +427,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data data_math["bus"][string(bus)]["terminals"] = connections[wdg_endNumber] data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) end # wdgs configurations @@ -720,6 +721,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data data_math["bus"][string(bus)]["terminals"] = connections[i] data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) end end @@ -859,6 +861,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data data_math["bus"][string(bus)]["terminals"] = wdg_connections data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) end # transformer tank end info. @@ -1157,8 +1160,12 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r data_math["load"]["$(math_obj["index"])"] = math_obj # Handle grounding - if ravens_obj["EnergyConsumer.grounded"] == "true" - bus_conn["grounded"] = Bool[0, 0, 0] + if !(haskey(bus_conn, "grounded")) + if ravens_obj["EnergyConsumer.grounded"] == "true" + bus_conn["grounded"] = ones(Bool, length(math_obj["connections"])) + else + bus_conn["grounded"] = zeros(Bool, length(math_obj["connections"])) + end end # Set bus type to PQ bus @@ -1256,7 +1263,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav "bus_i" => length(data_math["bus"]) + 1, "index" => length(data_math["bus"]) + 1, "terminals" => math_obj["connections"], - "grounded" => Bool[0, 0, 0], + "grounded" => zeros(Bool, nphases), "name" => "_virtual_bus.energy_source.$name", "bus_type" => math_obj["gen_status"] == 0 ? 4 : math_obj["control_mode"] == Int(ISOCHRONOUS) ? 3 : 2, "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), @@ -1589,8 +1596,8 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di terminals = ravens_obj["ConductingEquipment.Terminals"] # Loop through terminals - f_conns = [0,0,0] - t_conns = [0,0,0] + f_conns = [] + t_conns = [] for term in terminals if haskey(term, "Terminal.phases") phasecode = term["Terminal.phases"] @@ -1606,9 +1613,7 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di end # Verify connections are correct. - if (f_conns != t_conns ) - @error("f_conns are not equal to t_conns!. Revise connections/phases in Switch terminals") - end + @assert f_conns == t_conns "f_conns are not equal to t_conns!. Revise connections/phases in Switch terminals" math_obj["f_connections"] = f_conns math_obj["t_connections"] = t_conns @@ -1627,12 +1632,14 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di data_math["bus"][string(math_obj["f_bus"])]["terminals"] = f_conns data_math["bus"][string(math_obj["f_bus"])]["vmin"] = fill(0.0, nphases) data_math["bus"][string(math_obj["f_bus"])]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(math_obj["f_bus"])]["grounded"] = zeros(Bool, nphases) end if !(haskey(data_math["bus"][string(math_obj["t_bus"])], "terminals")) data_math["bus"][string(math_obj["t_bus"])]["terminals"] = t_conns data_math["bus"][string(math_obj["t_bus"])]["vmin"] = fill(0.0, nphases) data_math["bus"][string(math_obj["t_bus"])]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(math_obj["t_bus"])]["grounded"] = zeros(Bool, nphases) end # TODO: Status diff --git a/src/prob/common.jl b/src/prob/common.jl index 0800d6ee9..864b49744 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -118,7 +118,7 @@ function instantiate_mc_model( # @info "$(data["bus"])" - # for i in data["transformer"] + # for i in data["bus"] # @info "+++++++++++++++++++++++++++++++++++++++++++++++++++++" # @info "$(i)" # end @@ -165,7 +165,7 @@ function instantiate_mc_model_ravens( # @info "$(data["bus"])" - # for i in data["transformer"] + # for i in data["bus"] # @info "+++++++++++++++++++++++++++++++++++++++++++++++++++++" # @info "$(i)" # end From ff43f82f8accad2110ff63719833f6d587cb4c01 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 27 Feb 2025 13:35:35 -0700 Subject: [PATCH 32/99] FIX: LoadResponseCharacteristic to LoadResponse --- src/data_model/transformations/ravens2math.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index cb16adfd1..5c193a479 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1031,7 +1031,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r math_obj["load_bus"] = data_math["bus_lookup"][connectivity_node] # Handle Load Response Characteristics - load_response_characts = _extract_name(ravens_obj["EnergyConsumer.LoadResponseCharacteristic"]) + load_response_characts = _extract_name(ravens_obj["EnergyConsumer.LoadResponse"]) if load_response_characts == "Constant Z" math_obj["model"] = IMPEDANCE elseif load_response_characts == "Motor" From 732895e79fa31d40f01520f296e18325eb4c1f6a Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 27 Feb 2025 14:50:47 -0700 Subject: [PATCH 33/99] FIX: issues related to Equipment.inService and loads with multiple phases. Corrected unit tests with latest version of schema. --- src/data_model/transformations/ravens2math.jl | 123 +++++++++--------- test/data/ravens/ravens_case3_withcap.json | 26 ++-- test/data/ravens/ravens_case3_withgens.json | 30 ++--- .../data/ravens/ravens_case3_withgens_mn.json | 28 ++-- .../ravens/ravens_case3_withpvandstorage.json | 28 ++-- test/data/ravens/ravens_case3_withsubxf.json | 28 ++-- test/data/ravens/ravens_test_switch_1w.json | 6 +- test/data/ravens/ravens_test_switch_3w.json | 4 +- 8 files changed, 137 insertions(+), 136 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 5c193a479..b339281c9 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -338,7 +338,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj[t_key] = haskey(oplimitset, f_key) ? fill(oplimitset[f_key], nphases) : fill(Inf, nphases) end - math_obj["br_status"] = get(ravens_obj, "Equipment.inService", "true") == "true" ? 1 : 0 + math_obj["br_status"] = get(ravens_obj, "Equipment.inService", true) == true ? 1 : 0 data_math["branch"]["$(math_obj["index"])"] = math_obj push!(data_math["map"], Dict{String,Any}( @@ -481,8 +481,8 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data polarity = fill(1, nrw) # Status - status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" - status = status == "true" ? 1 : 0 + status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true + status = status == true ? 1 : 0 # Build loss model transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=dims, status=status) @@ -746,8 +746,8 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data polarity = fill(1, nrw) # Status - status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" - status = status == "true" ? 1 : 0 + status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true + status = status == true ? 1 : 0 # Build loss model transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=nphases, status=status) @@ -933,8 +933,8 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data polarity = fill(1, nrw) # Status - status = haskey(tanks[tank_id], "Equipment.inService") ? tanks[tank_id]["Equipment.inService"] : "true" - status = status == "true" ? 1 : 0 + status = haskey(tanks[tank_id], "Equipment.inService") ? tanks[tank_id]["Equipment.inService"] : true + status = status == true ? 1 : 0 # Build loss model transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=dims, status=status) @@ -1052,42 +1052,6 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r math_obj["model"] = POWER end - # Set p and q (w/ multinetwork support) - - if nw==0 - math_obj["pd"] = [ravens_obj["EnergyConsumer.p"] / power_scale_factor] - math_obj["qd"] = [ravens_obj["EnergyConsumer.q"] / power_scale_factor] - else - - # Get timeseries schedule - if haskey(ravens_obj, "EnergyConsumer.LoadForecast") - schdl_name = _extract_name(ravens_obj["EnergyConsumer.LoadForecast"]) - schdl = data_ravens["BasicIntervalSchedule"][schdl_name] - - # TODO: Define other types of timeseries (e.g., multipliers, etc.) - # units and multiplier modifiers - value1_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value1Multiplier"]] - value2_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value2Multiplier"]] - value1_unit = schdl["BasicIntervalSchedule.value1Unit"] - value2_unit = schdl["BasicIntervalSchedule.value2Unit"] - - if value1_unit == "W" - math_obj["pd"] = [schdl["EnergyConsumerSchedule.RegularTimePoints"][nw]["RegularTimePoint.value1"] * value1_multiplier / power_scale_factor] - end - if value1_unit == "VAr" - math_obj["qd"] = [schdl["EnergyConsumerSchedule.RegularTimePoints"][nw]["RegularTimePoint.value1"] * value1_multiplier / power_scale_factor] - end - if value2_unit == "W" - math_obj["pd"] = [schdl["EnergyConsumerSchedule.RegularTimePoints"][nw]["RegularTimePoint.value2"] * value2_multiplier / power_scale_factor] - end - if value2_unit == "VAr" - math_obj["qd"] = [schdl["EnergyConsumerSchedule.RegularTimePoints"][nw]["RegularTimePoint.value2"] * value2_multiplier / power_scale_factor] - end - else - @error("No timeseries, load forecast or multinetwork information found!") - end - end - # Set the nominal voltage base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] @@ -1125,6 +1089,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end # Handle phase-specific or three-phase connection + nphases = 0 phase_map = Dict("SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, "SinglePhaseKind.C" => 3) if haskey(ravens_obj, "EnergyConsumer.EnergyConsumerPhase") connections = Vector{Int64}() @@ -1136,13 +1101,49 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r push!(connections, phase) end math_obj["connections"] = connections + nphases = length(bus_conn["terminals"]) else - N = length(bus_conn["terminals"]) - bus_conn["vmax"] = fill(op_limit_max, N) - bus_conn["vmin"] = fill(op_limit_min, N) + nphases = length(bus_conn["terminals"]) + bus_conn["vmax"] = fill(op_limit_max, nphases) + bus_conn["vmin"] = fill(op_limit_min, nphases) math_obj["connections"] = bus_conn["terminals"] end + # Set p and q (w/ multinetwork support) + if nw==0 + math_obj["pd"] = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / power_scale_factor, nphases) + math_obj["qd"] = fill(get(ravens_obj, "EnergyConsumer.q", 0.0) / power_scale_factor, nphases) + else + # Get timeseries schedule + if haskey(ravens_obj, "EnergyConsumer.LoadForecast") + schdl_name = _extract_name(ravens_obj["EnergyConsumer.LoadForecast"]) + schdl = data_ravens["BasicIntervalSchedule"][schdl_name] + + # TODO: Define other types of timeseries (e.g., multipliers, etc.) + # units and multiplier modifiers + value1_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value1Multiplier"]] + value2_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value2Multiplier"]] + value1_unit = schdl["BasicIntervalSchedule.value1Unit"] + value2_unit = schdl["BasicIntervalSchedule.value2Unit"] + + if value1_unit == "W" + math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / power_scale_factor, nphases) + end + if value1_unit == "VAr" + math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / power_scale_factor, nphases) + end + if value2_unit == "W" + math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / power_scale_factor, nphases) + end + if value2_unit == "VAr" + math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / power_scale_factor, nphases) + end + else + @error("No timeseries, load forecast or multinetwork information found!") + end + end + + # Set the configuration # TODO: ADD: "PhaseShuntConnectionKind.Yn", "PhaseShuntConnectionKind.I", "PhaseShuntConnectionKind.G" config_map = Dict("PhaseShuntConnectionKind.Y" => WYE, "PhaseShuntConnectionKind.D" => DELTA) @@ -1154,14 +1155,14 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end # Set status, dispatchable flag, and index - math_obj["status"] = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" - math_obj["status"] = math_obj["status"] == "true" ? 1 : 0 + math_obj["status"] = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true + math_obj["status"] = math_obj["status"] == true ? 1 : 0 math_obj["dispatchable"] = 0 data_math["load"]["$(math_obj["index"])"] = math_obj # Handle grounding if !(haskey(bus_conn, "grounded")) - if ravens_obj["EnergyConsumer.grounded"] == "true" + if ravens_obj["EnergyConsumer.grounded"] == true bus_conn["grounded"] = ones(Bool, length(math_obj["connections"])) else bus_conn["grounded"] = zeros(Bool, length(math_obj["connections"])) @@ -1222,8 +1223,8 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav end # Generator status and configuration - math_obj["gen_status"] = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" - math_obj["gen_status"] = math_obj["gen_status"] == "true" ? 1 : 0 + math_obj["gen_status"] = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true + math_obj["gen_status"] = math_obj["gen_status"] == true ? 1 : 0 math_obj["configuration"] = get(ravens_obj, "EnergySource.connectionKind", WYE) @@ -1350,8 +1351,8 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] - math_obj["gen_status"] = get(ravens_obj, "Equipment.inService", "true") - math_obj["gen_status"] = status = math_obj["gen_status"] == "true" ? 1 : 0 + math_obj["gen_status"] = get(ravens_obj, "Equipment.inService", true) + math_obj["gen_status"] = status = math_obj["gen_status"] == true ? 1 : 0 # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) @@ -1438,8 +1439,8 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) math_obj["gen_bus"] = data_math["bus_lookup"][connectivity_node] - math_obj["gen_status"] = get(ravens_obj, "Equipment.inService", "true") - math_obj["gen_status"] = status = math_obj["gen_status"] == "true" ? 1 : 0 + math_obj["gen_status"] = get(ravens_obj, "Equipment.inService", true) + math_obj["gen_status"] = status = math_obj["gen_status"] == true ? 1 : 0 # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) @@ -1518,8 +1519,8 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data # Set the bus connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) math_obj["storage_bus"] = data_math["bus_lookup"][connectivity_node] - math_obj["status"] = get(ravens_obj, "Equipment.inService", "true") - math_obj["status"] = status = math_obj["status"] == "true" ? 1 : 0 + math_obj["status"] = get(ravens_obj, "Equipment.inService", true) + math_obj["status"] = status = math_obj["status"] == true ? 1 : 0 # TODO: configuration for generators is not available on CIM (yet) math_obj["configuration"] = get(ravens_obj, "configuration", WYE) @@ -1643,8 +1644,8 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di end # TODO: Status - math_obj["status"] = get(ravens_obj, "Equipment.inService", "true") - math_obj["status"] = status = math_obj["status"] == "true" ? 1 : 0 + math_obj["status"] = get(ravens_obj, "Equipment.inService", true) + math_obj["status"] = status = math_obj["status"] == true ? 1 : 0 # State sw_state = get(ravens_obj, "Switch.open", "false") @@ -1694,8 +1695,8 @@ function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data math_obj["shunt_bus"] = data_math["bus_lookup"][connectivity_node] # Status - status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : "true" - math_obj["status"] = status == "true" ? 1 : 0 + status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true + math_obj["status"] = status == true ? 1 : 0 # Connections/phases obtained from Terminals if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") diff --git a/test/data/ravens/ravens_case3_withcap.json b/test/data/ravens/ravens_case3_withcap.json index a5afd36fc..a6c2118ef 100644 --- a/test/data/ravens/ravens_case3_withcap.json +++ b/test/data/ravens/ravens_case3_withcap.json @@ -127,7 +127,7 @@ "IdentifiedObject.mRID": "f501b03c-aee6-4524-a253-3adc0a016c92", "IdentifiedObject.name": "quad", "Conductor.length": 1.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", "ACLineSegment.ACLineSegmentPhase": [ @@ -177,7 +177,7 @@ "IdentifiedObject.mRID": "ea549d70-b21a-4132-a5d2-ef9996f6c0ea", "IdentifiedObject.name": "ohline", "Conductor.length": 1.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", "ACLineSegment.ACLineSegmentPhase": [ @@ -233,11 +233,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -266,11 +266,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -299,11 +299,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -338,7 +338,7 @@ "EnergySource.x": 1.5522280002325312e-07, "EnergySource.r0": 5.069596039676399e-08, "EnergySource.x0": 1.5208788119029196e-07, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { @@ -366,7 +366,7 @@ "LinearShuntCompensator.g0PerSection": 0.0, "LinearShuntCompensator.normalSections": 1, "LinearShuntCompensator.maximumSections": 1, - "Equipment.inService": "true", + "Equipment.inService": true, "LinearShuntCompensator.aVRDelay": 0.0, "ShuntCompensator.sections": 1, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", diff --git a/test/data/ravens/ravens_case3_withgens.json b/test/data/ravens/ravens_case3_withgens.json index ecc5fac68..72762e2c7 100644 --- a/test/data/ravens/ravens_case3_withgens.json +++ b/test/data/ravens/ravens_case3_withgens.json @@ -131,7 +131,7 @@ "RotatingMachine.q": 484.3221048378525, "RotatingMachine.ratedS": 1200.0, "RotatingMachine.ratedU": 461.88021535170066, - "Equipment.inService": "true", + "Equipment.inService": true, "RotatingMachine.ratedPowerFactor": 0.9, "GeneratingUnit.minOperatingP": 0.0, "GeneratingUnit.maxOperatingP": 1080.0, @@ -157,7 +157,7 @@ "RotatingMachine.q": 968.644209675705, "RotatingMachine.ratedS": 2400.0, "RotatingMachine.ratedU": 461.88021535170066, - "Equipment.inService": "true", + "Equipment.inService": true, "RotatingMachine.ratedPowerFactor": 0.9, "GeneratingUnit.minOperatingP": 0.0, "GeneratingUnit.maxOperatingP": 2160.0, @@ -189,7 +189,7 @@ "EnergySource.x": 1.5522280002325312e-07, "EnergySource.r0": 5.069596039676399e-08, "EnergySource.x0": 1.5208788119029196e-07, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { @@ -211,11 +211,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -244,11 +244,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -277,11 +277,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -312,7 +312,7 @@ "IdentifiedObject.mRID": "357e3f68-a996-4ef9-8e29-5a9701da50f5", "IdentifiedObject.name": "ohline", "Conductor.length": 1.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", "ConductingEquipment.Terminals": [ @@ -362,7 +362,7 @@ "IdentifiedObject.mRID": "b0c876f2-8724-4b1d-9bb8-16ad6dc08866", "IdentifiedObject.name": "quad", "Conductor.length": 1.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", "ConductingEquipment.Terminals": [ @@ -603,4 +603,4 @@ "BaseVoltage.nominalVoltage": 400.0 } } -} \ No newline at end of file +} diff --git a/test/data/ravens/ravens_case3_withgens_mn.json b/test/data/ravens/ravens_case3_withgens_mn.json index e1eb5c059..ebd91ad24 100644 --- a/test/data/ravens/ravens_case3_withgens_mn.json +++ b/test/data/ravens/ravens_case3_withgens_mn.json @@ -131,7 +131,7 @@ "RotatingMachine.q": 484.3221048378525, "RotatingMachine.ratedS": 1200.0, "RotatingMachine.ratedU": 461.88021535170066, - "Equipment.inService": "true", + "Equipment.inService": true, "RotatingMachine.ratedPowerFactor": 0.9, "GeneratingUnit.minOperatingP": 0.0, "GeneratingUnit.maxOperatingP": 1080.0, @@ -157,7 +157,7 @@ "RotatingMachine.q": 968.644209675705, "RotatingMachine.ratedS": 2400.0, "RotatingMachine.ratedU": 461.88021535170066, - "Equipment.inService": "true", + "Equipment.inService": true, "RotatingMachine.ratedPowerFactor": 0.9, "GeneratingUnit.minOperatingP": 0.0, "GeneratingUnit.maxOperatingP": 2160.0, @@ -189,7 +189,7 @@ "EnergySource.x": 1.5522280002325312e-07, "EnergySource.r0": 5.069596039676399e-08, "EnergySource.x0": 1.5208788119029196e-07, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { @@ -211,11 +211,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "EnergyConsumer.LoadForecast": "EnergyConsumerSchedule::'load_shape'", "ConductingEquipment.Terminals": [ { @@ -245,11 +245,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "EnergyConsumer.LoadForecast": "EnergyConsumerSchedule::'load_shape'", "ConductingEquipment.Terminals": [ { @@ -279,11 +279,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "EnergyConsumer.LoadForecast": "EnergyConsumerSchedule::'load_shape'", "ConductingEquipment.Terminals": [ { @@ -315,7 +315,7 @@ "IdentifiedObject.mRID": "357e3f68-a996-4ef9-8e29-5a9701da50f5", "IdentifiedObject.name": "ohline", "Conductor.length": 1.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", "ConductingEquipment.Terminals": [ @@ -365,7 +365,7 @@ "IdentifiedObject.mRID": "b0c876f2-8724-4b1d-9bb8-16ad6dc08866", "IdentifiedObject.name": "quad", "Conductor.length": 1.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", "ConductingEquipment.Terminals": [ diff --git a/test/data/ravens/ravens_case3_withpvandstorage.json b/test/data/ravens/ravens_case3_withpvandstorage.json index 73b959d88..af4ccb4fc 100644 --- a/test/data/ravens/ravens_case3_withpvandstorage.json +++ b/test/data/ravens/ravens_case3_withpvandstorage.json @@ -80,7 +80,7 @@ "IdentifiedObject.mRID": "e9c718d0-d75c-41cf-b31e-5d1467780362", "IdentifiedObject.name": "ohline", "Conductor.length": 1.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", "ACLineSegment.ACLineSegmentPhase": [ @@ -130,7 +130,7 @@ "IdentifiedObject.mRID": "edba552d-daee-40f3-9488-336f9c9231dc", "IdentifiedObject.name": "quad", "Conductor.length": 1.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", "ACLineSegment.ACLineSegmentPhase": [ @@ -186,11 +186,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -219,11 +219,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -252,11 +252,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -291,7 +291,7 @@ "EnergySource.x": 1.5522280002325312e-07, "EnergySource.r0": 5.069596039676399e-08, "EnergySource.x0": 1.5208788119029196e-07, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { @@ -318,7 +318,7 @@ "PowerElectronicsConnection.ratedU": 400.0, "PowerElectronicsConnection.maxQ": 10000.0, "PowerElectronicsConnection.minQ": -10000.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { @@ -349,7 +349,7 @@ "PowerElectronicsConnection.ratedU": 400.0, "PowerElectronicsConnection.maxQ": 25000.0, "PowerElectronicsConnection.minQ": -25000.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { diff --git a/test/data/ravens/ravens_case3_withsubxf.json b/test/data/ravens/ravens_case3_withsubxf.json index 7f2ec6db4..6fc5d1d2b 100644 --- a/test/data/ravens/ravens_case3_withsubxf.json +++ b/test/data/ravens/ravens_case3_withsubxf.json @@ -126,7 +126,7 @@ "IdentifiedObject.mRID": "e9c718d0-d75c-41cf-b31e-5d1467780362", "IdentifiedObject.name": "ohline", "Conductor.length": 1.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", "ACLineSegment.ACLineSegmentPhase": [ @@ -176,7 +176,7 @@ "IdentifiedObject.mRID": "edba552d-daee-40f3-9488-336f9c9231dc", "IdentifiedObject.name": "quad", "Conductor.length": 1.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", "ACLineSegment.ACLineSegmentPhase": [ @@ -232,11 +232,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -265,11 +265,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -298,11 +298,11 @@ "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, - "EnergyConsumer.grounded": "true", - "Equipment.inService": "true", + "EnergyConsumer.grounded": true, + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -337,7 +337,7 @@ "EnergySource.x": 5.0292187e-05, "EnergySource.r0": 1.6425491e-05, "EnergySource.x0": 4.9276474e-05, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_7.2000'", "ConductingEquipment.Terminals": [ { @@ -364,7 +364,7 @@ "PowerElectronicsConnection.ratedU": 400.0, "PowerElectronicsConnection.maxQ": 10000.0, "PowerElectronicsConnection.minQ": -10000.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { @@ -395,7 +395,7 @@ "PowerElectronicsConnection.ratedU": 400.0, "PowerElectronicsConnection.maxQ": 25000.0, "PowerElectronicsConnection.minQ": -25000.0, - "Equipment.inService": "true", + "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { diff --git a/test/data/ravens/ravens_test_switch_1w.json b/test/data/ravens/ravens_test_switch_1w.json index 0c177322a..c2c8874b7 100644 --- a/test/data/ravens/ravens_test_switch_1w.json +++ b/test/data/ravens/ravens_test_switch_1w.json @@ -305,9 +305,9 @@ "EnergyConsumer.q": 2179.4495, "EnergyConsumer.customerCount": 1, "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.grounded": "true", + "EnergyConsumer.grounded": true, "PowerSystemResource.Location": "Location::'load1_Loc'", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -551,4 +551,4 @@ } } } -} \ No newline at end of file +} diff --git a/test/data/ravens/ravens_test_switch_3w.json b/test/data/ravens/ravens_test_switch_3w.json index ae7c35260..0e4a1c99c 100644 --- a/test/data/ravens/ravens_test_switch_3w.json +++ b/test/data/ravens/ravens_test_switch_3w.json @@ -383,9 +383,9 @@ "EnergyConsumer.q": 2179.4495, "EnergyConsumer.customerCount": 1, "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.grounded": "true", + "EnergyConsumer.grounded": true, "PowerSystemResource.Location": "Location::'load1_Loc'", - "EnergyConsumer.LoadResponseCharacteristic": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", From 9ac1abe0a1715466d7dda319b580b7c8a457d753 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 27 Feb 2025 15:28:06 -0700 Subject: [PATCH 34/99] FIX: name changes for LoadForecast -> LoadProfile and add support for simple multipliers in the load profile. --- src/data_model/transformations/ravens2math.jl | 50 +++++++++++++------ .../data/ravens/ravens_case3_withgens_mn.json | 6 +-- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index b339281c9..724ed11b2 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1115,29 +1115,51 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r math_obj["qd"] = fill(get(ravens_obj, "EnergyConsumer.q", 0.0) / power_scale_factor, nphases) else # Get timeseries schedule - if haskey(ravens_obj, "EnergyConsumer.LoadForecast") - schdl_name = _extract_name(ravens_obj["EnergyConsumer.LoadForecast"]) + if haskey(ravens_obj, "EnergyConsumer.LoadProfile") + schdl_name = _extract_name(ravens_obj["EnergyConsumer.LoadProfile"]) schdl = data_ravens["BasicIntervalSchedule"][schdl_name] # TODO: Define other types of timeseries (e.g., multipliers, etc.) # units and multiplier modifiers - value1_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value1Multiplier"]] - value2_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value2Multiplier"]] - value1_unit = schdl["BasicIntervalSchedule.value1Unit"] - value2_unit = schdl["BasicIntervalSchedule.value2Unit"] - if value1_unit == "W" - math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / power_scale_factor, nphases) + if haskey(schdl, "BasicIntervalSchedule.value1Multiplier") + value1_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value1Multiplier"]] + else + value1_multiplier = 1.0 + end + + if haskey(schdl, "BasicIntervalSchedule.value2Multiplier") + value2_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value2Multiplier"]] + else + value2_multiplier = 1.0 end - if value1_unit == "VAr" - math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / power_scale_factor, nphases) + + if haskey(schdl, "BasicIntervalSchedule.value1Unit") + value1_unit = lowercase(schdl["BasicIntervalSchedule.value1Unit"]) + if value1_unit == "w" + math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / power_scale_factor, nphases) + end + if value1_unit == "var" + math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / power_scale_factor, nphases) + end end - if value2_unit == "W" - math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / power_scale_factor, nphases) + + if haskey(schdl, "BasicIntervalSchedule.value2Unit") + value2_unit = lowercase(schdl["BasicIntervalSchedule.value2Unit"]) + if value2_unit == "w" + math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / power_scale_factor, nphases) + end + if value2_unit == "var" + math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / power_scale_factor, nphases) + end end - if value2_unit == "VAr" - math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / power_scale_factor, nphases) + + # Multipliers instead of actual values - TODO: add support for EnergyConsumerPhase data + if !haskey(schdl, "BasicIntervalSchedule.value1Unit") + math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * ravens_obj["EnergyConsumer.p"] / power_scale_factor, nphases) + math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * ravens_obj["EnergyConsumer.q"] / power_scale_factor, nphases) end + else @error("No timeseries, load forecast or multinetwork information found!") end diff --git a/test/data/ravens/ravens_case3_withgens_mn.json b/test/data/ravens/ravens_case3_withgens_mn.json index ebd91ad24..38094716f 100644 --- a/test/data/ravens/ravens_case3_withgens_mn.json +++ b/test/data/ravens/ravens_case3_withgens_mn.json @@ -216,7 +216,7 @@ "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", - "EnergyConsumer.LoadForecast": "EnergyConsumerSchedule::'load_shape'", + "EnergyConsumer.Profile": "EnergyConsumerSchedule::'load_shape'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -250,7 +250,7 @@ "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", - "EnergyConsumer.LoadForecast": "EnergyConsumerSchedule::'load_shape'", + "EnergyConsumer.Profile": "EnergyConsumerSchedule::'load_shape'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", @@ -284,7 +284,7 @@ "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", - "EnergyConsumer.LoadForecast": "EnergyConsumerSchedule::'load_shape'", + "EnergyConsumer.Profile": "EnergyConsumerSchedule::'load_shape'", "ConductingEquipment.Terminals": [ { "Ravens.CimObjectType": "Terminal", From c979b5b454d5ed182598b3d6455ff8383579bbab Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 27 Feb 2025 16:17:54 -0700 Subject: [PATCH 35/99] FIX: issues with loadprofiles multipliers and correct dimensions of pd and qd. --- src/data_model/transformations/ravens2math.jl | 33 +++++++++----- src/data_model/utils_ravens.jl | 43 +++++++++++-------- 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 724ed11b2..661bf2709 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -297,8 +297,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj["f_bus"] = data_math["bus_lookup"][f_node] math_obj["t_bus"] = data_math["bus_lookup"][t_node] - phase_map = Dict("SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, "SinglePhaseKind.C" => 3) - bus_terminals = nphases >= 3 ? collect(1:nphases) : [phase_map[phase["ACLineSegmentPhase.phase"]] for phase in ravens_obj["ACLineSegment.ACLineSegmentPhase"]] + bus_terminals = nphases >= 3 ? collect(1:nphases) : [_phase_map[phase["ACLineSegmentPhase.phase"]] for phase in ravens_obj["ACLineSegment.ACLineSegmentPhase"]] for bus in [math_obj["f_bus"], math_obj["t_bus"]] data_math["bus"][string(bus)]["terminals"] = bus_terminals @@ -1090,18 +1089,17 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r # Handle phase-specific or three-phase connection nphases = 0 - phase_map = Dict("SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, "SinglePhaseKind.C" => 3) if haskey(ravens_obj, "EnergyConsumer.EnergyConsumerPhase") connections = Vector{Int64}() for phase_info in ravens_obj["EnergyConsumer.EnergyConsumerPhase"] - phase = phase_map[phase_info["EnergyConsumerPhase.phase"]] + phase = _phase_map[phase_info["EnergyConsumerPhase.phase"]] phase_index = findfirst(==(phase), bus_conn["terminals"]) bus_conn["vmax"][phase_index] = op_limit_max bus_conn["vmin"][phase_index] = op_limit_min push!(connections, phase) end math_obj["connections"] = connections - nphases = length(bus_conn["terminals"]) + nphases = length(math_obj["connections"]) else nphases = length(bus_conn["terminals"]) bus_conn["vmax"] = fill(op_limit_max, nphases) @@ -1116,12 +1114,26 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r else # Get timeseries schedule if haskey(ravens_obj, "EnergyConsumer.LoadProfile") + + # get active (P) and reactive power (Q) of the load + active_power = zeros(Float64, nphases) + reactive_power = zeros(Float64, nphases) + + if haskey(ravens_obj, "EnergyConsumer.EnergyConsumerPhase") + for id in 1:nphases + phase_info = ravens_obj["EnergyConsumer.EnergyConsumerPhase"][id] + active_power[id] = phase_info["EnergyConsumerPhase.p"] + reactive_power[id] = phase_info["EnergyConsumerPhase.q"] + end + else + active_power = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / power_scale_factor, nphases) + reactive_power = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / power_scale_factor, nphases) + end + schdl_name = _extract_name(ravens_obj["EnergyConsumer.LoadProfile"]) schdl = data_ravens["BasicIntervalSchedule"][schdl_name] - # TODO: Define other types of timeseries (e.g., multipliers, etc.) # units and multiplier modifiers - if haskey(schdl, "BasicIntervalSchedule.value1Multiplier") value1_multiplier = _multipliers_map[schdl["BasicIntervalSchedule.value1Multiplier"]] else @@ -1156,8 +1168,8 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r # Multipliers instead of actual values - TODO: add support for EnergyConsumerPhase data if !haskey(schdl, "BasicIntervalSchedule.value1Unit") - math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * ravens_obj["EnergyConsumer.p"] / power_scale_factor, nphases) - math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * ravens_obj["EnergyConsumer.q"] / power_scale_factor, nphases) + math_obj["pd"] = get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 1.0) .* active_power ./ power_scale_factor + math_obj["qd"] = get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 1.0) .* reactive_power ./ power_scale_factor end else @@ -1228,9 +1240,8 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav nconductors = length(get(ravens_obj, "EnergySource.EnergySourcePhase", bus_conn["terminals"])) if haskey(ravens_obj, "EnergySource.EnergySourcePhase") - phase_map = Dict("SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, "SinglePhaseKind.C" => 3) for phase_info in ravens_obj["EnergySource.EnergySourcePhase"] - phase = phase_map[phase_info["EnergySourcePhase.phase"]] + phase = _phase_map[phase_info["EnergySourcePhase.phase"]] push!(connections, phase) end math_obj["connections"] = connections diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index f3e2e688f..c679e5dd8 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -1,27 +1,32 @@ const _phasecode_map = Dict( - "PhaseCode.ABC" => [1, 2, 3], - "PhaseCode.AB" => [1, 2], - "PhaseCode.AC" => [1, 3], - "PhaseCode.BC" => [2, 3], - "PhaseCode.A" => [1], - "PhaseCode.B" => [2], - "PhaseCode.C" => [3] + "PhaseCode.ABC" => [1, 2, 3], + "PhaseCode.AB" => [1, 2], + "PhaseCode.AC" => [1, 3], + "PhaseCode.BC" => [2, 3], + "PhaseCode.A" => [1], + "PhaseCode.B" => [2], + "PhaseCode.C" => [3] ) +_phase_map = Dict( + "SinglePhaseKind.A" => 1, + "SinglePhaseKind.B" => 2, + "SinglePhaseKind.C" => 3 +) const _multipliers_map = Dict( - "m" => 1e-3, - "c" => 1e-2, - "d" => 1e-1, - "da" => 1e1, - "h" => 1e2, - "k" => 1e3, - "M" => 1e6, - "G" => 1e9, - "T" => 1e12, - "P" => 1e15, - "E" => 1e18, - "Z" => 1e21 + "m" => 1e-3, + "c" => 1e-2, + "d" => 1e-1, + "da" => 1e1, + "h" => 1e2, + "k" => 1e3, + "M" => 1e6, + "G" => 1e9, + "T" => 1e12, + "P" => 1e15, + "E" => 1e18, + "Z" => 1e21 ) From dfc3859dd295094724e4fed8e38b0436529f32f5 Mon Sep 17 00:00:00 2001 From: jjospina Date: Fri, 28 Feb 2025 12:37:02 -0700 Subject: [PATCH 36/99] FIX: load and gen Q not being parsed correctly for multiple phases. --- src/data_model/transformations/ravens2math.jl | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 661bf2709..e0df1ebd7 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1109,8 +1109,8 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r # Set p and q (w/ multinetwork support) if nw==0 - math_obj["pd"] = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / power_scale_factor, nphases) - math_obj["qd"] = fill(get(ravens_obj, "EnergyConsumer.q", 0.0) / power_scale_factor, nphases) + math_obj["pd"] = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / (power_scale_factor*nphases), nphases) + math_obj["qd"] = fill(get(ravens_obj, "EnergyConsumer.q", 0.0) / (power_scale_factor*nphases), nphases) else # Get timeseries schedule if haskey(ravens_obj, "EnergyConsumer.LoadProfile") @@ -1126,8 +1126,8 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r reactive_power[id] = phase_info["EnergyConsumerPhase.q"] end else - active_power = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / power_scale_factor, nphases) - reactive_power = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / power_scale_factor, nphases) + active_power = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / (power_scale_factor*nphases), nphases) + reactive_power = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / (power_scale_factor*nphases), nphases) end schdl_name = _extract_name(ravens_obj["EnergyConsumer.LoadProfile"]) @@ -1416,10 +1416,23 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ # Set pmin math_obj["pmin"] = ((get(ravens_obj, "GeneratingUnit.minOperatingP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set qmin - math_obj["qmin"] = ((get(ravens_obj, "RotatingMachine.minQ", -Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set qmax - math_obj["qmax"] = ((get(ravens_obj, "RotatingMachine.maxQ", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + + # Set min and max Q + if haskey(ravens_obj, "RotatingMachine.minQ") + math_obj["qmin"] = ((ravens_obj["RotatingMachine.minQ"] * ones(nconductors)) ./ nconductors)./(power_scale_factor) + elseif haskey(ravens_obj, "SynchronousMachine.minQ") + math_obj["qmin"] = ((ravens_obj["SynchronousMachine.minQ"] * ones(nconductors)) ./ nconductors)./(power_scale_factor) + else + math_obj["qmin"] = fill(-Inf, nconductors) + end + + if haskey(ravens_obj, "RotatingMachine.maxQ") + math_obj["qmax"] = ((ravens_obj["RotatingMachine.maxQ"] * ones(nconductors)) ./ nconductors)./(power_scale_factor) + elseif haskey(ravens_obj, "SynchronousMachine.maxQ") + math_obj["qmax"] = ((ravens_obj["SynchronousMachine.maxQ"] * ones(nconductors)) ./ nconductors)./(power_scale_factor) + else + math_obj["qmax"] = fill(-Inf, nconductors) + end # Set pg and qg math_obj["pg"] = (get(ravens_obj, "RotatingMachine.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) From 674fe4e8999c8bdea77b164f290b1e0e668f4471 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 3 Mar 2025 14:57:15 -0700 Subject: [PATCH 37/99] FIX: admittance computation. --- src/data_model/transformations/ravens2math.jl | 2 +- src/data_model/utils_ravens.jl | 4 ++-- src/prob/common.jl | 22 ++++++++++++++----- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index e0df1ebd7..d03b2898d 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -317,7 +317,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: base_freq = data_math["settings"]["base_frequency"] for (key, param) in [("b_fr", "PhaseImpedanceData.b"), ("b_to", "PhaseImpedanceData.b"), ("g_fr", "PhaseImpedanceData.g"), ("g_to", "PhaseImpedanceData.g")] - math_obj[key] = _admittance_conversion_ravens(impedance_data, ravens_obj, param; freq=base_freq) + math_obj[key] = _admittance_conversion_ravens(impedance_data, ravens_obj, param) end math_obj["angmin"] = get(ravens_obj, "vad_lb", fill(-60.0, nphases)) diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index c679e5dd8..54f09b75b 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -86,7 +86,7 @@ end "converts admittance by multiplying by 2πωl" -function _admittance_conversion_ravens(data_eng::Dict{String,<:Any}, eng_obj::Dict{String,<:Any}, key::String; freq::Float64=60.0) +function _admittance_conversion_ravens(data_eng::Dict{String,<:Any}, eng_obj::Dict{String,<:Any}, key::String) _conductor_count = data_eng["PerLengthPhaseImpedance.conductorCount"] _admittance_matrix = zeros(Float64, _conductor_count, _conductor_count) @@ -99,7 +99,7 @@ function _admittance_conversion_ravens(data_eng::Dict{String,<:Any}, eng_obj::Di _admittance_matrix[col, row] = value end - return _admittance_matrix .* get(eng_obj, "Conductor.length", 1.0) .* freq ./ 1e2 # divide by 2 to get both sides _to and _fr + return _admittance_matrix .* get(eng_obj, "Conductor.length", 1.0) ./ 2 # divide by 2 to get both sides _to and _fr end "extracts the name from a ravens reference string" diff --git a/src/prob/common.jl b/src/prob/common.jl index 864b49744..ddc604a9d 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -118,9 +118,14 @@ function instantiate_mc_model( # @info "$(data["bus"])" - # for i in data["bus"] - # @info "+++++++++++++++++++++++++++++++++++++++++++++++++++++" - # @info "$(i)" + # for i in data["branch"] + # # @info "+++++++++++++++++++++++++++++++++++++++++++++++++++++" + # # @info "$(i)" + # for (j,k) in enumerate(i) + # for l in k + # @info "$(l)" + # end + # end # end # DEFINIDOEN_instantiate_mc_model @@ -165,9 +170,14 @@ function instantiate_mc_model_ravens( # @info "$(data["bus"])" - # for i in data["bus"] - # @info "+++++++++++++++++++++++++++++++++++++++++++++++++++++" - # @info "$(i)" + # for i in data["branch"] + # # @info "+++++++++++++++++++++++++++++++++++++++++++++++++++++" + # # @info "$(i)" + # for (j,k) in enumerate(i) + # for l in k + # @info "$(l)" + # end + # end # end # DEFINIDOEN_instantiate_mc_model_ravens From a40f4578c3628aa46c1862a190035bd8c612a8a1 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 4 Mar 2025 09:21:50 -0700 Subject: [PATCH 38/99] REF: pmax and pmin for rotating machine generating units. --- src/data_model/transformations/ravens2math.jl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index d03b2898d..db1e65b97 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1390,11 +1390,13 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) - # Set Pmax for generator - if !haskey(ravens_obj, "GeneratingUnit.maxOperatingP") - math_obj["pmax"] = ((get(ravens_obj, "RotatingMachine.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set Pmax and Pmin for generator + if haskey(ravens_obj, "RotatingMachine.GeneratingUnit") + math_obj["pmin"] = ((get(ravens_obj["RotatingMachine.GeneratingUnit"], "GeneratingUnit.minOperatingP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + math_obj["pmax"] = ((get(ravens_obj["RotatingMachine.GeneratingUnit"], "GeneratingUnit.maxOperatingP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) else - math_obj["pmax"] = ((get(ravens_obj, "GeneratingUnit.maxOperatingP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + math_obj["pmin"] = (zeros(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["pmax"] = ((get(ravens_obj, "RotatingMachine.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) end # Set bus type @@ -1414,9 +1416,6 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ data_math["bus"]["$(math_obj["gen_bus"])"]["va"] = [0.0, -120, 120, zeros(length(data_math["bus"]["$(math_obj["gen_bus"])"]) - 3)...][data_math["bus"]["$(math_obj["gen_bus"])"]["terminals"]] end - # Set pmin - math_obj["pmin"] = ((get(ravens_obj, "GeneratingUnit.minOperatingP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set min and max Q if haskey(ravens_obj, "RotatingMachine.minQ") math_obj["qmin"] = ((ravens_obj["RotatingMachine.minQ"] * ones(nconductors)) ./ nconductors)./(power_scale_factor) @@ -1431,7 +1430,7 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ elseif haskey(ravens_obj, "SynchronousMachine.maxQ") math_obj["qmax"] = ((ravens_obj["SynchronousMachine.maxQ"] * ones(nconductors)) ./ nconductors)./(power_scale_factor) else - math_obj["qmax"] = fill(-Inf, nconductors) + math_obj["qmax"] = fill(Inf, nconductors) end # Set pg and qg From d9745f920badc321a78471464a1af13ccaec2b99 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 4 Mar 2025 10:36:10 -0700 Subject: [PATCH 39/99] REF: operational limit for lines to be emerg instead of nominal. --- src/data_model/transformations/ravens2math.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index db1e65b97..b7543e131 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -325,7 +325,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: if (haskey(terminals[1], "ACDCTerminal.OperationalLimitSet")) oplimitset_id = _extract_name(terminals[1]["ACDCTerminal.OperationalLimitSet"]) - oplimitset = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][2] + oplimitset = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][1] # [1] emerg, [2] normal else oplimitset = Dict() end From b70769abe83d8d9409b3bf07ee37d9870dcec4af Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 4 Mar 2025 11:05:00 -0700 Subject: [PATCH 40/99] REF: multinetwork support for new ravens schema using UnitSymbol.w/var --- src/data_model/transformations/ravens2math.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index b7543e131..d16af38af 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1147,7 +1147,8 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end if haskey(schdl, "BasicIntervalSchedule.value1Unit") - value1_unit = lowercase(schdl["BasicIntervalSchedule.value1Unit"]) + unit_symbol = schdl["BasicIntervalSchedule.value1Unit"] + value1_unit = lowercase(unit_symbol[findfirst(isequal('.'), unit_symbol) + 1:end]) if value1_unit == "w" math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / power_scale_factor, nphases) end @@ -1157,7 +1158,8 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end if haskey(schdl, "BasicIntervalSchedule.value2Unit") - value2_unit = lowercase(schdl["BasicIntervalSchedule.value2Unit"]) + unit_symbol = schdl["BasicIntervalSchedule.value2Unit"] + value2_unit = lowercase(unit_symbol[findfirst(isequal('.'), unit_symbol) + 1:end]) if value2_unit == "w" math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / power_scale_factor, nphases) end From 60f1cdb2b8d5510438946e001d3be797c886740c Mon Sep 17 00:00:00 2001 From: Juan Ospina Date: Mon, 10 Mar 2025 11:45:01 -0600 Subject: [PATCH 41/99] Add ravens schema add line geometry (#4) * WIP: Add LineGeometry support for computing impedances and admittances based on WireInfo. * RM: few TODOs in computing z and y for LineGeometries - data available. * WIP: fix issues related to constructing lines using linegeometry * REF: computation for TransformerTank resistance and reactance for combined version. * REF: transformertank resistance and reactance computations for single tanks. Fixed issue related to Terminals in Transformers defined as correct vectors. * RM: unncessary files. * FIX: revert back terminals definitions. --- src/data_model/transformations/ravens2math.jl | 398 ++++++++++++++---- src/data_model/utils_ravens.jl | 15 +- 2 files changed, 327 insertions(+), 86 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index d16af38af..36d61ba86 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -288,7 +288,8 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: for (name, ravens_obj) in get(conductors, "ACLineSegment", Dict{Any,Dict{String,Any}}()) math_obj = _init_math_obj_ravens("ac_line_segment", name, ravens_obj, length(data_math["branch"]) + 1; pass_props=pass_props) - nphases = length(ravens_obj["ACLineSegment.ACLineSegmentPhase"]) + nconds = length(ravens_obj["ACLineSegment.ACLineSegmentPhase"]) # number of conductors/wires + nphases = 0 # init number of phases terminals = ravens_obj["ConductingEquipment.Terminals"] f_node = _extract_name(terminals[1]["Terminal.ConnectivityNode"]) @@ -297,7 +298,17 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj["f_bus"] = data_math["bus_lookup"][f_node] math_obj["t_bus"] = data_math["bus_lookup"][t_node] - bus_terminals = nphases >= 3 ? collect(1:nphases) : [_phase_map[phase["ACLineSegmentPhase.phase"]] for phase in ravens_obj["ACLineSegment.ACLineSegmentPhase"]] + bus_terminals = nconds >= 3 ? collect(1:nconds) : [_phase_map[phase["ACLineSegmentPhase.phase"]] for phase in ravens_obj["ACLineSegment.ACLineSegmentPhase"]] + + # TODO: Kron reduce bus terminals by removing conn 4 + reduce = false # flag for Kron reduction + if 4 in bus_terminals + reduce = true + bus_terminals = filter!(x -> x != 4, bus_terminals) + nphases = nconds - 1 + else + nphases = nconds + end for bus in [math_obj["f_bus"], math_obj["t_bus"]] data_math["bus"][string(bus)]["terminals"] = bus_terminals @@ -309,15 +320,212 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj["f_connections"] = bus_terminals math_obj["t_connections"] = bus_terminals - impedance_name = _extract_name(ravens_obj["ACLineSegment.PerLengthImpedance"]) - impedance_data = data_ravens["PerLengthLineParameter"]["PerLengthImpedance"]["PerLengthPhaseImpedance"][impedance_name] + # System frequency + base_freq = data_math["settings"]["base_frequency"] + + if (haskey(ravens_obj, "ACLineSegment.PerLengthImpedance")) + + impedance_name = _extract_name(ravens_obj["ACLineSegment.PerLengthImpedance"]) + impedance_data = data_ravens["PerLengthLineParameter"]["PerLengthImpedance"]["PerLengthPhaseImpedance"][impedance_name] + + math_obj["br_r"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.r") + math_obj["br_x"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.x") + + for (key, param) in [("b_fr", "PhaseImpedanceData.b"), ("b_to", "PhaseImpedanceData.b"), ("g_fr", "PhaseImpedanceData.g"), ("g_to", "PhaseImpedanceData.g")] + math_obj[key] = _admittance_conversion_ravens(impedance_data, ravens_obj, param) + end + + elseif (haskey(ravens_obj, "ACLineSegment.WireSpacingInfo")) + + # Get WireSpacingInfo + spacinginfo_name = _extract_name(ravens_obj["ACLineSegment.WireSpacingInfo"]) + spacinginfo_data = data_ravens["AssetInfo"]["WireSpacingInfo"][spacinginfo_name] + wire_positions = spacinginfo_data["WireSpacingInfo.WirePositions"] + num_of_wires = length(wire_positions) + + # Coordinates + x_coords = Vector{Float64}(undef, num_of_wires) + y_coords = Vector{Float64}(undef, num_of_wires) + + Threads.@threads for i in 1:1:num_of_wires + x_coords[i] = get(wire_positions[i], "WirePosition.xCoord", 0.0) + y_coords[i] = get(wire_positions[i], "WirePosition.yCoord", 0.0) + end + + # angular frequency + ω = 2π * base_freq + ω₀ = 2π * base_freq + + # Get data for each specific ACLineSegmentPhase + segmentphase_data = ravens_obj["ACLineSegment.ACLineSegmentPhase"] + + # Wire Info. + gmr = Vector{Float64}(undef, nconds) # gmr of Wire, default: radius of wire * 0.7788 + radius = Vector{Float64}(undef, nconds) # radius of Wire + rac = Vector{Float64}(undef, nconds) # AC resistance + rdc = Vector{Float64}(undef, nconds) # DC resistance, default: AC resistance / 1.02 + dcable = Vector{Float64}(undef, nconds) # diameter of Wire: radius of wire * 2 + + # Concentric Neutrals Info. + rstrand = Vector{Float64}(undef, nconds) # resistance of CN cable + nstrand = Vector{Float64}(undef, nconds) # number of CN conductors + dstrand = Vector{Float64}(undef, nconds) # diameter of CN conductor + gmrstrand = Vector{Float64}(undef, nconds) # gmr of CN conductor, default: radius of CN * 0.7788 + + # insulation info. + dins = Vector{Float64}(undef, nconds) # diameter over insulation (over jacket) + tins = Vector{Float64}(undef, nconds) # thickness of insulation + + # tape shield info. + diashield = Vector{Float64}(undef, nconds) + tapelayer = Vector{Float64}(undef, nconds) + tapelap = Vector{Float64}(undef, nconds) + + for i in 1:1:nconds + + wireinfo_name = _extract_name(segmentphase_data[i]["PowerSystemResource.AssetDatasheet"]) + wireinfo_data = data_ravens["AssetInfo"]["WireInfo"][wireinfo_name] + + radius[i] = get(wireinfo_data, "WireInfo.radius", NaN) + @assert radius[i] != NaN "WireInfo radius not found! using NaN. Revise data." + + # Note: gets rewritten as missing if not needed + dcable[i] = radius[i] * 2.0 + + gmr[i] = get(wireinfo_data, "WireInfo.gmr", radius[i] * 0.778) + + if wireinfo_data["Ravens.cimObjectType"] == "OverheadWireInfo" + rac[i] = get(wireinfo_data, "WireInfo.rAC25", NaN) + @assert rac[i] != NaN "WireInfo AC25 resistance is not found! using NaN. Revise input data." + rdc[i] = rac[i] / 1.02 + elseif wireinfo_data["Ravens.cimObjectType"] == "ConcentricNeutralCableInfo" + rdc[i] = get(wireinfo_data, "WireInfo.rDC20", NaN) + @assert rdc[i] != NaN "WireInfo rDC20 resistance is not found! using NaN. Revise input data." + rac[i] = rdc[i] * 1.02 + else + @error("Cable type not supported. Resistances (AC or DC) not found!") + end + + # Concentric Neutrals Information. + rstrand[i] = get(wireinfo_data, "ConcentricNeutralCableInfo.neutralStrandRDC20", NaN) + nstrand[i] = get(wireinfo_data, "ConcentricNeutralCableInfo.neutralStrandCount", NaN) + dstrand[i] = get(wireinfo_data, "ConcentricNeutralCableInfo.neutralStrandRadius", NaN) * 2.0 + gmrstrand[i] = get(wireinfo_data, "ConcentricNeutralCableInfo.neutralStrandGmr", (dstrand[i]/2.0) * 0.778) + + # insulation information + dins[i] = get(wireinfo_data, "CableInfo.diameterOverJacket", NaN) + tins[i] = get(wireinfo_data, "WireInfo.insulationThickness", NaN) + + # TODO: tape shielded cables information + diashield[i] = NaN + tapelayer[i] = NaN + tapelap[i] = NaN + + end + + # Check for NaNs and replace with missing. + rstrand = findfirst(isnan, rstrand) !== nothing ? missing : rstrand + nstrand = findfirst(isnan, nstrand) !== nothing ? missing : nstrand + dcable = findfirst(isnan, dstrand) !== nothing ? missing : dcable # use dstrand as signal for dcable to be missing + dstrand = findfirst(isnan, dstrand) !== nothing ? missing : dstrand + gmrstrand = findfirst(isnan, gmrstrand) !== nothing ? missing : gmrstrand + epsr = findfirst(isnan, dins) !== nothing ? missing : ones(nconds).*2.3 # use dins as signal for epsr to be missing + dins = findfirst(isnan, dins) !== nothing ? missing : dins + tins = findfirst(isnan, tins) !== nothing ? missing : tins + diashield = findfirst(isnan, diashield) !== nothing ? missing : diashield + tapelayer = findfirst(isnan, tapelayer) !== nothing ? missing : tapelayer + tapelap = findfirst(isnan, tapelap) !== nothing ? missing : tapelap + + # TODO: earth model (using default) + earth_model = "deri" + + # rho (default) - ρ = earth resistivity = 100 Ω-m + rho = 100 + + # @info "*********************************" + # @info "NAME: $(name)" + # @info "XCOORDS: $(x_coords)" + # @info "YCOORDS: $(y_coords)" + # @info "W: $(ω)" + # @info "GMR: $(gmr)" + # @info "RADIUS: $(radius)" + # @info "NCONDS: $(nconds)" + # @info "EARTH: $(earth_model)" + # @info "RAC: $(rac)" + # @info "WO: $(ω₀)" + # @info "RDC: $(rdc)" + # @info "RHO: $(rho)" + # @info "NPHASES: $(nphases)" + # @info "RSTRAND: $(rstrand)" + # @info "NSTRAND: $(nstrand)" + # @info "DCABLE: $(dcable)" + # @info "DTRAND: $(dstrand)" + # @info "GMRSTRAND: $(gmrstrand)" + # @info "EPSR: $(epsr)" + # @info "DINS: $(dins)" + # @info "TINS: $(tins)" + # @info "DIASHIELD: $(diashield)" + # @info "TAPELAYER: $(tapelayer)" + # @info "TAPELAP: $(tapelap)" + + # Calculate line constants + z, y = calculate_line_constants( + x_coords, + y_coords, + ω, + gmr, + radius, + nconds, # TODO: check if nwires or nconds + earth_model, + rac, + ω₀, + rdc, + rho, + nphases, # TODO: check if nconds or nphases + rstrand, + nstrand, + dcable, + dstrand, + gmrstrand, + epsr, + dins, + tins, + diashield, + tapelayer, + tapelap + ) + + # TODO: Kron reduction + if reduce + z, y = _kron(z, y, nphases) + end + + rs, xs = real(z), imag(z) + g, b = real(y), imag(y) + + b_fr = (b ./ 2.0) .* base_freq + b_to = (b ./ 2.0) .* base_freq + g_fr = (g ./ 2.0) .* base_freq + g_to = (g ./ 2.0) .* base_freq + + math_obj["br_r"] = _impedance_conversion_ravens(ravens_obj, rs) + math_obj["br_x"] = _impedance_conversion_ravens(ravens_obj, xs) + + math_obj["b_fr"] = _admittance_conversion_ravens(ravens_obj, b_fr) + math_obj["b_to"] = _admittance_conversion_ravens(ravens_obj, b_to) + + math_obj["g_fr"] = _admittance_conversion_ravens(ravens_obj, g_fr) + math_obj["g_to"] = _admittance_conversion_ravens(ravens_obj, g_to) + + # @info "$( math_obj["br_r"])" + # @info "$( math_obj["br_x"])" + # @info "$( math_obj["b_fr"])" + # @info "$( math_obj["b_to"])" + # @info "$( math_obj["g_fr"])" + # @info "$( math_obj["g_to"])" + # @info "*********************************" - math_obj["br_r"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.r") - math_obj["br_x"] = _impedance_conversion_ravens(impedance_data, ravens_obj, "PhaseImpedanceData.x") - base_freq = data_math["settings"]["base_frequency"] - for (key, param) in [("b_fr", "PhaseImpedanceData.b"), ("b_to", "PhaseImpedanceData.b"), ("g_fr", "PhaseImpedanceData.g"), ("g_to", "PhaseImpedanceData.g")] - math_obj[key] = _admittance_conversion_ravens(impedance_data, ravens_obj, param) end math_obj["angmin"] = get(ravens_obj, "vad_lb", fill(-60.0, nphases)) @@ -430,25 +638,32 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data end # wdgs configurations - if wdgs[wdg_id]["PowerTransformerEnd.connectionKind"] == "WindingConnection.Y" + if wdgs[wdg_endNumber]["PowerTransformerEnd.connectionKind"] == "WindingConnection.Y" || wdgs[wdg_endNumber]["PowerTransformerEnd.connectionKind"] == "WindingConnection.Yn" wdgs_confs[wdg_endNumber] = WYE - elseif wdgs[wdg_id]["PowerTransformerEnd.connectionKind"] == "WindingConnection.D" + elseif wdgs[wdg_endNumber]["PowerTransformerEnd.connectionKind"] == "WindingConnection.D" wdgs_confs[wdg_endNumber] = DELTA else @error("PowerTransformer ConnectionKind not supported yet!") end # Transformer data for each winding - vnom[wdg_id] = wdgs[wdg_id]["PowerTransformerEnd.ratedU"] - snom[wdg_id] = wdgs[wdg_id]["PowerTransformerEnd.ratedS"] - r_s[wdg_id] = wdgs[wdg_id]["PowerTransformerEnd.r"] - if haskey(wdgs[wdg_id], "TransformerEnd.MeshImpedance") - x_sc[wdg_id] = get(wdgs[wdg_id]["TransformerEnd.MeshImpedance"], "TransformerMeshImpedance.x", 0.0) - end - if haskey(wdgs[wdg_id], "TransformerEnd.CoreAdmittance") - g_sh[wdg_id] = get(wdgs[wdg_id]["TransformerEnd.CoreAdmittance"], "TransformerCoreAdmittance.g", 0.0) - b_sh[wdg_id] = - get(wdgs[wdg_id]["TransformerEnd.CoreAdmittance"], "TransformerCoreAdmittance.b", 0.0) - end + vnom[wdg_endNumber] = wdgs[wdg_endNumber]["PowerTransformerEnd.ratedU"] + snom[wdg_endNumber] = wdgs[wdg_endNumber]["PowerTransformerEnd.ratedS"] + + # resistance + transf_star_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.StarImpedance", Dict()) + r_s[wdg_endNumber] = get(wdgs[wdg_endNumber], "PowerTransformerEnd.r", + get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)) + + # reactance + transf_mesh_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.MeshImpedance", Dict()) + x_sc[wdg_endNumber] = get(transf_mesh_impedance, "TransformerMeshImpedance.x", + get(transf_star_impedance, "TransformerStarImpedance.x", 0.0)) + + # admittance + transf_core_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.CoreAdmittance", Dict()) + g_sh[wdg_id] = get(transf_core_impedance, "TransformerCoreAdmittance.g", 0.0) + b_sh[wdg_id] = - get(transf_core_impedance, "TransformerCoreAdmittance.b", 0.0) # TODO: RatioTapChanger if haskey(wdgs[wdg_id], "TransformerEnd.RatioTapChanger") @@ -572,7 +787,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # init nodes vector for combined transformer windings nodes = ["" for _ in 1:nrw] - # nodes = [Vector{String}(undef, nphases) for _ in 1:nrw] # init rs, x_sc, g_sh, and b_sh data per wdg/tank(phase) r_s = [zeros(Float64, nphases) for _ in 1:nrw] @@ -628,34 +842,39 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data @error("PhaseCode not supported yet!") end - # transformer tank end info. transf_end_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] vnom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedU"] snom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedS"] - leak_impedance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] - resistance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.r"] zbase = (vnom_wdg^2) / snom_wdg ratios = vnom_wdg/voltage_scale_factor # assign vnom_wdg to vnom for transformer vnom[wdg_endNumber] = vnom_wdg - # compute r_s, x_sc, g_sh, and b_sh per winding per tank (when needed) - r_s[wdg_endNumber][tank_id] = resistance_wdg # rs is specified with respect to each winding - x_sc[wdg_endNumber][tank_id] = (sqrt((leak_impedance_wdg / zbase)^2 - ((resistance_wdg*100.0 / zbase)*2)^2)/100.0)*zbase + # resistance computation + transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) + r_s[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", + get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)) + r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios^2 - # data is measured externally, but we now refer it to the internal side + # reactance computation + x_sc[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.x", + get(transf_star_impedance, "TransformerStarImpedance.x", 0.0)) + # -- alternative computation of xsc using sc tests + if haskey(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndShortCircuitTests") + leak_impedance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] + x_sc[wdg_endNumber][tank_id] = (sqrt((leak_impedance_wdg / zbase)^2 - ((r_s[wdg_endNumber][tank_id]*100.0 / zbase)*2)^2)/100.0)*zbase + end x_sc[wdg_endNumber][tank_id] = (x_sc[wdg_endNumber][tank_id]/ratios^2) - r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios^2 # g_sh always with respect to wdg #1 always if wdg_endNumber == 1 - loss = transf_end_info[1]["TransformerEndInfo.EnergisedEndNoLoadTests"][1]["NoLoadTest.loss"] + transf_end_noloadtest = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndNoLoadTests", [Dict()]) + loss = get(transf_end_noloadtest[1], "NoLoadTest.loss", 0.0) g_sh_tank = (loss*snom_wdg)/zbase - exct_current = transf_end_info[1]["TransformerEndInfo.EnergisedEndNoLoadTests"][1]["NoLoadTest.excitingCurrent"] - b_sh_tank = -((sqrt((exct_current)^2 - (loss/(0.01*snom_wdg))^2))/(100.0*zbase)) - + exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", 0.0) + b_sh_tank = -((sqrt(abs((exct_current)^2 - (loss/(0.01*snom_wdg))^2)))/(100.0*zbase)) # data is measured externally, but we now refer it to the internal side g_sh[tank_id] = g_sh_tank*ratios^2 b_sh[tank_id] = b_sh_tank*ratios^2 @@ -663,7 +882,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # configuration conf = transf_end_info[wdg_endNumber]["TransformerEndInfo.connectionKind"] - if conf == "WindingConnection.Y" || conf == "WindingConnection.I" + if conf == "WindingConnection.Y" || conf == "WindingConnection.I" || conf == "WindingConnection.Yn" configuration[wdg_endNumber] = WYE elseif conf == "WindingConnection.D" configuration[wdg_endNumber] = DELTA @@ -707,8 +926,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data vnom_prev = deepcopy(vnom) end - ### --------------------- - end @@ -822,10 +1039,12 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data connections = Vector{Vector{Int64}}(undef, nrw) # wdgs data vectors - vnom_wdgs = Vector{Float64}(undef, nrw) - snom_wdgs = Vector{Float64}(undef, nrw) - leak_impedance = Vector{Float64}(undef, nrw) - resistance = Vector{Float64}(undef, nrw) + vnom = zeros(Float64, nrw) + # init rs, x_sc, g_sh, and b_sh data per wdg + r_s = zeros(Float64, nrw) + x_sc = zeros(Float64, nrw) + g_sh = 0.0 + b_sh = 0.0 # configurations wdgs_confs = Vector{ConnConfig}(undef, nrw) @@ -850,7 +1069,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # connections (based on _phasecode_map) if haskey(_phasecode_map, wdg_phasecode) wdg_connections = _phasecode_map[wdg_phasecode] - connections[wdg_id] = wdg_connections + connections[wdg_endNumber] = wdg_connections else @error("PhaseCode not supported yet!") end @@ -865,62 +1084,71 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # transformer tank end info. transf_end_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] - vnom_wdgs[wdg_id] = transf_end_info[wdg_id]["TransformerEndInfo.ratedU"] - snom_wdgs[wdg_id] = transf_end_info[wdg_id]["TransformerEndInfo.ratedS"] - leak_impedance[wdg_id] = transf_end_info[wdg_id]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] - resistance[wdg_id] = transf_end_info[wdg_id]["TransformerEndInfo.r"] + vnom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedU"] + snom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedS"] + + zbase = (vnom_wdg^2) / snom_wdg + ratios = vnom_wdg/voltage_scale_factor + + # assign vnom_wdg to vnom for transformer + vnom[wdg_endNumber] = vnom_wdg + + # resistance computation + transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) + r_s[wdg_endNumber] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", + get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)) + r_s[wdg_endNumber] = r_s[wdg_endNumber]/ratios^2 + + # reactance computation + x_sc[wdg_endNumber] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.x", + get(transf_star_impedance, "TransformerStarImpedance.x", 0.0)) + # -- alternative computation of xsc using sc tests + if haskey(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndShortCircuitTests") + leak_impedance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] + x_sc[wdg_endNumber] = (sqrt((leak_impedance_wdg / zbase)^2 - ((r_s[wdg_endNumber]*100.0 / zbase)*2)^2)/100.0)*zbase + end + x_sc[wdg_endNumber] = (x_sc[wdg_endNumber]/ratios^2) + + # g_sh always with respect to wdg #1 always + if wdg_endNumber == 1 + transf_end_noloadtest = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndNoLoadTests", [Dict()]) + loss = get(transf_end_noloadtest[1], "NoLoadTest.loss", 0.0) + g_sh_tank = (loss*snom_wdg)/zbase + exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", 0.0) + b_sh_tank = -((sqrt(abs((exct_current)^2 - (loss/(0.01*snom_wdg))^2)))/(100.0*zbase)) + # data is measured externally, but we now refer it to the internal side + g_sh = g_sh_tank*ratios^2 + b_sh = b_sh_tank*ratios^2 + end # wdgs configurations - wdg_conf = transf_end_info[wdg_id]["TransformerEndInfo.connectionKind"] # extract wdg conf - if wdg_conf == "WindingConnection.Y" || wdg_conf == "WindingConnection.I" - wdgs_confs[wdg_id] = WYE + wdg_conf = transf_end_info[wdg_endNumber]["TransformerEndInfo.connectionKind"] # extract wdg conf + if wdg_conf == "WindingConnection.Y" || wdg_conf == "WindingConnection.I" || wdg_conf == "WindingConnection.Yn" + wdgs_confs[wdg_endNumber] = WYE elseif wdg_conf == "WindingConnection.D" - wdgs_confs[wdg_id] = DELTA + wdgs_confs[wdg_endNumber] = DELTA else @error("PowerTransformer ConnectionKind not supported yet!") end # TODO: RatioTapChanger - if haskey(wdgs_data[wdg_id], "TransformerEnd.RatioTapChanger") + if haskey(wdgs_data[wdg_endNumber], "TransformerEnd.RatioTapChanger") # TODO: default for now, but needs to be corrected! - tm_set[wdg_id] = fill(1.0, nphases) - tm_lb[wdg_id] = fill(0.9, nphases) - tm_ub[wdg_id] = fill(1.1, nphases) - tm_fix[wdg_id] = ones(Bool, nphases) - tm_step[wdg_id] = fill(1/32, nphases) + tm_set[wdg_endNumber] = fill(1.0, nphases) + tm_lb[wdg_endNumber] = fill(0.9, nphases) + tm_ub[wdg_endNumber] = fill(1.1, nphases) + tm_fix[wdg_endNumber] = ones(Bool, nphases) + tm_step[wdg_endNumber] = fill(1/32, nphases) else # default - tm_set[wdg_id] = fill(1.0, nphases) - tm_lb[wdg_id] = fill(0.9, nphases) - tm_ub[wdg_id] = fill(1.1, nphases) - tm_fix[wdg_id] = ones(Bool, nphases) - tm_step[wdg_id] = fill(1/32, nphases) + tm_set[wdg_endNumber] = fill(1.0, nphases) + tm_lb[wdg_endNumber] = fill(0.9, nphases) + tm_ub[wdg_endNumber] = fill(1.1, nphases) + tm_fix[wdg_endNumber] = ones(Bool, nphases) + tm_step[wdg_endNumber] = fill(1/32, nphases) end end - # calculate zbase in which the data is specified, and convert to SI - zbase = (vnom_wdgs.^2) ./ snom_wdgs - - # x_sc computed from leak impedance - x_sc = (sqrt.((leak_impedance ./ zbase).^2 - ((resistance.*100.0 ./ zbase)*2).^2)./100.0).*zbase - - # rs is specified with respect to each winding - r_s = resistance - - # g_sh always with respect to wdg #1 - loss = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"][1]["TransformerEndInfo.EnergisedEndNoLoadTests"][1]["NoLoadTest.loss"] - g_sh = (loss*snom_wdgs[1])/zbase[1] - - exct_current = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"][1]["TransformerEndInfo.EnergisedEndNoLoadTests"][1]["NoLoadTest.excitingCurrent"] - b_sh = -((sqrt((exct_current)^2 - (loss/(0.01*snom_wdgs[1]))^2))/(100.0*zbase[1])) - - # data is measured externally, but we now refer it to the internal side - ratios = vnom_wdgs/voltage_scale_factor - x_sc = (x_sc./ratios.^2) - r_s = r_s./ratios.^2 - g_sh = g_sh*ratios[1]^2 - b_sh = b_sh*ratios[1]^2 - # convert x_sc from list of upper triangle elements to an explicit dict y_sh = g_sh + im*b_sh z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) @@ -958,7 +1186,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data wdg_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] # make virtual bus and mark it for reduction - tm_nom = wdgs_confs[wdg_id]==DELTA ? vnom_wdgs[wdg_id]*sqrt(3)/voltage_scale_factor : vnom_wdgs[wdg_id]/voltage_scale_factor + tm_nom = wdgs_confs[wdg_id]==DELTA ? vnom[wdg_id]*sqrt(3)/voltage_scale_factor : vnom[wdg_id]/voltage_scale_factor # Get correct f_node for winding wdg_term = wdgs_data[wdg_id]["ConductingEquipment.Terminals"][1] diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 54f09b75b..eab10860c 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -11,7 +11,8 @@ const _phasecode_map = Dict( _phase_map = Dict( "SinglePhaseKind.A" => 1, "SinglePhaseKind.B" => 2, - "SinglePhaseKind.C" => 3 + "SinglePhaseKind.C" => 3, + "SinglePhaseKind.N" => 4 ) const _multipliers_map = Dict( @@ -43,6 +44,18 @@ function _init_math_obj_ravens(obj_type::String, eng_id::Any, eng_obj::Dict{Stri end +"converts impendance in Ohm/m by multiplying by length" +function _impedance_conversion_ravens(eng_obj::Dict{String,<:Any}, vals::Matrix{Float64}) + return vals .* get(eng_obj, "Conductor.length", 1.0) +end + + +"converts admittance by multiplying by 2πωl" +function _admittance_conversion_ravens(eng_obj::Dict{String,<:Any}, vals::Matrix{Float64}) + 2.0 .* pi .* vals .* get(eng_obj, "Conductor.length", 1.0) ./ 1e9 +end + + "converts impendance in Ohm/m by multiplying by length" function _impedance_conversion_ravens(data_eng::Dict{String,Any}, eng_obj::Dict{String,Any}, key::String) From 9056a666258c383ac06e94b9329dddd28054c3b5 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 10 Mar 2025 11:49:10 -0600 Subject: [PATCH 42/99] FIX: BatteryUnitEfficiency and add newly converted ravens test cases. --- src/data_model/transformations/ravens2math.jl | 21 +- test/data/ravens/ravens_case3_withcap.json | 723 ++++++++------- test/data/ravens/ravens_case3_withgens.json | 864 +++++++++--------- .../ravens/ravens_case3_withpvandstorage.json | 777 ++++++++-------- 4 files changed, 1224 insertions(+), 1161 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 36d61ba86..57cd7dc7b 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1701,7 +1701,7 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data for (name, ravens_obj) in get(regulating_cond_eq, "PowerElectronicsConnection", Dict{Any,Dict{String,Any}}()) # Get type of PowerElectronicsUnit - pec_type = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "Ravens.CimObjectType", "") + pec_type = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "Ravens.cimObjectType", "") if (pec_type == "PhotoVoltaicUnit") @@ -1803,10 +1803,19 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data # Set battery parameters math_obj["energy"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.storedE"]/power_scale_factor - if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.limitEnergy") + if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "BatteryUnit.BatteryUnitEfficiency") math_obj["energy_rating"] = ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.ratedE"]/power_scale_factor + math_obj["charge_efficiency"] = 100.0 + math_obj["discharge_efficiency"] = 100.0 + math_obj["p_loss"] = 0 + math_obj["q_loss"] = 0 else - math_obj["energy_rating"] = ((ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["InefficientBatteryUnit.limitEnergy"]/100)*ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.ratedE"])/power_scale_factor + math_obj["energy_rating"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.BatteryUnitEfficiency"], "BatteryUnitEfficiency.limitEnergy", 100.0)/100.0)*ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["BatteryUnit.ratedE"])/power_scale_factor + math_obj["charge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "BatteryUnitEfficiency.efficiencyCharge", 100.0) / 100.0 + math_obj["discharge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "BatteryUnitEfficiency.efficiencyDischarge", 100.0) / 100.0 + # TODO: These are still missing from the RAVENS Schema + math_obj["p_loss"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "BatteryUnitEfficiency.idlingActivePower", 0)./(power_scale_factor) + math_obj["q_loss"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "BatteryUnitEfficiency.idlingReactivePower", 0)./(power_scale_factor) end if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") @@ -1817,8 +1826,6 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data math_obj["discharge_rating"] = (get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf))./(power_scale_factor) end - math_obj["charge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.efficiencyCharge", 100.0) / 100.0 - math_obj["discharge_efficiency"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.efficiencyDischarge", 100.0) / 100.0 math_obj["thermal_rating"] = get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf)/power_scale_factor math_obj["qmin"] = (get(ravens_obj, "PowerElectronicsConnection.minQ", -math_obj["discharge_rating"]*power_scale_factor))./(power_scale_factor) @@ -1828,10 +1835,6 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data math_obj["r"] = get(ravens_obj, "PowerElectronicsConnection.r", 0) math_obj["x"] = get(ravens_obj, "PowerElectronicsConnection.x", 0) - # TODO: These are still missing from the RAVENS Schema - math_obj["p_loss"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.idlingActivePower", 0)./(power_scale_factor) - math_obj["q_loss"] = get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "InefficientBatteryUnit.idlingReactivePower", 0)./(power_scale_factor) - # TODO: control mode do not exist in the RAVENS-CIM (Need to be added) math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) diff --git a/test/data/ravens/ravens_case3_withcap.json b/test/data/ravens/ravens_case3_withcap.json index a6c2118ef..7ded2d307 100644 --- a/test/data/ravens/ravens_case3_withcap.json +++ b/test/data/ravens/ravens_case3_withcap.json @@ -1,235 +1,13 @@ { - "PerLengthLineParameter": { - "PerLengthImpedance": { - "PerLengthPhaseImpedance": { - "4/0quad": { - "Ravens.CimObjectType": "PerLengthPhaseImpedance", - "IdentifiedObject.mRID": "b9ede34e-a50f-4afc-b83e-f3cd0578a600", - "IdentifiedObject.name": "4/0quad", - "PerLengthPhaseImpedance.conductorCount": 3, - "PerLengthPhaseImpedance.PhaseImpedanceData": [ - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.0467, - "PhaseImpedanceData.x": 0.0267, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.1167, - "PhaseImpedanceData.x": 0.0667, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.0467, - "PhaseImpedanceData.x": 0.0267, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 1, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.1167, - "PhaseImpedanceData.x": 0.0667, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 3, - "PhaseImpedanceData.r": 0.1167, - "PhaseImpedanceData.x": 0.0667, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.0467, - "PhaseImpedanceData.x": 0.0267, - "PhaseImpedanceData.b": -0.0 - } - ] - }, - "556mcm": { - "Ravens.CimObjectType": "PerLengthPhaseImpedance", - "IdentifiedObject.mRID": "c71a840c-a77b-4be6-b20e-8a372d0af874", - "IdentifiedObject.name": "556mcm", - "PerLengthPhaseImpedance.conductorCount": 3, - "PerLengthPhaseImpedance.PhaseImpedanceData": [ - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 3, - "PhaseImpedanceData.r": 0.1, - "PhaseImpedanceData.x": 0.0583, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.04, - "PhaseImpedanceData.x": 0.0233, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.04, - "PhaseImpedanceData.x": 0.0233, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.04, - "PhaseImpedanceData.x": 0.0233, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 1, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.1, - "PhaseImpedanceData.x": 0.0583, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.1, - "PhaseImpedanceData.x": 0.0583, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - } - ] - } - } - } - }, "PowerSystemResource": { "Equipment": { "ConductingEquipment": { - "Conductor": { - "ACLineSegment": { - "quad": { - "Ravens.CimObjectType": "ACLineSegment", - "IdentifiedObject.mRID": "f501b03c-aee6-4524-a253-3adc0a016c92", - "IdentifiedObject.name": "quad", - "Conductor.length": 1.0, - "Equipment.inService": true, - "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", - "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", - "ACLineSegment.ACLineSegmentPhase": [ - { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "9cce4dc1-447a-435f-ae0f-8b31058209b7", - "IdentifiedObject.name": "quad_A", - "ACLineSegmentPhase.phase": "SinglePhaseKind.A", - "ACLineSegmentPhase.sequenceNumber": 1 - }, - { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "349837bd-1743-4fdd-9305-129146cf7048", - "IdentifiedObject.name": "quad_B", - "ACLineSegmentPhase.phase": "SinglePhaseKind.B", - "ACLineSegmentPhase.sequenceNumber": 2 - }, - { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "31349b5e-6351-4ccb-8462-1f2717f03565", - "IdentifiedObject.name": "quad_C", - "ACLineSegmentPhase.phase": "SinglePhaseKind.C", - "ACLineSegmentPhase.sequenceNumber": 3 - } - ], - "ConductingEquipment.Terminals": [ - { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "645b55d4-e061-4163-b1ba-d0d74395a42c", - "IdentifiedObject.name": "quad_T1", - "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" - }, - { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "208c5aea-a854-4124-b365-c69677b1a5b2", - "IdentifiedObject.name": "quad_T2", - "ACDCTerminal.sequenceNumber": 2, - "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" - } - ] - }, - "ohline": { - "Ravens.CimObjectType": "ACLineSegment", - "IdentifiedObject.mRID": "ea549d70-b21a-4132-a5d2-ef9996f6c0ea", - "IdentifiedObject.name": "ohline", - "Conductor.length": 1.0, - "Equipment.inService": true, - "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", - "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", - "ACLineSegment.ACLineSegmentPhase": [ - { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "b3094d11-632b-489b-a645-fa006dde1367", - "IdentifiedObject.name": "ohline_A", - "ACLineSegmentPhase.phase": "SinglePhaseKind.A", - "ACLineSegmentPhase.sequenceNumber": 1 - }, - { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "5191b2b6-09ee-44d5-b3a8-17de5b345216", - "IdentifiedObject.name": "ohline_B", - "ACLineSegmentPhase.phase": "SinglePhaseKind.B", - "ACLineSegmentPhase.sequenceNumber": 2 - }, - { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "d8523544-a3e0-466a-94ab-b68dbdf4f36a", - "IdentifiedObject.name": "ohline_C", - "ACLineSegmentPhase.phase": "SinglePhaseKind.C", - "ACLineSegmentPhase.sequenceNumber": 3 - } - ], - "ConductingEquipment.Terminals": [ - { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "d15f3652-af59-4f84-a4d4-b218c4ad6b2a", - "IdentifiedObject.name": "ohline_T1", - "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" - }, - { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "c72fbd81-3362-436d-be2b-ebff11174263", - "IdentifiedObject.name": "ohline_T2", - "ACDCTerminal.sequenceNumber": 2, - "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" - } - ] - } - } - }, "EnergyConnection": { "EnergyConsumer": { - "l1": { - "Ravens.CimObjectType": "EnergyConsumer", - "IdentifiedObject.mRID": "8bef6e0f-813f-4cd5-9613-4fe60e159e7b", - "IdentifiedObject.name": "l1", + "l2": { + "Ravens.cimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "4e4702cf-7f18-44c3-93f9-93821ed0c4e6", + "IdentifiedObject.name": "l2", "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, @@ -240,29 +18,30 @@ "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "09eb27e3-654c-4823-bdce-51fc6b3dbffe", - "IdentifiedObject.name": "l1_T1", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "ce89b6cf-4c5a-4676-bbab-25d93f5807b4", + "IdentifiedObject.name": "l2_T1", "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.A", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.phases": "PhaseCode.B", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" } ], "EnergyConsumer.EnergyConsumerPhase": [ { - "Ravens.CimObjectType": "EnergyConsumerPhase", - "IdentifiedObject.mRID": "317c70ec-5985-482f-b515-bf94de7eef00", - "IdentifiedObject.name": "l1_A", + "Ravens.cimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "b40a48ed-24f4-429d-bd16-1f0d4b2cfc04", + "IdentifiedObject.name": "l2_B", "EnergyConsumerPhase.p": 6000.0, "EnergyConsumerPhase.q": 3000.0, - "EnergyConsumerPhase.phase": "SinglePhaseKind.A" + "EnergyConsumerPhase.phase": "SinglePhaseKind.B" } ] }, - "l2": { - "Ravens.CimObjectType": "EnergyConsumer", - "IdentifiedObject.mRID": "92d0f990-dc53-4496-86a7-25244905f08e", - "IdentifiedObject.name": "l2", + "l3": { + "Ravens.cimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "38b13fa4-3f89-44f9-9d73-a450e25ae2c1", + "IdentifiedObject.name": "l3", "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, @@ -273,29 +52,30 @@ "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "d4cb98f1-86d4-4860-aafd-563dd86e7a52", - "IdentifiedObject.name": "l2_T1", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "04a05739-b1a0-419e-8cfc-a38fcb5a8b2d", + "IdentifiedObject.name": "l3_T1", "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.B", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.phases": "PhaseCode.C", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" } ], "EnergyConsumer.EnergyConsumerPhase": [ { - "Ravens.CimObjectType": "EnergyConsumerPhase", - "IdentifiedObject.mRID": "d20c16f2-db2b-459a-81f1-535a1559c762", - "IdentifiedObject.name": "l2_B", + "Ravens.cimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "a7f35df2-55b8-4541-847e-b81dc7bcb7f7", + "IdentifiedObject.name": "l3_C", "EnergyConsumerPhase.p": 6000.0, "EnergyConsumerPhase.q": 3000.0, - "EnergyConsumerPhase.phase": "SinglePhaseKind.B" + "EnergyConsumerPhase.phase": "SinglePhaseKind.C" } ] }, - "l3": { - "Ravens.CimObjectType": "EnergyConsumer", - "IdentifiedObject.mRID": "6bc98558-9400-4d89-a6fe-54ccaee27b38", - "IdentifiedObject.name": "l3", + "l1": { + "Ravens.cimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "671deb49-478c-4e01-afb3-e5493b79e7a9", + "IdentifiedObject.name": "l1", "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, @@ -306,30 +86,31 @@ "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "701902a4-7dab-40eb-b1f6-f5008e5fcb9c", - "IdentifiedObject.name": "l3_T1", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "969c99fd-7a05-4e7d-a11c-5adb91529509", + "IdentifiedObject.name": "l1_T1", "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.C", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.phases": "PhaseCode.A", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" } ], "EnergyConsumer.EnergyConsumerPhase": [ { - "Ravens.CimObjectType": "EnergyConsumerPhase", - "IdentifiedObject.mRID": "cdacb568-8574-4002-9635-64a893e4a2b0", - "IdentifiedObject.name": "l3_C", + "Ravens.cimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "af3f616f-5a03-494e-a2aa-66d41c0e8983", + "IdentifiedObject.name": "l1_A", "EnergyConsumerPhase.p": 6000.0, "EnergyConsumerPhase.q": 3000.0, - "EnergyConsumerPhase.phase": "SinglePhaseKind.C" + "EnergyConsumerPhase.phase": "SinglePhaseKind.A" } ] } }, "EnergySource": { "source": { - "Ravens.CimObjectType": "EnergySource", - "IdentifiedObject.mRID": "c0d17284-08ca-46f4-899a-5a87055acd9a", + "Ravens.cimObjectType": "EnergySource", + "IdentifiedObject.mRID": "d2849b1b-7772-4d4a-949d-5de0554cbd4c", "IdentifiedObject.name": "source", "EnergySource.nominalVoltage": 400.0, "EnergySource.voltageMagnitude": 398.36, @@ -342,8 +123,8 @@ "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "2709c1dc-e81b-41c1-9cdb-262c3df42a9e", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "8cb856e5-8b34-47d6-9bc7-15b21e52e53d", "IdentifiedObject.name": "source_T1", "ACDCTerminal.sequenceNumber": 1, "Terminal.phases": "PhaseCode.ABC", @@ -355,55 +136,164 @@ "RegulatingCondEq": { "ShuntCompensator": { "c1": { - "Ravens.CimObjectType": "LinearShuntCompensator", - "IdentifiedObject.mRID": "41f54a4b-8980-4117-9aaf-985c316768ea", + "Ravens.cimObjectType": "LinearShuntCompensator", + "IdentifiedObject.mRID": "40b072d2-1459-4810-ae25-7d1af553084b", "IdentifiedObject.name": "c1", "ShuntCompensator.nomU": 400.0, "LinearShuntCompensator.bPerSection": 0.12499999999999997, "LinearShuntCompensator.gPerSection": 0.0, - "ShuntCompensator.phaseConnection": "ShuntConnectionKind.Y", + "ShuntCompensator.phaseConnection": "PhaseShuntConnectionKind.Y", "LinearShuntCompensator.b0PerSection": 0.12499999999999997, "LinearShuntCompensator.g0PerSection": 0.0, - "LinearShuntCompensator.normalSections": 1, - "LinearShuntCompensator.maximumSections": 1, + "ShuntCompensator.normalSections": 1, + "ShuntCompensator.maximumSections": 1, "Equipment.inService": true, - "LinearShuntCompensator.aVRDelay": 0.0, - "ShuntCompensator.sections": 1, + "ShuntCompensator.aVRDelay": 0.0, + "ShuntCompensator.sections": 1.0, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "6095aca4-7c9c-4d4e-801c-469a47c6b595", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "8c18dcac-6986-452f-93c1-9f3c5f8e7e28", "IdentifiedObject.name": "c1_T1", "ACDCTerminal.sequenceNumber": 1, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_38.97114317029974_51.96152422706632'" } ] } } } + }, + "Conductor": { + "ACLineSegment": { + "quad": { + "Ravens.cimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "fc5789c3-b0d4-43cb-b486-df1fa52f5a00", + "IdentifiedObject.name": "quad", + "Equipment.inService": true, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "Conductor.length": 1.0, + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", + "ConductingEquipment.Terminals": [ + { + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "b40a4567-9713-40ef-8d44-cd1611fba66a", + "IdentifiedObject.name": "quad_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" + }, + { + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "30427167-38f0-4fc0-a30c-505b84288e11", + "IdentifiedObject.name": "quad_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" + } + ], + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "7a34457b-4055-4c69-b100-1b98092a55d1", + "IdentifiedObject.name": "quad_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "dfa50ff9-7061-491d-abaa-06abd224c925", + "IdentifiedObject.name": "quad_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "3e42579c-92ee-4299-aee2-83637f0e8dc8", + "IdentifiedObject.name": "quad_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ] + }, + "ohline": { + "Ravens.cimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "617cbf5b-db10-4c5a-9a69-f72b5d05c6d4", + "IdentifiedObject.name": "ohline", + "Equipment.inService": true, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "Conductor.length": 1.0, + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", + "ConductingEquipment.Terminals": [ + { + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "93792d12-16fe-48de-8654-c1e2d6b4275f", + "IdentifiedObject.name": "ohline_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" + }, + { + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "f9676c55-dd17-442a-ac75-30aab306e0ff", + "IdentifiedObject.name": "ohline_T2", + "ACDCTerminal.sequenceNumber": 2, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" + } + ], + "ACLineSegment.ACLineSegmentPhase": [ + { + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "4ba78bf5-e98a-4a57-95a6-9a5a3b3bef04", + "IdentifiedObject.name": "ohline_A", + "ACLineSegmentPhase.phase": "SinglePhaseKind.A", + "ACLineSegmentPhase.sequenceNumber": 1 + }, + { + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "a569f9bc-d0b6-4598-b6fc-b82d9a8265ef", + "IdentifiedObject.name": "ohline_B", + "ACLineSegmentPhase.phase": "SinglePhaseKind.B", + "ACLineSegmentPhase.sequenceNumber": 2 + }, + { + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "4dcb9f1e-388f-4159-acc9-5a0eadf49765", + "IdentifiedObject.name": "ohline_C", + "ACLineSegmentPhase.phase": "SinglePhaseKind.C", + "ACLineSegmentPhase.sequenceNumber": 3 + } + ] + } + } } } } }, "OperationalLimitSet": { "OpLimI_38.97114317029974_51.96152422706632": { - "Ravens.CimObjectType": "OperationalLimitSet", - "IdentifiedObject.mRID": "44764d73-372f-4d55-8e84-5ab8ffc703da", + "Ravens.cimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "df42099d-914d-4f26-91ad-7e279849ab2e", "IdentifiedObject.name": "OpLimI_38.97114317029974_51.96152422706632", "OperationalLimitSet.OperationalLimitValue": [ { - "Ravens.CimObjectType": "CurrentLimit", - "IdentifiedObject.mRID": "7f1251a9-83e6-42e1-9447-7af24510b432", + "Ravens.cimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "b6c1bcf8-d44e-45bb-9f0b-2244bd61dd7f", "IdentifiedObject.name": "OpLimI_38.97114317029974_51.96152422706632_Norm", "CurrentLimit.value": 38.97114317029974, "CurrentLimit.normalValue": 38.97114317029974, "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" }, { - "Ravens.CimObjectType": "CurrentLimit", - "IdentifiedObject.mRID": "26784e14-226e-4420-84c3-e11c926df475", + "Ravens.cimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "7d04bea6-1bbc-4d8f-92ff-5e793997e854", "IdentifiedObject.name": "OpLimI_38.97114317029974_51.96152422706632_Emerg", "CurrentLimit.value": 51.96152422706632, "CurrentLimit.normalValue": 38.97114317029974, @@ -412,44 +302,44 @@ ] }, "OpLimI_400.0_600.0": { - "Ravens.CimObjectType": "OperationalLimitSet", - "IdentifiedObject.mRID": "f59e344b-c2c5-4465-8584-11feeefaec83", + "Ravens.cimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "020ca323-f577-4b8d-8c03-970bca7222fe", "IdentifiedObject.name": "OpLimI_400.0_600.0", "OperationalLimitSet.OperationalLimitValue": [ { - "Ravens.CimObjectType": "CurrentLimit", - "IdentifiedObject.mRID": "e2876119-1166-41b7-82b2-55c3af3724ff", - "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", - "CurrentLimit.value": 600.0, - "CurrentLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" - }, - { - "Ravens.CimObjectType": "CurrentLimit", - "IdentifiedObject.mRID": "318af2aa-38b8-4073-915d-cba9e3c02b3c", + "Ravens.cimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "901ded36-5a2e-4a7d-8aba-25197f6d1534", "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", "CurrentLimit.value": 400.0, "CurrentLimit.normalValue": 400.0, "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" + }, + { + "Ravens.cimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "45dd4a09-d3cd-40f6-8993-1a4d13fdcb71", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", + "CurrentLimit.value": 600.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" } ] }, "OpLimV_380.0-420.00000000000006": { - "Ravens.CimObjectType": "OperationalLimitSet", - "IdentifiedObject.mRID": "ebe9634e-a35b-4086-be5a-3784f598c20a", + "Ravens.cimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "3643ffa0-c35e-4025-b0a5-766d3b6435a2", "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006", "OperationalLimitSet.OperationalLimitValue": [ { - "Ravens.CimObjectType": "VoltageLimit", - "IdentifiedObject.mRID": "d0fb9602-f090-467f-bdcc-594f7ea61c64", + "Ravens.cimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "77023bed-e40e-474f-a9c3-2e79ec1f7bfb", "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAhigh", "VoltageLimit.value": 420.00000000000006, "VoltageLimit.normalValue": 400.0, "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" }, { - "Ravens.CimObjectType": "VoltageLimit", - "IdentifiedObject.mRID": "6f5f1408-a98b-47cc-afa7-117e80e51771", + "Ravens.cimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "563219e7-ef3e-4955-949e-d630ec727007", "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAlow", "VoltageLimit.value": 380.0, "VoltageLimit.normalValue": 400.0, @@ -458,123 +348,248 @@ ] } }, + "PerLengthLineParameter": { + "PerLengthImpedance": { + "PerLengthPhaseImpedance": { + "556mcm": { + "Ravens.cimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "59f14e7d-be3b-4133-aaf5-3686495071f2", + "IdentifiedObject.name": "556mcm", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + } + ] + }, + "4/0quad": { + "Ravens.cimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "a106d3dc-a198-4d11-ace2-6dc07bf59169", + "IdentifiedObject.name": "4/0quad", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + } + ] + } + } + } + }, "Location": { "primary_Location": { - "Ravens.CimObjectType": "Location", - "IdentifiedObject.mRID": "37309db4-0940-411e-857a-93153c0359a2", + "Ravens.cimObjectType": "Location", + "IdentifiedObject.mRID": "f1e62041-40d1-407b-9a44-f58035006249", "IdentifiedObject.name": "primary_Location", "Location.PositionPoints": [ { - "Ravens.CimObjectType": "PositionPoint", - "PositionPoint.sequenceNumber": 1, - "PositionPoint.xPosition": 0.0, - "PositionPoint.yPosition": 0.0 + "Ravens.cimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 0, + "PositionPoint.xPosition": "0.0", + "PositionPoint.yPosition": "0.0" } ] }, "loadbus_Location": { - "Ravens.CimObjectType": "Location", - "IdentifiedObject.mRID": "f570a5d2-6a61-4776-959e-f4a8f19b1706", + "Ravens.cimObjectType": "Location", + "IdentifiedObject.mRID": "e7b7df3c-577e-4da9-b547-45c818d80807", "IdentifiedObject.name": "loadbus_Location", "Location.PositionPoints": [ { - "Ravens.CimObjectType": "PositionPoint", - "PositionPoint.sequenceNumber": 1, - "PositionPoint.xPosition": 0.0, - "PositionPoint.yPosition": 0.0 + "Ravens.cimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 0, + "PositionPoint.xPosition": "0.0", + "PositionPoint.yPosition": "0.0" } ] }, "sourcebus_Location": { - "Ravens.CimObjectType": "Location", - "IdentifiedObject.mRID": "758373e1-f065-4503-af46-6f89b548922c", + "Ravens.cimObjectType": "Location", + "IdentifiedObject.mRID": "3c24e9a5-5400-4f63-8adc-cb424586f18e", "IdentifiedObject.name": "sourcebus_Location", "Location.PositionPoints": [ { - "Ravens.CimObjectType": "PositionPoint", - "PositionPoint.sequenceNumber": 1, - "PositionPoint.xPosition": 0.0, - "PositionPoint.yPosition": 0.0 + "Ravens.cimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 0, + "PositionPoint.xPosition": "0.0", + "PositionPoint.yPosition": "0.0" } ] } }, "EnergyConnectionProfile": { - "Ravens.CimObjectType": "EnergyConnectionProfile", - "IdentifiedObject.mRID": "d4723d5b-add9-49b0-88a1-d8e47ebbde66", - "IdentifiedObject.name": "Load::::::defaultload", - "EnergyConnectionProfile.dssSpectrum": "defaultload" + "Load::::::defaultload": { + "Ravens.cimObjectType": "EnergyConnectionProfile", + "IdentifiedObject.mRID": "1a9d79f7-a43d-442e-b796-b9feb14a17b1", + "IdentifiedObject.name": "Load::::::defaultload", + "EnergyConnectionProfile.dssSpectrum": "defaultload" + } }, "Versions": { "IEC61970CIMVersion": { - "Ravens.CimObjectType": "IEC61970CIMVersion", + "Ravens.cimObjectType": "IEC61970CIMVersion", "IEC61970CIMVersion.version": "IEC61970CIM100", "IEC61970CIMVersion.date": "2019-04-01" + }, + "RavensVersion": { + "Ravens.cimObjectType": "RavensVersion", + "RavensVersion.date": "2025-03-10", + "RavensVersion.version": "RAVENSv0.3.0-dev" + } + }, + "LoadResponseCharacteristic": { + "Constant kVA": { + "Ravens.cimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "489a74aa-4d4f-4fe2-898e-e427e779eee3", + "IdentifiedObject.name": "Constant kVA", + "LoadResponseCharacteristic.pConstantPower": 100.0, + "LoadResponseCharacteristic.qConstantPower": 100.0 } }, "OperationalLimitType": { - "absoluteValueType_5000000000.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "9c0ee368-c6f1-4ace-afeb-4e760aecba46", - "IdentifiedObject.name": "absoluteValueType_5000000000.0s", - "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "lowType_5000000000.0s": { + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "55cbac53-876f-4b2c-a2a8-d348c17ecfb6", + "IdentifiedObject.name": "lowType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low", "OperationalLimitType.acceptableDuration": 5000000000.0 }, "highType_5000000000.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "05706366-f802-478e-91d6-f5aafaa14e04", + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "c53c645e-6e21-4524-a372-cc24f2643931", "IdentifiedObject.name": "highType_5000000000.0s", "OperationalLimitType.direction": "OperationalLimitDirectionKind.high", "OperationalLimitType.acceptableDuration": 5000000000.0 }, "absoluteValueType_86400.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "34e53b7e-0543-4ac6-8d1d-fa971d98b53f", + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "50900681-ca6f-44d2-9b14-adf028a4b3e3", "IdentifiedObject.name": "absoluteValueType_86400.0s", "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", "OperationalLimitType.acceptableDuration": 86400.0 }, - "lowType_5000000000.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "473b0218-b900-4e00-9e93-8e8adc1767d2", - "IdentifiedObject.name": "lowType_5000000000.0s", - "OperationalLimitType.direction": "OperationalLimitDirectionKind.low", + "absoluteValueType_5000000000.0s": { + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "14b8120a-0794-4910-82ce-866fe814ac85", + "IdentifiedObject.name": "absoluteValueType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", "OperationalLimitType.acceptableDuration": 5000000000.0 } }, "ConnectivityNode": { "primary": { - "Ravens.CimObjectType": "ConnectivityNode", - "IdentifiedObject.mRID": "88e0ace1-46b4-491a-a521-bac23f64b8c0", + "Ravens.cimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "43f0c7ee-a2f0-4d63-aef5-e1d7d4d573bc", "IdentifiedObject.name": "primary" }, "sourcebus": { - "Ravens.CimObjectType": "ConnectivityNode", - "IdentifiedObject.mRID": "b4d268bc-7862-4be1-a540-71dcf3feeb4e", + "Ravens.cimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "5d3c5fd4-b79c-4f4b-bc7e-4f5f93ce14b0", "IdentifiedObject.name": "sourcebus" }, "loadbus": { - "Ravens.CimObjectType": "ConnectivityNode", - "IdentifiedObject.mRID": "a8274412-8b0f-4bb3-a8d8-1db65e3a3685", + "Ravens.cimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "bc35f150-6102-4f0c-8f29-6c63b8efe5ea", "IdentifiedObject.name": "loadbus", "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" } }, "BaseVoltage": { "BaseV_0.4": { - "Ravens.CimObjectType": "BaseVoltage", - "IdentifiedObject.mRID": "5c7d64a6-5188-43a6-bf1a-1740452091ef", + "Ravens.cimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "9c927679-58be-42f9-aa8c-ec74322e2b24", "IdentifiedObject.name": "BaseV_0.4", "BaseVoltage.nominalVoltage": 400.0 } - }, - "LoadResponseCharacteristic": { - "Constant kVA": { - "Ravens.CimObjectType": "LoadResponseCharacteristic", - "IdentifiedObject.mRID": "0d3ba428-f9a0-40ad-953a-52a09911bc60", - "IdentifiedObject.name": "Constant kVA", - "LoadResponseCharacteristic.pConstantPower": 100, - "LoadResponseCharacteristic.qConstantPower": 100 - } } -} +} \ No newline at end of file diff --git a/test/data/ravens/ravens_case3_withgens.json b/test/data/ravens/ravens_case3_withgens.json index 72762e2c7..55ca62d87 100644 --- a/test/data/ravens/ravens_case3_withgens.json +++ b/test/data/ravens/ravens_case3_withgens.json @@ -1,212 +1,83 @@ { - "PerLengthLineParameter": { - "PerLengthImpedance": { - "PerLengthPhaseImpedance": { - "4/0quad": { - "Ravens.CimObjectType": "PerLengthPhaseImpedance", - "IdentifiedObject.mRID": "88bc7e59-e9ce-4600-a949-3e2cecbc2fda", - "IdentifiedObject.name": "4/0quad", - "PerLengthPhaseImpedance.conductorCount": 3, - "PerLengthPhaseImpedance.PhaseImpedanceData": [ - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.0467, - "PhaseImpedanceData.x": 0.0267, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 1, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.1167, - "PhaseImpedanceData.x": 0.0667, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.0467, - "PhaseImpedanceData.x": 0.0267, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 3, - "PhaseImpedanceData.r": 0.1167, - "PhaseImpedanceData.x": 0.0667, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.1167, - "PhaseImpedanceData.x": 0.0667, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.0467, - "PhaseImpedanceData.x": 0.0267, - "PhaseImpedanceData.b": -0.0 - } - ] + "OperationalLimitSet": { + "OpLimV_360.00000000000006-440.00000000000006": { + "Ravens.cimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "0affa440-d2d8-4fa3-92f6-c74b4d320853", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.cimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "5af21a33-2166-4d75-a2f4-3f579caa911e", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAhigh", + "VoltageLimit.value": 440.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" }, - "556mcm": { - "Ravens.CimObjectType": "PerLengthPhaseImpedance", - "IdentifiedObject.mRID": "d6879f7a-124f-4e82-987a-46f5ba3e2f9d", - "IdentifiedObject.name": "556mcm", - "PerLengthPhaseImpedance.conductorCount": 3, - "PerLengthPhaseImpedance.PhaseImpedanceData": [ - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 3, - "PhaseImpedanceData.r": 0.1, - "PhaseImpedanceData.x": 0.0583, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.04, - "PhaseImpedanceData.x": 0.0233, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.04, - "PhaseImpedanceData.x": 0.0233, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.1, - "PhaseImpedanceData.x": 0.0583, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 1, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.1, - "PhaseImpedanceData.x": 0.0583, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.04, - "PhaseImpedanceData.x": 0.0233, - "PhaseImpedanceData.b": -0.0 - } - ] + { + "Ravens.cimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "ac7913ff-485d-44f8-9617-230ce8aab4fd", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAlow", + "VoltageLimit.value": 360.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" } - } + ] + }, + "OpLimV_380.0-420.00000000000006": { + "Ravens.cimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "9394d894-7ec0-4a26-a9b6-66bccc8f1414", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.cimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "8ab44324-b7d8-4d81-bf9a-1c5e2d1e36f2", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAhigh", + "VoltageLimit.value": 420.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + }, + { + "Ravens.cimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "0bd94978-9d79-439c-ad54-02dbe37283d4", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAlow", + "VoltageLimit.value": 380.0, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + } + ] + }, + "OpLimI_400.0_600.0": { + "Ravens.cimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "2d93253b-f2bb-432f-96ff-7e4eec67d8e3", + "IdentifiedObject.name": "OpLimI_400.0_600.0", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.cimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "759a2254-d4c0-4d27-8bc6-d47c07d4d5ce", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", + "CurrentLimit.value": 600.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" + }, + { + "Ravens.cimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "f134e287-ae7c-4d85-a547-da0769d972b8", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", + "CurrentLimit.value": 400.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" + } + ] } }, "PowerSystemResource": { "Equipment": { "ConductingEquipment": { "EnergyConnection": { - "RegulatingCondEq": { - "RotatingMachine": { - "gen2": { - "Ravens.CimObjectType": "SynchronousMachine", - "IdentifiedObject.mRID": "c657d8a1-32c2-402f-8403-9b06c112318a", - "IdentifiedObject.name": "gen2", - "RotatingMachine.p": 1000.0, - "RotatingMachine.q": 484.3221048378525, - "RotatingMachine.ratedS": 1200.0, - "RotatingMachine.ratedU": 461.88021535170066, - "Equipment.inService": true, - "RotatingMachine.ratedPowerFactor": 0.9, - "GeneratingUnit.minOperatingP": 0.0, - "GeneratingUnit.maxOperatingP": 1080.0, - "SynchronousMachine.maxQ": 523.0678732248807, - "SynchronousMachine.minQ": -523.0678732248807, - "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", - "ConductingEquipment.Terminals": [ - { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "012eb2d2-f4d8-4cc9-825f-b634c66e5d84", - "IdentifiedObject.name": "gen2_T1", - "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" - } - ] - }, - "gen1": { - "Ravens.CimObjectType": "SynchronousMachine", - "IdentifiedObject.mRID": "3f2267a8-4f0c-4ac5-9415-8568d7d414b2", - "IdentifiedObject.name": "gen1", - "RotatingMachine.p": 2000.0, - "RotatingMachine.q": 968.644209675705, - "RotatingMachine.ratedS": 2400.0, - "RotatingMachine.ratedU": 461.88021535170066, - "Equipment.inService": true, - "RotatingMachine.ratedPowerFactor": 0.9, - "GeneratingUnit.minOperatingP": 0.0, - "GeneratingUnit.maxOperatingP": 2160.0, - "SynchronousMachine.maxQ": 1046.1357464497614, - "SynchronousMachine.minQ": -1046.1357464497614, - "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", - "ConductingEquipment.Terminals": [ - { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "20cd756e-faae-47d9-a177-b605e6ae55fb", - "IdentifiedObject.name": "gen1_T1", - "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" - } - ] - } - } - }, - "EnergySource": { - "source": { - "Ravens.CimObjectType": "EnergySource", - "IdentifiedObject.mRID": "494c011a-7640-4ed7-a3d5-2cd1a55413c0", - "IdentifiedObject.name": "source", - "EnergySource.nominalVoltage": 400.0, - "EnergySource.voltageMagnitude": 398.36, - "EnergySource.voltageAngle": 0.0, - "EnergySource.r": 3.880570000581328e-08, - "EnergySource.x": 1.5522280002325312e-07, - "EnergySource.r0": 5.069596039676399e-08, - "EnergySource.x0": 1.5208788119029196e-07, - "Equipment.inService": true, - "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", - "ConductingEquipment.Terminals": [ - { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "327a6ba6-06c2-40ff-a0cc-550dd50d824d", - "IdentifiedObject.name": "source_T1", - "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" - } - ] - } - }, "EnergyConsumer": { "l2": { - "Ravens.CimObjectType": "EnergyConsumer", - "IdentifiedObject.mRID": "f227af26-b8ae-47b3-97cc-4d1e5d6bbfd3", + "Ravens.cimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "677244d1-61ee-4d4e-bc78-2e627da48d73", "IdentifiedObject.name": "l2", "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, @@ -216,30 +87,31 @@ "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", - "ConductingEquipment.Terminals": [ - { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "9f8d612e-85f8-4757-9ff8-f9ae5947ddd8", - "IdentifiedObject.name": "l2_T1", - "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.B", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" - } - ], "EnergyConsumer.EnergyConsumerPhase": [ { - "Ravens.CimObjectType": "EnergyConsumerPhase", - "IdentifiedObject.mRID": "f3cd189c-bd31-4fd4-beed-8967142aa0ea", + "Ravens.cimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "a1f404e6-1659-46a4-b99e-55dc23b05891", "IdentifiedObject.name": "l2_B", "EnergyConsumerPhase.p": 6000.0, "EnergyConsumerPhase.q": 3000.0, "EnergyConsumerPhase.phase": "SinglePhaseKind.B" } + ], + "ConductingEquipment.Terminals": [ + { + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "839eabd9-7a80-47b8-981c-7ef4cc1c33e9", + "IdentifiedObject.name": "l2_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.B", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" + } ] }, "l1": { - "Ravens.CimObjectType": "EnergyConsumer", - "IdentifiedObject.mRID": "8bff0407-deee-4f99-92fa-1dee4047621e", + "Ravens.cimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "260a548c-2df4-4402-be48-c113af690711", "IdentifiedObject.name": "l1", "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, @@ -249,30 +121,31 @@ "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", - "ConductingEquipment.Terminals": [ - { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "4c93404d-1381-4fb2-b2db-36da5d6a0583", - "IdentifiedObject.name": "l1_T1", - "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.A", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" - } - ], "EnergyConsumer.EnergyConsumerPhase": [ { - "Ravens.CimObjectType": "EnergyConsumerPhase", - "IdentifiedObject.mRID": "d4f8dc3a-8a95-4361-968a-1d841de4d7d1", + "Ravens.cimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "7cafb047-287c-4094-ba1d-a69241fa9547", "IdentifiedObject.name": "l1_A", "EnergyConsumerPhase.p": 6000.0, "EnergyConsumerPhase.q": 3000.0, "EnergyConsumerPhase.phase": "SinglePhaseKind.A" } + ], + "ConductingEquipment.Terminals": [ + { + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "3202c504-99f7-4e15-90c7-649e8c82aac7", + "IdentifiedObject.name": "l1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.A", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" + } ] }, "l3": { - "Ravens.CimObjectType": "EnergyConsumer", - "IdentifiedObject.mRID": "f8e9430c-56a5-44c3-8b53-98464182dec3", + "Ravens.cimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "c7d592fa-7438-4d21-bc9a-dbd3ed4c0a88", "IdentifiedObject.name": "l3", "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, @@ -280,26 +153,121 @@ "EnergyConsumer.grounded": true, "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", - "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", - "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.phaseConnection": "PhaseShuntConnectionKind.Y", + "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", + "EnergyConsumer.EnergyConsumerPhase": [ + { + "Ravens.cimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "5ea39eca-a263-4d5c-a3bd-2d47cbb6dd02", + "IdentifiedObject.name": "l3_C", + "EnergyConsumerPhase.p": 6000.0, + "EnergyConsumerPhase.q": 3000.0, + "EnergyConsumerPhase.phase": "SinglePhaseKind.C" + } + ], + "ConductingEquipment.Terminals": [ + { + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "f53bbd4e-e290-4f13-9673-86ec97228078", + "IdentifiedObject.name": "l3_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.C", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" + } + ] + } + }, + "RegulatingCondEq": { + "RotatingMachine": { + "gen2": { + "Ravens.cimObjectType": "SynchronousMachine", + "IdentifiedObject.mRID": "81390416-2b37-4121-a37e-e3515f83795c", + "IdentifiedObject.name": "gen2", + "RotatingMachine.p": 1000.0, + "RotatingMachine.q": 0.0, + "RotatingMachine.ratedS": 1200.0, + "RotatingMachine.ratedU": 461.88021535170066, + "Equipment.inService": true, + "RotatingMachine.ratedPowerFactor": 1.0, + "SynchronousMachine.maxQ": 0.0, + "SynchronousMachine.minQ": -0.0, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "fbe395fc-6f7b-4e1c-ada7-5035bf86591f", + "IdentifiedObject.name": "gen2_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_360.00000000000006-440.00000000000006'" + } + ], + "RotatingMachine.GeneratingUnit": { + "Ravens.cimObjectType": "GeneratingUnit", + "IdentifiedObject.mRID": "aa977def-b0c9-45ef-bd9e-e5246fa72809", + "IdentifiedObject.name": "gen2_GenUnit", + "GeneratingUnit.minOperatingP": 0.0, + "GeneratingUnit.maxOperatingP": 1200.0 + } + }, + "gen1": { + "Ravens.cimObjectType": "SynchronousMachine", + "IdentifiedObject.mRID": "2a263555-a184-45b4-9433-78c719b019d5", + "IdentifiedObject.name": "gen1", + "RotatingMachine.p": 2000.0, + "RotatingMachine.q": 0.0, + "RotatingMachine.ratedS": 2400.0, + "RotatingMachine.ratedU": 461.88021535170066, + "Equipment.inService": true, + "RotatingMachine.ratedPowerFactor": 1.0, + "SynchronousMachine.maxQ": 0.0, + "SynchronousMachine.minQ": -0.0, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "ee4f4ef2-c05f-4928-8a13-aee428fb33d0", + "IdentifiedObject.name": "gen1_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_360.00000000000006-440.00000000000006'" + } + ], + "RotatingMachine.GeneratingUnit": { + "Ravens.cimObjectType": "GeneratingUnit", + "IdentifiedObject.mRID": "2ccc4531-6602-42a4-8f34-ef0ba4a0b2b9", + "IdentifiedObject.name": "gen1_GenUnit", + "GeneratingUnit.minOperatingP": 0.0, + "GeneratingUnit.maxOperatingP": 2400.0 + } + } + } + }, + "EnergySource": { + "source": { + "Ravens.cimObjectType": "EnergySource", + "IdentifiedObject.mRID": "c3c06e8c-905c-463b-8931-92fd363392c4", + "IdentifiedObject.name": "source", + "EnergySource.nominalVoltage": 400.0, + "EnergySource.voltageMagnitude": 398.36, + "EnergySource.voltageAngle": 0.0, + "EnergySource.r": 3.880570000581328e-08, + "EnergySource.x": 1.5522280002325312e-07, + "EnergySource.r0": 5.069596039676399e-08, + "EnergySource.x0": 1.5208788119029196e-07, + "Equipment.inService": true, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "ec5de9d0-8f3a-409c-afaa-5dd15969842f", - "IdentifiedObject.name": "l3_T1", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "a642d1eb-87ce-42df-b5ce-35bb5f9c5806", + "IdentifiedObject.name": "source_T1", "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.C", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" - } - ], - "EnergyConsumer.EnergyConsumerPhase": [ - { - "Ravens.CimObjectType": "EnergyConsumerPhase", - "IdentifiedObject.mRID": "cdb85d03-72cd-4c1a-aa27-ee985895d65c", - "IdentifiedObject.name": "l3_C", - "EnergyConsumerPhase.p": 6000.0, - "EnergyConsumerPhase.q": 3000.0, - "EnergyConsumerPhase.phase": "SinglePhaseKind.C" + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" } ] } @@ -308,49 +276,51 @@ "Conductor": { "ACLineSegment": { "ohline": { - "Ravens.CimObjectType": "ACLineSegment", - "IdentifiedObject.mRID": "357e3f68-a996-4ef9-8e29-5a9701da50f5", + "Ravens.cimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "a1b1ffe9-726f-4db4-9f4c-361d85a20e32", "IdentifiedObject.name": "ohline", - "Conductor.length": 1.0, "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "Conductor.length": 1.0, "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "262a28c0-79c8-46f8-be2f-48baba94b09b", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "15f418d3-1bf9-4e64-9580-3e4225a1459c", "IdentifiedObject.name": "ohline_T1", "ACDCTerminal.sequenceNumber": 1, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" }, { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "20c1e2b3-faab-4f16-9d28-1438cf5adc31", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "106352b3-12ae-4793-a934-8c26c9544b3d", "IdentifiedObject.name": "ohline_T2", "ACDCTerminal.sequenceNumber": 2, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" } ], "ACLineSegment.ACLineSegmentPhase": [ { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "43a9f788-638f-48c5-9211-437795fad9da", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "0df805ac-88f5-4a4a-8c4e-1e106d004f31", "IdentifiedObject.name": "ohline_A", "ACLineSegmentPhase.phase": "SinglePhaseKind.A", "ACLineSegmentPhase.sequenceNumber": 1 }, { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "939db8dd-1631-44e8-aa9d-cb391f06136d", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "abde4a1e-ea6e-466c-8809-bd27c2790cff", "IdentifiedObject.name": "ohline_B", "ACLineSegmentPhase.phase": "SinglePhaseKind.B", "ACLineSegmentPhase.sequenceNumber": 2 }, { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "8a764636-52d0-470f-abcd-9cee75f114de", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "d7ea28c1-e041-45d3-b9db-820e23d6ec2f", "IdentifiedObject.name": "ohline_C", "ACLineSegmentPhase.phase": "SinglePhaseKind.C", "ACLineSegmentPhase.sequenceNumber": 3 @@ -358,49 +328,51 @@ ] }, "quad": { - "Ravens.CimObjectType": "ACLineSegment", - "IdentifiedObject.mRID": "b0c876f2-8724-4b1d-9bb8-16ad6dc08866", + "Ravens.cimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "cc9c65a6-6195-45d3-86ea-e4195a8ce2c5", "IdentifiedObject.name": "quad", - "Conductor.length": 1.0, "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "Conductor.length": 1.0, "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "fba92277-7b25-42e3-8782-10e01ebf3ccf", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "314f40f6-1d4b-4f62-9441-ece3fc4d0338", "IdentifiedObject.name": "quad_T1", "ACDCTerminal.sequenceNumber": 1, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" }, { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "7a7bd627-5599-4139-bd71-a659a313fafc", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "c0b7bcfa-2281-41f1-bf80-c67dcdfc9c59", "IdentifiedObject.name": "quad_T2", "ACDCTerminal.sequenceNumber": 2, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" } ], "ACLineSegment.ACLineSegmentPhase": [ { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "06ccbe19-290d-4808-8edb-40afc7e7c41e", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "c14509f5-2901-451a-9da2-33ec6baff5e7", "IdentifiedObject.name": "quad_A", "ACLineSegmentPhase.phase": "SinglePhaseKind.A", "ACLineSegmentPhase.sequenceNumber": 1 }, { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "79df9209-3379-4ce7-bd5b-2f927daccd8a", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "7d18daf8-563d-4106-aeb2-b8dbeb7e6556", "IdentifiedObject.name": "quad_B", "ACLineSegmentPhase.phase": "SinglePhaseKind.B", "ACLineSegmentPhase.sequenceNumber": 2 }, { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "27dfc4e3-829a-4c4a-abb2-dab081e599c7", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "4fe98fa1-175e-4009-b246-631838fe5047", "IdentifiedObject.name": "quad_C", "ACLineSegmentPhase.phase": "SinglePhaseKind.C", "ACLineSegmentPhase.sequenceNumber": 3 @@ -412,195 +384,249 @@ } } }, - "EnergyConnectionProfile": { - "Ravens.CimObjectType": "EnergyConnectionProfile", - "IdentifiedObject.mRID": "b1c858fa-9961-4915-ac2b-6c40546f4e55", - "IdentifiedObject.name": "Load::::::defaultload", - "EnergyConnectionProfile.dssSpectrum": "defaultload" - }, - "OperationalLimitSet": { - "OpLimV_360.00000000000006-440.00000000000006": { - "Ravens.CimObjectType": "OperationalLimitSet", - "IdentifiedObject.mRID": "1fd3801e-4bc9-4995-a833-b8a934a51856", - "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006", - "OperationalLimitSet.OperationalLimitValue": [ - { - "Ravens.CimObjectType": "VoltageLimit", - "IdentifiedObject.mRID": "e2cbc64e-5a29-4df5-b214-f9ed9aa5cb5d", - "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAlow", - "VoltageLimit.value": 360.00000000000006, - "VoltageLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" - }, - { - "Ravens.CimObjectType": "VoltageLimit", - "IdentifiedObject.mRID": "27d3baf8-3d5e-4465-9e84-3e52708211f1", - "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAhigh", - "VoltageLimit.value": 440.00000000000006, - "VoltageLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" - } - ] - }, - "OpLimV_380.0-420.00000000000006": { - "Ravens.CimObjectType": "OperationalLimitSet", - "IdentifiedObject.mRID": "35e30ea0-641e-43b7-a1e4-0e15e42334e1", - "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006", - "OperationalLimitSet.OperationalLimitValue": [ - { - "Ravens.CimObjectType": "VoltageLimit", - "IdentifiedObject.mRID": "cce047bb-3dc5-4f08-85ae-401c93562f34", - "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAhigh", - "VoltageLimit.value": 420.00000000000006, - "VoltageLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + "PerLengthLineParameter": { + "PerLengthImpedance": { + "PerLengthPhaseImpedance": { + "4/0quad": { + "Ravens.cimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "e5604025-92d3-48a7-9ac7-eb9e4f620b87", + "IdentifiedObject.name": "4/0quad", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + } + ] }, - { - "Ravens.CimObjectType": "VoltageLimit", - "IdentifiedObject.mRID": "88c7ce0d-859b-4dda-bb25-64d33ba36831", - "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAlow", - "VoltageLimit.value": 380.0, - "VoltageLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + "556mcm": { + "Ravens.cimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "24b81d74-a75f-4b71-8af8-e881c2136864", + "IdentifiedObject.name": "556mcm", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + } + ] } - ] + } + } + }, + "EnergyConnectionProfile": { + "Load::::::defaultload": { + "Ravens.cimObjectType": "EnergyConnectionProfile", + "IdentifiedObject.mRID": "50cab77c-b334-4448-932d-a1056b2a384d", + "IdentifiedObject.name": "Load::::::defaultload", + "EnergyConnectionProfile.dssSpectrum": "defaultload" + } + }, + "Versions": { + "IEC61970CIMVersion": { + "Ravens.cimObjectType": "IEC61970CIMVersion", + "IEC61970CIMVersion.version": "IEC61970CIM100", + "IEC61970CIMVersion.date": "2019-04-01" }, - "OpLimI_400.0_600.0": { - "Ravens.CimObjectType": "OperationalLimitSet", - "IdentifiedObject.mRID": "47ba5a2e-b0e0-469d-b456-b74d90a89598", - "IdentifiedObject.name": "OpLimI_400.0_600.0", - "OperationalLimitSet.OperationalLimitValue": [ - { - "Ravens.CimObjectType": "CurrentLimit", - "IdentifiedObject.mRID": "ce6d7dcd-e426-44cb-ab33-9e8a6de1b60f", - "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", - "CurrentLimit.value": 600.0, - "CurrentLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" - }, - { - "Ravens.CimObjectType": "CurrentLimit", - "IdentifiedObject.mRID": "a301065e-a50e-4dd7-856b-c7035e9ea52f", - "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", - "CurrentLimit.value": 400.0, - "CurrentLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" - } - ] + "RavensVersion": { + "Ravens.cimObjectType": "RavensVersion", + "RavensVersion.date": "2025-03-10", + "RavensVersion.version": "RAVENSv0.3.0-dev" } }, "Location": { - "primary_Location": { - "Ravens.CimObjectType": "Location", - "IdentifiedObject.mRID": "db2f0d86-da66-46ac-adc1-6eec717cf555", - "IdentifiedObject.name": "primary_Location", + "loadbus_Location": { + "Ravens.cimObjectType": "Location", + "IdentifiedObject.mRID": "60644937-51dc-4b31-a2a7-8b9d78ab03a1", + "IdentifiedObject.name": "loadbus_Location", "Location.PositionPoints": [ { - "Ravens.CimObjectType": "PositionPoint", - "PositionPoint.sequenceNumber": 1, - "PositionPoint.xPosition": 0.0, - "PositionPoint.yPosition": 0.0 + "Ravens.cimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 0, + "PositionPoint.xPosition": "0.0", + "PositionPoint.yPosition": "0.0" } ] }, - "loadbus_Location": { - "Ravens.CimObjectType": "Location", - "IdentifiedObject.mRID": "76056310-0c84-49e6-9d92-c0a3cce574e4", - "IdentifiedObject.name": "loadbus_Location", + "primary_Location": { + "Ravens.cimObjectType": "Location", + "IdentifiedObject.mRID": "72627437-8d03-4fbc-80ab-2d57e34bd115", + "IdentifiedObject.name": "primary_Location", "Location.PositionPoints": [ { - "Ravens.CimObjectType": "PositionPoint", - "PositionPoint.sequenceNumber": 1, - "PositionPoint.xPosition": 0.0, - "PositionPoint.yPosition": 0.0 + "Ravens.cimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 0, + "PositionPoint.xPosition": "0.0", + "PositionPoint.yPosition": "0.0" } ] }, "sourcebus_Location": { - "Ravens.CimObjectType": "Location", - "IdentifiedObject.mRID": "4c73c3dd-7250-4f6a-af69-d203960b0a34", + "Ravens.cimObjectType": "Location", + "IdentifiedObject.mRID": "ab3ac2d6-30d9-454a-ac71-82f6f70e021c", "IdentifiedObject.name": "sourcebus_Location", "Location.PositionPoints": [ { - "Ravens.CimObjectType": "PositionPoint", - "PositionPoint.sequenceNumber": 1, - "PositionPoint.xPosition": 0.0, - "PositionPoint.yPosition": 0.0 + "Ravens.cimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 0, + "PositionPoint.xPosition": "0.0", + "PositionPoint.yPosition": "0.0" } ] } }, - "Versions": { - "IEC61970CIMVersion": { - "Ravens.CimObjectType": "IEC61970CIMVersion", - "IEC61970CIMVersion.version": "IEC61970CIM100", - "IEC61970CIMVersion.date": "2019-04-01" + "OperationalLimitType": { + "lowType_5000000000.0s": { + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "5b4f431e-a0f2-4f4d-8138-684413152f97", + "IdentifiedObject.name": "lowType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.low", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "highType_5000000000.0s": { + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "5fe17911-6295-47c8-95f0-c9ef0ce84501", + "IdentifiedObject.name": "highType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "absoluteValueType_5000000000.0s": { + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "95cfc3c6-31b8-463c-a3fb-a2f4831ed87e", + "IdentifiedObject.name": "absoluteValueType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "absoluteValueType_86400.0s": { + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "1bb7cc8e-0219-4893-9c92-c1ecdb8587fb", + "IdentifiedObject.name": "absoluteValueType_86400.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", + "OperationalLimitType.acceptableDuration": 86400.0 } }, "ConnectivityNode": { "loadbus": { - "Ravens.CimObjectType": "ConnectivityNode", - "IdentifiedObject.mRID": "4ac8da05-a223-4bf6-b372-12c9479c495a", + "Ravens.cimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "16aebef9-3243-427a-bd9f-57f877c59c34", "IdentifiedObject.name": "loadbus", "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_360.00000000000006-440.00000000000006'" }, "primary": { - "Ravens.CimObjectType": "ConnectivityNode", - "IdentifiedObject.mRID": "3e877b8a-ef33-4e18-8c80-1b05050bfc40", + "Ravens.cimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "f01441bc-8fb7-4e17-9d4d-70a191de5e7f", "IdentifiedObject.name": "primary", "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_360.00000000000006-440.00000000000006'" }, "sourcebus": { - "Ravens.CimObjectType": "ConnectivityNode", - "IdentifiedObject.mRID": "d192d550-1fc0-489f-8e47-72209fa989e7", + "Ravens.cimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "2dc9aa38-76ef-4ede-a123-7e3aae193a6c", "IdentifiedObject.name": "sourcebus" } }, - "OperationalLimitType": { - "absoluteValueType_86400.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "d60da1eb-6a60-41ba-99df-7313cad312fa", - "IdentifiedObject.name": "absoluteValueType_86400.0s", - "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", - "OperationalLimitType.acceptableDuration": 86400.0 - }, - "highType_5000000000.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "a1a82ad0-e426-4ecb-816a-5a58f034756b", - "IdentifiedObject.name": "highType_5000000000.0s", - "OperationalLimitType.direction": "OperationalLimitDirectionKind.high", - "OperationalLimitType.acceptableDuration": 5000000000.0 - }, - "lowType_5000000000.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "1eaf0044-6272-4146-bf43-5c5310023469", - "IdentifiedObject.name": "lowType_5000000000.0s", - "OperationalLimitType.direction": "OperationalLimitDirectionKind.low", - "OperationalLimitType.acceptableDuration": 5000000000.0 - }, - "absoluteValueType_5000000000.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "1a39544c-2df7-46a9-a6c0-cfb28ab6eaab", - "IdentifiedObject.name": "absoluteValueType_5000000000.0s", - "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", - "OperationalLimitType.acceptableDuration": 5000000000.0 + "BaseVoltage": { + "BaseV_0.4": { + "Ravens.cimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "79419d6e-b0a8-4127-9889-95978fa40de5", + "IdentifiedObject.name": "BaseV_0.4", + "BaseVoltage.nominalVoltage": 400.0 } }, "LoadResponseCharacteristic": { "Constant kVA": { - "Ravens.CimObjectType": "LoadResponseCharacteristic", - "IdentifiedObject.mRID": "777f5c7c-dea1-4a88-8db0-e5bd71a2fd4b", + "Ravens.cimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "dc0534be-b25d-45be-899f-27b258112328", "IdentifiedObject.name": "Constant kVA", - "LoadResponseCharacteristic.pConstantPower": 100, - "LoadResponseCharacteristic.qConstantPower": 100 - } - }, - "BaseVoltage": { - "BaseV_0.4": { - "Ravens.CimObjectType": "BaseVoltage", - "IdentifiedObject.mRID": "93c27318-44cd-41b7-a873-f9001d1b831f", - "IdentifiedObject.name": "BaseV_0.4", - "BaseVoltage.nominalVoltage": 400.0 + "LoadResponseCharacteristic.pConstantPower": 100.0, + "LoadResponseCharacteristic.qConstantPower": 100.0 } } -} +} \ No newline at end of file diff --git a/test/data/ravens/ravens_case3_withpvandstorage.json b/test/data/ravens/ravens_case3_withpvandstorage.json index af4ccb4fc..162666cf9 100644 --- a/test/data/ravens/ravens_case3_withpvandstorage.json +++ b/test/data/ravens/ravens_case3_withpvandstorage.json @@ -1,73 +1,120 @@ { - "OperationalLimitSet": { - "OpLimI_400.0_600.0": { - "Ravens.CimObjectType": "OperationalLimitSet", - "IdentifiedObject.mRID": "1e3d77af-8a23-466a-bdd9-39cee9f9fe92", - "IdentifiedObject.name": "OpLimI_400.0_600.0", - "OperationalLimitSet.OperationalLimitValue": [ - { - "Ravens.CimObjectType": "CurrentLimit", - "IdentifiedObject.mRID": "fc496404-0ea3-49ad-a418-fb8b10aa2724", - "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", - "CurrentLimit.value": 600.0, - "CurrentLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" - }, - { - "Ravens.CimObjectType": "CurrentLimit", - "IdentifiedObject.mRID": "33f3b868-cb9b-4223-b83c-e050cd47a7d0", - "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", - "CurrentLimit.value": 400.0, - "CurrentLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" - } - ] - }, - "OpLimV_360.00000000000006-440.00000000000006": { - "Ravens.CimObjectType": "OperationalLimitSet", - "IdentifiedObject.mRID": "514c489d-6957-4739-bb9d-ff5da50e8f4e", - "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006", - "OperationalLimitSet.OperationalLimitValue": [ - { - "Ravens.CimObjectType": "VoltageLimit", - "IdentifiedObject.mRID": "513ecee1-8a86-4ced-b436-e4def25953cc", - "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAhigh", - "VoltageLimit.value": 440.00000000000006, - "VoltageLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" - }, - { - "Ravens.CimObjectType": "VoltageLimit", - "IdentifiedObject.mRID": "e22b44ed-3b12-4bf9-8be3-a591a3cf732b", - "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAlow", - "VoltageLimit.value": 360.00000000000006, - "VoltageLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" - } - ] - }, - "OpLimV_380.0-420.00000000000006": { - "Ravens.CimObjectType": "OperationalLimitSet", - "IdentifiedObject.mRID": "5c5e7910-bdea-408b-9cba-c96967e39939", - "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006", - "OperationalLimitSet.OperationalLimitValue": [ - { - "Ravens.CimObjectType": "VoltageLimit", - "IdentifiedObject.mRID": "5f98e299-22cb-48a5-acd0-ba5404111eed", - "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAlow", - "VoltageLimit.value": 380.0, - "VoltageLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + "PerLengthLineParameter": { + "PerLengthImpedance": { + "PerLengthPhaseImpedance": { + "4/0quad": { + "Ravens.cimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "532a5afc-e4cd-4fe7-a502-82d27b2dded8", + "IdentifiedObject.name": "4/0quad", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1167, + "PhaseImpedanceData.x": 0.0667, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.0467, + "PhaseImpedanceData.x": 0.0267, + "PhaseImpedanceData.b": -0.0 + } + ] }, - { - "Ravens.CimObjectType": "VoltageLimit", - "IdentifiedObject.mRID": "43fb3ee9-3b9a-4a7b-ace5-5ddcac6d59d5", - "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAhigh", - "VoltageLimit.value": 420.00000000000006, - "VoltageLimit.normalValue": 400.0, - "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + "556mcm": { + "Ravens.cimObjectType": "PerLengthPhaseImpedance", + "IdentifiedObject.mRID": "cd4a29d9-4833-4586-8d9f-a93692830710", + "IdentifiedObject.name": "556mcm", + "PerLengthPhaseImpedance.conductorCount": 3, + "PerLengthPhaseImpedance.PhaseImpedanceData": [ + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 3, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 3, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 2, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 1, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.1, + "PhaseImpedanceData.x": 0.0583, + "PhaseImpedanceData.b": 1.6000000000000003e-05 + }, + { + "Ravens.cimObjectType": "PhaseImpedanceData", + "PhaseImpedanceData.row": 2, + "PhaseImpedanceData.column": 1, + "PhaseImpedanceData.r": 0.04, + "PhaseImpedanceData.x": 0.0233, + "PhaseImpedanceData.b": -0.0 + } + ] } - ] + } } }, "PowerSystemResource": { @@ -75,103 +122,107 @@ "ConductingEquipment": { "Conductor": { "ACLineSegment": { - "ohline": { - "Ravens.CimObjectType": "ACLineSegment", - "IdentifiedObject.mRID": "e9c718d0-d75c-41cf-b31e-5d1467780362", - "IdentifiedObject.name": "ohline", - "Conductor.length": 1.0, + "quad": { + "Ravens.cimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "34ed21be-4f28-4326-9367-dfb2582eb955", + "IdentifiedObject.name": "quad", "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", - "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", + "Conductor.length": 1.0, + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", "ACLineSegment.ACLineSegmentPhase": [ { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "350fed0a-7395-4736-aa12-ac2d7e87ac92", - "IdentifiedObject.name": "ohline_A", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "7548f9ee-bed7-46a4-80ed-952553d75570", + "IdentifiedObject.name": "quad_A", "ACLineSegmentPhase.phase": "SinglePhaseKind.A", "ACLineSegmentPhase.sequenceNumber": 1 }, { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "3b5406ff-4fb5-4a30-8e2c-4f09db60a544", - "IdentifiedObject.name": "ohline_B", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "c427163d-b3da-4ce5-b278-0184314823cc", + "IdentifiedObject.name": "quad_B", "ACLineSegmentPhase.phase": "SinglePhaseKind.B", "ACLineSegmentPhase.sequenceNumber": 2 }, { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "8d10892c-1893-4a48-8f5b-615fcb4c0d55", - "IdentifiedObject.name": "ohline_C", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "556d4c10-dd22-45b5-945a-2669206d7f35", + "IdentifiedObject.name": "quad_C", "ACLineSegmentPhase.phase": "SinglePhaseKind.C", "ACLineSegmentPhase.sequenceNumber": 3 } ], "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "37415ad4-1071-481c-b741-06e6b8ca05d4", - "IdentifiedObject.name": "ohline_T1", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "9128897b-7185-4b73-83ca-4667a4a7ff56", + "IdentifiedObject.name": "quad_T1", "ACDCTerminal.sequenceNumber": 1, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" }, { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "3bd4d2fc-d02b-4238-9630-83fe0b294662", - "IdentifiedObject.name": "ohline_T2", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "4a34b29b-9977-4175-9f14-8b73d0c3b08d", + "IdentifiedObject.name": "quad_T2", "ACDCTerminal.sequenceNumber": 2, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" } ] }, - "quad": { - "Ravens.CimObjectType": "ACLineSegment", - "IdentifiedObject.mRID": "edba552d-daee-40f3-9488-336f9c9231dc", - "IdentifiedObject.name": "quad", - "Conductor.length": 1.0, + "ohline": { + "Ravens.cimObjectType": "ACLineSegment", + "IdentifiedObject.mRID": "51e8b467-ed7a-4f32-abaa-e6048604637e", + "IdentifiedObject.name": "ohline", "Equipment.inService": true, "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", - "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'4/0quad'", + "Conductor.length": 1.0, + "ACLineSegment.PerLengthImpedance": "PerLengthPhaseImpedance::'556mcm'", "ACLineSegment.ACLineSegmentPhase": [ { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "c087897c-8221-477a-b33b-59ed2ff423c7", - "IdentifiedObject.name": "quad_A", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "991d4946-1c78-46c3-9273-ef94db49733c", + "IdentifiedObject.name": "ohline_A", "ACLineSegmentPhase.phase": "SinglePhaseKind.A", "ACLineSegmentPhase.sequenceNumber": 1 }, { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "57c71971-b70b-49a2-868b-a64aceb3b031", - "IdentifiedObject.name": "quad_B", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "e9634f6e-cb67-4124-b1f8-c8ba8e2801bb", + "IdentifiedObject.name": "ohline_B", "ACLineSegmentPhase.phase": "SinglePhaseKind.B", "ACLineSegmentPhase.sequenceNumber": 2 }, { - "Ravens.CimObjectType": "ACLineSegmentPhase", - "IdentifiedObject.mRID": "732aea91-11c1-4dcb-a9ed-45de010dde2f", - "IdentifiedObject.name": "quad_C", + "Ravens.cimObjectType": "ACLineSegmentPhase", + "IdentifiedObject.mRID": "70e033e8-c9bb-407d-a93b-b0aaa4de2aff", + "IdentifiedObject.name": "ohline_C", "ACLineSegmentPhase.phase": "SinglePhaseKind.C", "ACLineSegmentPhase.sequenceNumber": 3 } ], "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "82cce1dc-5fc1-4a98-9f53-2b347ed1d3b5", - "IdentifiedObject.name": "quad_T1", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "24957142-0907-4330-b662-2865da114bed", + "IdentifiedObject.name": "ohline_T1", "ACDCTerminal.sequenceNumber": 1, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'primary'" + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" }, { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "f0e02033-fa13-4ac4-b6cf-0e0444d72d18", - "IdentifiedObject.name": "quad_T2", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "26e7863d-d2ef-41f7-bcb8-d4aa3e4887f5", + "IdentifiedObject.name": "ohline_T2", "ACDCTerminal.sequenceNumber": 2, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.ConnectivityNode": "ConnectivityNode::'primary'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimI_400.0_600.0'" } ] } @@ -179,10 +230,10 @@ }, "EnergyConnection": { "EnergyConsumer": { - "l2": { - "Ravens.CimObjectType": "EnergyConsumer", - "IdentifiedObject.mRID": "09b604b2-00d7-4a4e-994d-2f189ee9642b", - "IdentifiedObject.name": "l2", + "l1": { + "Ravens.cimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "673b14d9-552c-4da8-a872-c6d9f8d04647", + "IdentifiedObject.name": "l1", "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, @@ -193,29 +244,30 @@ "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "9b397420-cdcf-4127-85ae-73559a000953", - "IdentifiedObject.name": "l2_T1", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "71e3be37-d17e-4f08-b989-5af569de81d2", + "IdentifiedObject.name": "l1_T1", "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.B", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.phases": "PhaseCode.A", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" } ], "EnergyConsumer.EnergyConsumerPhase": [ { - "Ravens.CimObjectType": "EnergyConsumerPhase", - "IdentifiedObject.mRID": "03858c77-6453-407c-8119-da6a76508b59", - "IdentifiedObject.name": "l2_B", + "Ravens.cimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "73384992-664e-498e-9325-0a561b220d71", + "IdentifiedObject.name": "l1_A", "EnergyConsumerPhase.p": 6000.0, "EnergyConsumerPhase.q": 3000.0, - "EnergyConsumerPhase.phase": "SinglePhaseKind.B" + "EnergyConsumerPhase.phase": "SinglePhaseKind.A" } ] }, - "l3": { - "Ravens.CimObjectType": "EnergyConsumer", - "IdentifiedObject.mRID": "f9667c10-e77a-4409-8099-072bfdce24e0", - "IdentifiedObject.name": "l3", + "l2": { + "Ravens.cimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "5dbbd6a1-fe55-4085-9c95-fafe7b60dcb8", + "IdentifiedObject.name": "l2", "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, @@ -226,29 +278,30 @@ "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "18771bf2-42eb-4758-a101-0a92cb9508e5", - "IdentifiedObject.name": "l3_T1", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "472c3167-f983-4be6-bf38-b45e30ee9bcc", + "IdentifiedObject.name": "l2_T1", "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.C", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.phases": "PhaseCode.B", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" } ], "EnergyConsumer.EnergyConsumerPhase": [ { - "Ravens.CimObjectType": "EnergyConsumerPhase", - "IdentifiedObject.mRID": "dbfde1f4-2422-4e65-933b-7b9d43a22cc7", - "IdentifiedObject.name": "l3_C", + "Ravens.cimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "50c7b891-cf25-4b1b-9fb8-d345606d915b", + "IdentifiedObject.name": "l2_B", "EnergyConsumerPhase.p": 6000.0, "EnergyConsumerPhase.q": 3000.0, - "EnergyConsumerPhase.phase": "SinglePhaseKind.C" + "EnergyConsumerPhase.phase": "SinglePhaseKind.B" } ] }, - "l1": { - "Ravens.CimObjectType": "EnergyConsumer", - "IdentifiedObject.mRID": "089386b2-ecab-4d6f-ab32-12c2c5527ee5", - "IdentifiedObject.name": "l1", + "l3": { + "Ravens.cimObjectType": "EnergyConsumer", + "IdentifiedObject.mRID": "096ed9d0-a350-44a9-95d6-fb50b867dbd7", + "IdentifiedObject.name": "l3", "EnergyConsumer.p": 6000.0, "EnergyConsumer.q": 3000.0, "EnergyConsumer.customerCount": 1, @@ -259,48 +312,23 @@ "EnergyConsumer.LoadResponse": "LoadResponseCharacteristic::'Constant kVA'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "8db69196-5be7-4038-a656-c345313d6dcc", - "IdentifiedObject.name": "l1_T1", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "036411ab-ea0c-4e3f-af4d-ac8ea9041a4a", + "IdentifiedObject.name": "l3_T1", "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.A", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.phases": "PhaseCode.C", + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" } ], "EnergyConsumer.EnergyConsumerPhase": [ { - "Ravens.CimObjectType": "EnergyConsumerPhase", - "IdentifiedObject.mRID": "445afb26-9fca-40ff-9161-1fae6c0c1619", - "IdentifiedObject.name": "l1_A", + "Ravens.cimObjectType": "EnergyConsumerPhase", + "IdentifiedObject.mRID": "bd2ee194-f130-4ec0-8377-d307edd995a7", + "IdentifiedObject.name": "l3_C", "EnergyConsumerPhase.p": 6000.0, "EnergyConsumerPhase.q": 3000.0, - "EnergyConsumerPhase.phase": "SinglePhaseKind.A" - } - ] - } - }, - "EnergySource": { - "source": { - "Ravens.CimObjectType": "EnergySource", - "IdentifiedObject.mRID": "5181f211-4f84-4220-905d-ce5a2136c86b", - "IdentifiedObject.name": "source", - "EnergySource.nominalVoltage": 400.0, - "EnergySource.voltageMagnitude": 398.36, - "EnergySource.voltageAngle": 0.0, - "EnergySource.r": 3.880570000581328e-08, - "EnergySource.x": 1.5522280002325312e-07, - "EnergySource.r0": 5.069596039676399e-08, - "EnergySource.x0": 1.5208788119029196e-07, - "Equipment.inService": true, - "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", - "ConductingEquipment.Terminals": [ - { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "f67ae006-bbc4-408b-90bc-ac62d33ce9d5", - "IdentifiedObject.name": "source_T1", - "ACDCTerminal.sequenceNumber": 1, - "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + "EnergyConsumerPhase.phase": "SinglePhaseKind.C" } ] } @@ -308,8 +336,8 @@ "RegulatingCondEq": { "PowerElectronicsConnection": { "pv1": { - "Ravens.CimObjectType": "PowerElectronicsConnection", - "IdentifiedObject.mRID": "997cec18-9472-4c89-8fb7-6e7d8ca4d377", + "Ravens.cimObjectType": "PowerElectronicsConnection", + "IdentifiedObject.mRID": "82240357-1de0-4930-9da2-a042c55c2080", "IdentifiedObject.name": "pv1", "PowerElectronicsConnection.maxIFault": 1.1111111111111112, "PowerElectronicsConnection.p": 9999.997590992734, @@ -322,25 +350,26 @@ "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "a1d1a18a-5c36-4804-8fc0-13f756823d19", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "d0cb3693-8e80-42fe-83b7-84266f17b3f1", "IdentifiedObject.name": "pv1_T1", "ACDCTerminal.sequenceNumber": 1, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_360.00000000000006-440.00000000000006'" } ], "PowerElectronicsConnection.PowerElectronicsUnit": { - "Ravens.CimObjectType": "PhotoVoltaicUnit", - "IdentifiedObject.mRID": "24872726-129e-491f-83cc-74135a8432b4", + "Ravens.cimObjectType": "PhotoVoltaicUnit", + "IdentifiedObject.mRID": "4dd3baeb-a830-448c-bede-267a947a5f3d", "IdentifiedObject.name": "pv1_PVPanels", "PowerElectronicsUnit.minP": 2000.0, "PowerElectronicsUnit.maxP": 500000.0 } }, "s1": { - "Ravens.CimObjectType": "PowerElectronicsConnection", - "IdentifiedObject.mRID": "cb0d7d2e-e799-4aaf-bb04-5daf2bfb9a00", + "Ravens.cimObjectType": "PowerElectronicsConnection", + "IdentifiedObject.mRID": "619bff40-d23e-4422-8aa6-9e06c94ca055", "IdentifiedObject.name": "s1", "PowerElectronicsConnection.maxIFault": 1.1111111111111112, "PowerElectronicsConnection.p": -0.0, @@ -353,269 +382,259 @@ "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", "ConductingEquipment.Terminals": [ { - "Ravens.CimObjectType": "Terminal", - "IdentifiedObject.mRID": "6f75e791-02dc-496f-8117-106bef0e0700", + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "9c7322ed-2a5c-4add-944e-d371fc080ac1", "IdentifiedObject.name": "s1_T1", "ACDCTerminal.sequenceNumber": 1, "Terminal.phases": "PhaseCode.ABC", - "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'" + "Terminal.ConnectivityNode": "ConnectivityNode::'loadbus'", + "ACDCTerminal.OperationalLimitSet": "OperationalLimitSet::'OpLimV_360.00000000000006-440.00000000000006'" } ], "PowerElectronicsConnection.PowerElectronicsUnit": { - "Ravens.CimObjectType": "BatteryUnit", - "IdentifiedObject.mRID": "09908453-5eb9-4927-817a-0dd0a84e0f95", + "Ravens.cimObjectType": "BatteryUnit", + "IdentifiedObject.mRID": "f9e87072-5642-4a89-8f14-8138a9a72fbd", "IdentifiedObject.name": "s1_Cells", - "PowerElectronicsUnit.minP": -60000.0, - "PowerElectronicsUnit.maxP": 60000.0, + "PowerElectronicsUnit.minP": -48000.0, + "PowerElectronicsUnit.maxP": 36000.0, "BatteryUnit.storedE": 6000.0, "BatteryUnit.ratedE": 60000.0, - "InefficientBatteryUnit.reserveEnery": 20.0, - "InefficientBatteryUnit.limitEnergy": 100.0, - "InefficientBatteryUnit.efficiencyDischarge": 98.0, - "InefficientBatteryUnit.efficiencyCharge": 95.0 + "BatteryUnit.BatteryUnitEfficiency": { + "Ravens.cimObjectType": "BatteryUnitEfficiency", + "BatteryUnitEfficiency.reserveEnergy": 20.0, + "BatteryUnitEfficiency.limitEnergy": 100.0, + "BatteryUnitEfficiency.efficiencyDischarge": 98.0, + "BatteryUnitEfficiency.efficiencyCharge": 95.0 + } } } } + }, + "EnergySource": { + "source": { + "Ravens.cimObjectType": "EnergySource", + "IdentifiedObject.mRID": "0dad6066-d7fa-43ef-b4a7-4c26345b242b", + "IdentifiedObject.name": "source", + "EnergySource.nominalVoltage": 400.0, + "EnergySource.voltageMagnitude": 398.36, + "EnergySource.voltageAngle": 0.0, + "EnergySource.r": 3.880570000581328e-08, + "EnergySource.x": 1.5522280002325312e-07, + "EnergySource.r0": 5.069596039676399e-08, + "EnergySource.x0": 1.5208788119029196e-07, + "Equipment.inService": true, + "ConductingEquipment.BaseVoltage": "BaseVoltage::'BaseV_0.4'", + "ConductingEquipment.Terminals": [ + { + "Ravens.cimObjectType": "Terminal", + "IdentifiedObject.mRID": "9c96ce0e-c82a-4a7b-8f27-b6fcd97ba6ce", + "IdentifiedObject.name": "source_T1", + "ACDCTerminal.sequenceNumber": 1, + "Terminal.phases": "PhaseCode.ABC", + "Terminal.ConnectivityNode": "ConnectivityNode::'sourcebus'" + } + ] + } } } } } }, - "Versions": { - "IEC61970CIMVersion": { - "Ravens.CimObjectType": "IEC61970CIMVersion", - "IEC61970CIMVersion.version": "IEC61970CIM100", - "IEC61970CIMVersion.date": "2019-04-01" - } - }, - "PerLengthLineParameter": { - "PerLengthImpedance": { - "PerLengthPhaseImpedance": { - "4/0quad": { - "Ravens.CimObjectType": "PerLengthPhaseImpedance", - "IdentifiedObject.mRID": "a2ccef36-6f66-45e7-8db4-fdd9766d8c8d", - "IdentifiedObject.name": "4/0quad", - "PerLengthPhaseImpedance.conductorCount": 3, - "PerLengthPhaseImpedance.PhaseImpedanceData": [ - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.0467, - "PhaseImpedanceData.x": 0.0267, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.0467, - "PhaseImpedanceData.x": 0.0267, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.1167, - "PhaseImpedanceData.x": 0.0667, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.0467, - "PhaseImpedanceData.x": 0.0267, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 3, - "PhaseImpedanceData.r": 0.1167, - "PhaseImpedanceData.x": 0.0667, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 1, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.1167, - "PhaseImpedanceData.x": 0.0667, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - } - ] + "OperationalLimitSet": { + "OpLimI_400.0_600.0": { + "Ravens.cimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "b1d5198a-0a07-41bb-a990-775416c29909", + "IdentifiedObject.name": "OpLimI_400.0_600.0", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.cimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "70c15f39-01ef-4500-9138-382ea716e1c7", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Emerg", + "CurrentLimit.value": 600.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_86400.0s'" }, - "556mcm": { - "Ravens.CimObjectType": "PerLengthPhaseImpedance", - "IdentifiedObject.mRID": "8a93bb2a-3217-48d0-b19b-ae8354399310", - "IdentifiedObject.name": "556mcm", - "PerLengthPhaseImpedance.conductorCount": 3, - "PerLengthPhaseImpedance.PhaseImpedanceData": [ - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 3, - "PhaseImpedanceData.r": 0.1, - "PhaseImpedanceData.x": 0.0583, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.04, - "PhaseImpedanceData.x": 0.0233, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 1, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.1, - "PhaseImpedanceData.x": 0.0583, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 2, - "PhaseImpedanceData.r": 0.1, - "PhaseImpedanceData.x": 0.0583, - "PhaseImpedanceData.b": 1.6000000000000003e-05 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 2, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.04, - "PhaseImpedanceData.x": 0.0233, - "PhaseImpedanceData.b": -0.0 - }, - { - "Ravens.CimObjectType": "PhaseImpedanceData", - "PhaseImpedanceData.row": 3, - "PhaseImpedanceData.column": 1, - "PhaseImpedanceData.r": 0.04, - "PhaseImpedanceData.x": 0.0233, - "PhaseImpedanceData.b": -0.0 - } - ] + { + "Ravens.cimObjectType": "CurrentLimit", + "IdentifiedObject.mRID": "71e23bab-fd7a-4528-a4fe-9fb27ad7a90b", + "IdentifiedObject.name": "OpLimI_400.0_600.0_Norm", + "CurrentLimit.value": 400.0, + "CurrentLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'absoluteValueType_5000000000.0s'" } - } + ] + }, + "OpLimV_380.0-420.00000000000006": { + "Ravens.cimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "19191123-2aea-4717-978d-8bb88ce9d7b7", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.cimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "a18292e3-76c4-4f03-99e2-b8c920848fa6", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAlow", + "VoltageLimit.value": 380.0, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + }, + { + "Ravens.cimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "78bba5c1-3498-4cad-83f3-be982608dd1f", + "IdentifiedObject.name": "OpLimV_380.0-420.00000000000006_RangeAhigh", + "VoltageLimit.value": 420.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + } + ] + }, + "OpLimV_360.00000000000006-440.00000000000006": { + "Ravens.cimObjectType": "OperationalLimitSet", + "IdentifiedObject.mRID": "82015c7d-be9a-4177-ad4b-8d42ce221f83", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006", + "OperationalLimitSet.OperationalLimitValue": [ + { + "Ravens.cimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "ea6856e9-952c-4101-bba3-2d82f189bd58", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAlow", + "VoltageLimit.value": 360.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'lowType_5000000000.0s'" + }, + { + "Ravens.cimObjectType": "VoltageLimit", + "IdentifiedObject.mRID": "acf94306-c465-4da7-9fb6-2b74ca85502e", + "IdentifiedObject.name": "OpLimV_360.00000000000006-440.00000000000006_RangeAhigh", + "VoltageLimit.value": 440.00000000000006, + "VoltageLimit.normalValue": 400.0, + "OperationalLimit.OperationalLimitType": "OperationalLimitType::'highType_5000000000.0s'" + } + ] } }, "Location": { - "primary_Location": { - "Ravens.CimObjectType": "Location", - "IdentifiedObject.mRID": "cd4c22b1-390a-48b4-ba9b-c5b0a6a13e79", - "IdentifiedObject.name": "primary_Location", + "loadbus_Location": { + "Ravens.cimObjectType": "Location", + "IdentifiedObject.mRID": "0d920a83-4bc1-4d38-9130-949bfdd94adb", + "IdentifiedObject.name": "loadbus_Location", "Location.PositionPoints": [ { - "Ravens.CimObjectType": "PositionPoint", - "PositionPoint.sequenceNumber": 1, - "PositionPoint.xPosition": 0.0, - "PositionPoint.yPosition": 0.0 + "Ravens.cimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 0, + "PositionPoint.xPosition": "0.0", + "PositionPoint.yPosition": "0.0" } ] }, - "loadbus_Location": { - "Ravens.CimObjectType": "Location", - "IdentifiedObject.mRID": "1f628e25-f631-49b3-b43c-b8618559661c", - "IdentifiedObject.name": "loadbus_Location", + "primary_Location": { + "Ravens.cimObjectType": "Location", + "IdentifiedObject.mRID": "c92d1246-2401-47ff-a3eb-433f1f3497f2", + "IdentifiedObject.name": "primary_Location", "Location.PositionPoints": [ { - "Ravens.CimObjectType": "PositionPoint", - "PositionPoint.sequenceNumber": 1, - "PositionPoint.xPosition": 0.0, - "PositionPoint.yPosition": 0.0 + "Ravens.cimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 0, + "PositionPoint.xPosition": "0.0", + "PositionPoint.yPosition": "0.0" } ] }, "sourcebus_Location": { - "Ravens.CimObjectType": "Location", - "IdentifiedObject.mRID": "17d93d69-c091-40d2-8292-e9800154e3f9", + "Ravens.cimObjectType": "Location", + "IdentifiedObject.mRID": "98ab82b1-c19c-47de-95f0-46c86dedead3", "IdentifiedObject.name": "sourcebus_Location", "Location.PositionPoints": [ { - "Ravens.CimObjectType": "PositionPoint", - "PositionPoint.sequenceNumber": 1, - "PositionPoint.xPosition": 0.0, - "PositionPoint.yPosition": 0.0 + "Ravens.cimObjectType": "PositionPoint", + "PositionPoint.sequenceNumber": 0, + "PositionPoint.xPosition": "0.0", + "PositionPoint.yPosition": "0.0" } ] } }, - "EnergyConnectionProfile": { - "Ravens.CimObjectType": "EnergyConnectionProfile", - "IdentifiedObject.mRID": "a7098736-cc57-4a69-b250-3101ae6dd9f5", - "IdentifiedObject.name": "Load::::::defaultload", - "EnergyConnectionProfile.dssSpectrum": "defaultload" + "Versions": { + "IEC61970CIMVersion": { + "Ravens.cimObjectType": "IEC61970CIMVersion", + "IEC61970CIMVersion.version": "IEC61970CIM100", + "IEC61970CIMVersion.date": "2019-04-01" + }, + "RavensVersion": { + "Ravens.cimObjectType": "RavensVersion", + "RavensVersion.date": "2025-03-10", + "RavensVersion.version": "RAVENSv0.3.0-dev" + } }, - "BaseVoltage": { - "BaseV_0.4": { - "Ravens.CimObjectType": "BaseVoltage", - "IdentifiedObject.mRID": "270f81bf-ab58-46e9-863a-08744d924604", - "IdentifiedObject.name": "BaseV_0.4", - "BaseVoltage.nominalVoltage": 400.0 + "EnergyConnectionProfile": { + "Load::::::defaultload": { + "Ravens.cimObjectType": "EnergyConnectionProfile", + "IdentifiedObject.mRID": "bbfe7b24-be64-40f5-b470-7b9a91e70e10", + "IdentifiedObject.name": "Load::::::defaultload", + "EnergyConnectionProfile.dssSpectrum": "defaultload" } }, "OperationalLimitType": { - "highType_5000000000.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "48f1510a-52d8-4c04-a0e7-59a8876eafa2", - "IdentifiedObject.name": "highType_5000000000.0s", - "OperationalLimitType.direction": "OperationalLimitDirectionKind.high", - "OperationalLimitType.acceptableDuration": 5000000000.0 - }, "absoluteValueType_5000000000.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "faf34841-2190-4133-bf8d-cf31f35a80a0", + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "3dc9bb35-c022-43de-a24c-846838ed7322", "IdentifiedObject.name": "absoluteValueType_5000000000.0s", "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", "OperationalLimitType.acceptableDuration": 5000000000.0 }, "absoluteValueType_86400.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "14a68643-2417-4e41-b809-940b9b1856d1", + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "b0603ff4-2f2a-4886-af77-a0de3a8c6346", "IdentifiedObject.name": "absoluteValueType_86400.0s", "OperationalLimitType.direction": "OperationalLimitDirectionKind.absoluteValue", "OperationalLimitType.acceptableDuration": 86400.0 }, "lowType_5000000000.0s": { - "Ravens.CimObjectType": "OperationalLimitType", - "IdentifiedObject.mRID": "33ce2fce-d1cb-4df3-924f-0399aa127edd", + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "d6567221-6669-4750-b09e-e346dfec213e", "IdentifiedObject.name": "lowType_5000000000.0s", "OperationalLimitType.direction": "OperationalLimitDirectionKind.low", "OperationalLimitType.acceptableDuration": 5000000000.0 + }, + "highType_5000000000.0s": { + "Ravens.cimObjectType": "OperationalLimitType", + "IdentifiedObject.mRID": "7d6d2a7b-bce7-4696-91d8-faa660c458b6", + "IdentifiedObject.name": "highType_5000000000.0s", + "OperationalLimitType.direction": "OperationalLimitDirectionKind.high", + "OperationalLimitType.acceptableDuration": 5000000000.0 } }, "ConnectivityNode": { "loadbus": { - "Ravens.CimObjectType": "ConnectivityNode", - "IdentifiedObject.mRID": "0f25fa64-77ce-4721-ad73-ecad9127fa2e", + "Ravens.cimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "193ba930-8505-4feb-b824-7042f4c2cc9e", "IdentifiedObject.name": "loadbus", "ConnectivityNode.OperationalLimitSet": "OperationalLimitSet::'OpLimV_380.0-420.00000000000006'" }, - "sourcebus": { - "Ravens.CimObjectType": "ConnectivityNode", - "IdentifiedObject.mRID": "e4ff4b6e-79fe-40b2-af40-e0226cf5f4a4", - "IdentifiedObject.name": "sourcebus" - }, "primary": { - "Ravens.CimObjectType": "ConnectivityNode", - "IdentifiedObject.mRID": "cc97ba78-4f37-4d8f-8044-55f023a74a28", + "Ravens.cimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "144607fb-7af7-4c65-b328-9dfb1225a38c", "IdentifiedObject.name": "primary" + }, + "sourcebus": { + "Ravens.cimObjectType": "ConnectivityNode", + "IdentifiedObject.mRID": "565090d8-b906-4e80-babf-63f8597a7fcd", + "IdentifiedObject.name": "sourcebus" } }, "LoadResponseCharacteristic": { "Constant kVA": { - "Ravens.CimObjectType": "LoadResponseCharacteristic", - "IdentifiedObject.mRID": "141f856d-53fd-4d9b-b71b-464b1db94318", + "Ravens.cimObjectType": "LoadResponseCharacteristic", + "IdentifiedObject.mRID": "1e4cf027-4833-47f3-9566-8c891dea8926", "IdentifiedObject.name": "Constant kVA", - "LoadResponseCharacteristic.pConstantPower": 100, - "LoadResponseCharacteristic.qConstantPower": 100 + "LoadResponseCharacteristic.pConstantPower": 100.0, + "LoadResponseCharacteristic.qConstantPower": 100.0 + } + }, + "BaseVoltage": { + "BaseV_0.4": { + "Ravens.cimObjectType": "BaseVoltage", + "IdentifiedObject.mRID": "55b47d8e-eca0-4fd4-a309-ecc81bdb6fa1", + "IdentifiedObject.name": "BaseV_0.4", + "BaseVoltage.nominalVoltage": 400.0 } } -} +} \ No newline at end of file From b15bf8ef2a95ed0022534c4eceadd9c03fba994b Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 19 Mar 2025 13:14:44 -0600 Subject: [PATCH 43/99] FIX: issues related to Switch.open, default angles for energy source, transformertanks new way to define terminals, and TODO check on redefining terminals of bus depending on what is connected to the bus. --- src/data_model/transformations/ravens2math.jl | 138 +++++++++--- src/data_model/utils_ravens.jl | 6 +- src/prob/common.jl | 196 ++++++++++++++++-- 3 files changed, 287 insertions(+), 53 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 57cd7dc7b..926476efc 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -80,7 +80,10 @@ function _map_ravens2math( "voltage_scale_factor" => 1e3, "power_scale_factor" => 1e3, "base_frequency" => get(_data_ravens, "BaseFrequency", 60.0), - "vbases_default" => Dict{String,Real}() + "vbases_default" => Dict{String,Real}(), + "vbases_network" => Dict{String,Real}(), + "vbases_buses" => Dict{String,Real}() + ) # Multinetwork @@ -286,8 +289,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: conductors = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["Conductor"] for (name, ravens_obj) in get(conductors, "ACLineSegment", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj_ravens("ac_line_segment", name, ravens_obj, length(data_math["branch"]) + 1; pass_props=pass_props) - + math_obj = _init_math_obj_ravens("conductor", name, ravens_obj, length(data_math["branch"]) + 1; pass_props=pass_props) nconds = length(ravens_obj["ACLineSegment.ACLineSegmentPhase"]) # number of conductors/wires nphases = 0 # init number of phases terminals = ravens_obj["ConductingEquipment.Terminals"] @@ -310,11 +312,19 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: nphases = nconds end + # TODO: Revise if the elseif is needed! for bus in [math_obj["f_bus"], math_obj["t_bus"]] - data_math["bus"][string(bus)]["terminals"] = bus_terminals - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + if !(haskey(data_math["bus"][string(bus)], "terminals")) + data_math["bus"][string(bus)]["terminals"] = bus_terminals + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + elseif (length(data_math["bus"][string(bus)]["terminals"]) < length(bus_terminals)) + data_math["bus"][string(bus)]["terminals"] = bus_terminals + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + end end math_obj["f_connections"] = bus_terminals @@ -611,7 +621,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data for wdg_id in 1:nrw # wdg phasecode & terminals - wdg_terminals = wdgs[wdg_id]["ConductingEquipment.Terminals"][1] + wdg_terminals = ravens_obj["ConductingEquipment.Terminals"][wdg_id] wdg_phasecode = wdg_terminals["Terminal.phases"] # wdg endNumber @@ -628,6 +638,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data nphases = length(connections[wdg_endNumber]) # add terminals and voltage limits info. if missing + # TODO: Revise if the elseif is needed! node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) bus = data_math["bus_lookup"][node] if !(haskey(data_math["bus"][string(bus)], "terminals")) @@ -635,6 +646,11 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + elseif (length(data_math["bus"][string(bus)]["terminals"]) < length(connections[wdg_endNumber])) + data_math["bus"][string(bus)]["terminals"] = connections[wdg_endNumber] + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) end # wdgs configurations @@ -650,6 +666,9 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data vnom[wdg_endNumber] = wdgs[wdg_endNumber]["PowerTransformerEnd.ratedU"] snom[wdg_endNumber] = wdgs[wdg_endNumber]["PowerTransformerEnd.ratedS"] + # Add vnom info to vbases + data_math["settings"]["vbases_network"][string(bus)] = deepcopy(vnom[wdg_endNumber]/voltage_scale_factor) + # resistance transf_star_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.StarImpedance", Dict()) r_s[wdg_endNumber] = get(wdgs[wdg_endNumber], "PowerTransformerEnd.r", @@ -721,7 +740,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data tm_nom = wdgs_confs[wdg_id]==DELTA ? wdgs[wdg_id]["PowerTransformerEnd.ratedU"]*sqrt(3)/voltage_scale_factor : wdgs[wdg_id]["PowerTransformerEnd.ratedU"]/voltage_scale_factor # Get correct f_node for winding - wdg_term = wdgs[wdg_id]["ConductingEquipment.Terminals"][1] + wdg_term = ravens_obj["ConductingEquipment.Terminals"][wdg_id] f_node_wdgterm = _extract_name(wdg_term["Terminal.ConnectivityNode"]) # Transformer Object @@ -821,7 +840,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data for wdg_id in 1:nrw # wdg terminals & phasecode - wdg_terminals = wdgs[wdg_id]["ConductingEquipment.Terminals"][1] + wdg_terminals = ravens_obj["ConductingEquipment.Terminals"][wdg_id] wdg_phasecode = wdg_terminals["Terminal.phases"] # wdg endNumber @@ -933,12 +952,20 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data for i in 1:length(nodes) n = nodes[i] bus = data_math["bus_lookup"][n] + # TODO: Revise if the elseif is needed! if !(haskey(data_math["bus"][string(bus)], "terminals")) data_math["bus"][string(bus)]["terminals"] = connections[i] data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + elseif (length(data_math["bus"][string(bus)]["terminals"]) < length(connections[i])) + data_math["bus"][string(bus)]["terminals"] = connections[i] + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) end + # Add vnom info to bus + data_math["settings"]["vbases_network"][string(bus)] = deepcopy(vnom[i]/voltage_scale_factor) end # wdg i, tank 1 - assumes tank 1 always exists @@ -1058,7 +1085,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data for wdg_id in 1:nrw - wdg_terminals = wdgs_data[wdg_id]["ConductingEquipment.Terminals"][1] + wdg_terminals = ravens_obj["ConductingEquipment.Terminals"][wdg_id] wdg_phasecode = wdg_terminals["Terminal.phases"] wdg_endNumber = wdgs_data[wdg_id]["TransformerEnd.endNumber"] @@ -1074,12 +1101,18 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data @error("PhaseCode not supported yet!") end + # TODO: Revise if the elseif is needed! nphases = length(wdg_connections) if !(haskey(data_math["bus"][string(bus)], "terminals")) data_math["bus"][string(bus)]["terminals"] = wdg_connections data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + elseif (length(data_math["bus"][string(bus)]["terminals"]) < length(wdg_connections)) + data_math["bus"][string(bus)]["terminals"] = wdg_connections + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) end # transformer tank end info. @@ -1093,6 +1126,9 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # assign vnom_wdg to vnom for transformer vnom[wdg_endNumber] = vnom_wdg + # Add vnom info to bus + data_math["settings"]["vbases_network"][string(bus)] = deepcopy(vnom_wdg/voltage_scale_factor) + # resistance computation transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) r_s[wdg_endNumber] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", @@ -1189,7 +1225,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data tm_nom = wdgs_confs[wdg_id]==DELTA ? vnom[wdg_id]*sqrt(3)/voltage_scale_factor : vnom[wdg_id]/voltage_scale_factor # Get correct f_node for winding - wdg_term = wdgs_data[wdg_id]["ConductingEquipment.Terminals"][1] + wdg_term = ravens_obj["ConductingEquipment.Terminals"][wdg_id] f_node_wdgterm = _extract_name(wdg_term["Terminal.ConnectivityNode"]) # Transformer Object @@ -1238,6 +1274,11 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data end end end + + # Checks and calculates voltage bases for elements that do not have Voltage Bases. + # TODO: Revise if this is the best way to be calculate vbases for missing elements + data_math["settings"]["vbases_buses"] = calc_math_voltage_bases(data_math, data_math["settings"]["vbases_network"])[1] # [1] bus_vbase, [2] edge_vbase + end @@ -1279,16 +1320,19 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r math_obj["model"] = POWER end - # Set the nominal voltage - base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) - base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - # math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor) / (sqrt(3) / 2) - math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor_sqrt3) - # Set voltage bounds for the bus connected bus_info = string(math_obj["load_bus"]) bus_conn = data_math["bus"][bus_info] + # Set the nominal voltage + if haskey(ravens_obj, "ConductingEquipment.BaseVoltage") + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) + base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor_sqrt3) + else + math_obj["vnom_kv"] = data_math["settings"]["vbases_buses"][bus_info] + end + if haskey(data_ravens["ConnectivityNode"][connectivity_node], "ConnectivityNode.OperationalLimitSet") op_limit_id = _extract_name(data_ravens["ConnectivityNode"][connectivity_node]["ConnectivityNode.OperationalLimitSet"]) op_limits = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"] @@ -1409,8 +1453,8 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r # Set the configuration - # TODO: ADD: "PhaseShuntConnectionKind.Yn", "PhaseShuntConnectionKind.I", "PhaseShuntConnectionKind.G" - config_map = Dict("PhaseShuntConnectionKind.Y" => WYE, "PhaseShuntConnectionKind.D" => DELTA) + # TODO: ADD: "PhaseShuntConnectionKind.I", "PhaseShuntConnectionKind.G" + config_map = Dict("PhaseShuntConnectionKind.Y" => WYE, "PhaseShuntConnectionKind.D" => DELTA, "PhaseShuntConnectionKind.Yn" => WYE) config = get(config_map, ravens_obj["EnergyConsumer.phaseConnection"], nothing) if config !== nothing math_obj["configuration"] = config @@ -1418,6 +1462,12 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r @error("Configuration of load $(name) is not supported.") end + # Correct (if needed) single-phase DELTA connections + if (math_obj["configuration"] == DELTA) && (nphases == 1) + math_obj["configuration"] = WYE + @warn "EnergyConsumer (load): $name has DELTA configuration but only 1 connection (phase). DELTA configurations must have at least 2 or 3 connections!" + end + # Set status, dispatchable flag, and index math_obj["status"] = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true math_obj["status"] = math_obj["status"] == true ? 1 : 0 @@ -1491,10 +1541,15 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav math_obj["configuration"] = get(ravens_obj, "EnergySource.connectionKind", WYE) - # Vnom and vbases_default - base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) - vnom = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] / sqrt(nconductors) - data_math["settings"]["vbases_default"][connectivity_node] = vnom / voltage_scale_factor + # Set the nominal voltage + if haskey(ravens_obj, "ConductingEquipment.BaseVoltage") + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) + vnom = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] / sqrt(nconductors) + data_math["settings"]["vbases_default"][connectivity_node] = vnom / voltage_scale_factor + else + vnom = ravens_obj["EnergySource.nominalVoltage"] / sqrt(nconductors) + data_math["settings"]["vbases_default"][connectivity_node] = vnom / voltage_scale_factor + end # Power, voltage, and limits nphases = nconductors # You can adjust nphases based on your specific kron reduction logic if needed @@ -1531,7 +1586,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav "name" => "_virtual_bus.energy_source.$name", "bus_type" => math_obj["gen_status"] == 0 ? 4 : math_obj["control_mode"] == Int(ISOCHRONOUS) ? 3 : 2, "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), - "va" => rad2deg.(_wrap_to_pi.([-2 * π / nphases * (i - 1) + ravens_obj["EnergySource.voltageAngle"] for i in 1:nphases])), + "va" => rad2deg.(_wrap_to_pi.([-2 * π / nphases * (i - 1) + get(ravens_obj, "EnergySource.voltageAngle", 0.0) for i in 1:nphases])), "vmin" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), "vmax" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), "vm_pair_lb" => deepcopy(get(ravens_obj, "EnergySource.vpairMin", Tuple{Any,Any,Real}[])), @@ -1572,7 +1627,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav data_math["bus"]["$gen_bus"]["vmin"] = [vm_lb..., fill(0.0, nconductors - nphases)...] data_math["bus"]["$gen_bus"]["vmax"] = [vm_ub..., fill(Inf, nconductors - nphases)...] data_math["bus"]["$gen_bus"]["vm"] = fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases) - data_math["bus"]["$gen_bus"]["va"] = rad2deg.(_wrap_to_pi.([-2 * π / nphases * (i - 1) + ravens_obj["EnergySource.voltageAngle"] for i in 1:nphases])) + data_math["bus"]["$gen_bus"]["va"] = rad2deg.(_wrap_to_pi.([-2 * π / nphases * (i - 1) + get(ravens_obj, "EnergySource.voltageAngle", 0.0) for i in 1:nphases])) data_math["bus"]["$gen_bus"]["bus_type"] = _compute_bus_type(bus_conn["bus_type"], math_obj["gen_status"], math_obj["control_mode"]) end @@ -1633,11 +1688,16 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) - # Set the nominal voltage - base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) - nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - base_voltage = nominal_voltage / sqrt(nconductors) - math_obj["vbase"] = base_voltage / voltage_scale_factor + # Set the nominal voltage + bus_conn = data_math["bus"]["$(math_obj["gen_bus"])"] + if haskey(ravens_obj, "ConductingEquipment.BaseVoltage") + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) + nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + base_voltage = nominal_voltage / sqrt(nconductors) + math_obj["vbase"] = base_voltage / voltage_scale_factor + else + math_obj["vbase"] = data_math["settings"]["vbases_buses"][string(math_obj["gen_bus"])] + end if control_mode == Int(ISOCHRONOUS) && status == 1 data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) @@ -1907,18 +1967,30 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di math_obj["t_bus"] = data_math["bus_lookup"][t_node] # Add vmin/vmax/terminals infor to fbus and tbus if missing + # TODO: Revise if the elseif is needed! if !(haskey(data_math["bus"][string(math_obj["f_bus"])], "terminals")) data_math["bus"][string(math_obj["f_bus"])]["terminals"] = f_conns data_math["bus"][string(math_obj["f_bus"])]["vmin"] = fill(0.0, nphases) data_math["bus"][string(math_obj["f_bus"])]["vmax"] = fill(Inf, nphases) data_math["bus"][string(math_obj["f_bus"])]["grounded"] = zeros(Bool, nphases) + elseif (length(data_math["bus"][string(math_obj["f_bus"])]["terminals"]) < length(f_conns)) + data_math["bus"][string(math_obj["f_bus"])]["terminals"] = f_conns + data_math["bus"][string(math_obj["f_bus"])]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(math_obj["f_bus"])]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(math_obj["f_bus"])]["grounded"] = zeros(Bool, nphases) end + # TODO: Revise if the elseif is needed! if !(haskey(data_math["bus"][string(math_obj["t_bus"])], "terminals")) data_math["bus"][string(math_obj["t_bus"])]["terminals"] = t_conns data_math["bus"][string(math_obj["t_bus"])]["vmin"] = fill(0.0, nphases) data_math["bus"][string(math_obj["t_bus"])]["vmax"] = fill(Inf, nphases) data_math["bus"][string(math_obj["t_bus"])]["grounded"] = zeros(Bool, nphases) + elseif (length(data_math["bus"][string(math_obj["t_bus"])]["terminals"]) < length(t_conns)) + data_math["bus"][string(math_obj["t_bus"])]["terminals"] = t_conns + data_math["bus"][string(math_obj["t_bus"])]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(math_obj["t_bus"])]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(math_obj["t_bus"])]["grounded"] = zeros(Bool, nphases) end # TODO: Status @@ -1926,8 +1998,8 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di math_obj["status"] = status = math_obj["status"] == true ? 1 : 0 # State - sw_state = get(ravens_obj, "Switch.open", "false") - sw_state = sw_state == "false" ? CLOSED : OPEN + sw_state = get(ravens_obj, "Switch.open", false) + sw_state = sw_state == false ? CLOSED : OPEN math_obj["state"] = Int(sw_state) # TODO: Dispatchable diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index eab10860c..7f831563e 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -1,11 +1,15 @@ const _phasecode_map = Dict( + "PhaseCode.ABCN" => [1, 2, 3], "PhaseCode.ABC" => [1, 2, 3], "PhaseCode.AB" => [1, 2], "PhaseCode.AC" => [1, 3], "PhaseCode.BC" => [2, 3], "PhaseCode.A" => [1], "PhaseCode.B" => [2], - "PhaseCode.C" => [3] + "PhaseCode.C" => [3], + "PhaseCode.AN" => [1], + "PhaseCode.BN" => [2], + "PhaseCode.CN" => [3] ) _phase_map = Dict( diff --git a/src/prob/common.jl b/src/prob/common.jl index ddc604a9d..7ed75d4d5 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,16 +116,78 @@ function instantiate_mc_model( ) end - # @info "$(data["bus"])" - - # for i in data["branch"] - # # @info "+++++++++++++++++++++++++++++++++++++++++++++++++++++" - # # @info "$(i)" - # for (j,k) in enumerate(i) - # for l in k - # @info "$(l)" - # end - # end + # for (i,j) in data["transformer"] + + # # @info "Name: $(i)" + # # @info "Data: $(j)" + + # # # BRANCHES + # # @info "$(j["name"])" + # # @info "$(j["f_bus"])" + # # @info "$(j["f_connections"])" + # # @info "$(j["t_bus"])" + # # @info "$(j["t_connections"])" + # # @info "$(j["br_status"])" + + # # # BUS + # # @info "$(j["name"])" + # # @info "$(j["grounded"])" + # # @info "$(j["vmin"])" + # # @info "$(j["vmax"])" + # # @info "$(j["bus_i"])" + # # @info "$(j["terminals"])" + # # @info "$(j["index"])" + # # @info "$(j["bus_type"])" + + # # # GENS + # # @info "$(j["name"])" + # # @info "$(j["model"])" + # # @info "$(j["connections"])" + # # @info "$(j["configuration"])" + # # @info "$(j["gen_bus"])" + # # @info "$(j["gen_status"])" + # # @info "$(j["control_mode"])" + # # @info "$(j["pmin"])" + # # @info "$(j["pmax"])" + # # @info "$(j["qmin"])" + # # @info "$(j["qmax"])" + + # # # SWITCHES + # # @info "$(j["name"])" + # # @info "$(j["f_bus"])" + # # @info "$(j["f_connections"])" + # # @info "$(j["t_bus"])" + # # @info "$(j["t_connections"])" + # # @info "$(j["vbase"])" + # # @info "$(j["status"])" + + # # # TRANSFORMER + # # @info "$(j["name"])" + # # @info "$(j["f_bus"])" + # # @info "$(j["f_connections"])" + # # @info "$(j["t_bus"])" + # # @info "$(j["t_connections"])" + # # @info "$(j["polarity"])" + # # @info "$(j["status"])" + # # @info "$(j["index"])" + # # @info "$(j["configuration"])" + # # @info "$(j["sm_ub"])" + # # @info "$(j["cm_ub"])" + # # @info "$(j["f_vbase"])" + # # @info "$(j["t_vbase"])" + + # # # LOAD + # # @info "$(j["name"])" + # # @info "$(j["model"])" + # # @info "$(j["pd"])" + # # @info "$(j["qd"])" + # # @info "$(j["vbase"])" + # # @info "$(j["vnom_kv"])" + # # @info "$(j["load_bus"])" + # # @info "$(j["index"])" + # # @info "$(j["configuration"])" + # # @info "$(j["connections"])" + # end # DEFINIDOEN_instantiate_mc_model @@ -168,18 +230,114 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - # @info "$(data["bus"])" - # for i in data["branch"] - # # @info "+++++++++++++++++++++++++++++++++++++++++++++++++++++" - # # @info "$(i)" - # for (j,k) in enumerate(i) - # for l in k - # @info "$(l)" - # end - # end + + # for (i,j) in data["transformer"] + + + # # @info "Name: $(i)" + # # @info "Data: $(j)" + + # # # BRANCHES + # # @info "$(j["name"])" + # # @info "$(j["f_bus"])" + # # @info "$(j["f_connections"])" + # # @info "$(j["t_bus"])" + # # @info "$(j["t_connections"])" + # # @info "$(j["br_status"])" + + # # # BUS + # # @info "$(j["name"])" + # # @info "$(j["grounded"])" + # # @info "$(j["vmin"])" + # # @info "$(j["vmax"])" + # # @info "$(j["bus_i"])" + # # @info "$(j["terminals"])" + # # @info "$(j["index"])" + # # @info "$(j["bus_type"])" + + # # # GENS + # # @info "$(j["name"])" + # # @info "$(j["model"])" + # # @info "$(j["connections"])" + # # @info "$(j["configuration"])" + # # @info "$(j["gen_bus"])" + # # @info "$(j["gen_status"])" + # # @info "$(j["control_mode"])" + # # @info "$(j["pmin"])" + # # @info "$(j["pmax"])" + # # @info "$(j["qmin"])" + # # @info "$(j["qmax"])" + + # # # SWITCHES + # # @info "$(j["name"])" + # # @info "$(j["f_bus"])" + # # @info "$(j["f_connections"])" + # # @info "$(j["t_bus"])" + # # @info "$(j["t_connections"])" + # # @info "$(j["vbase"])" + # # @info "$(j["status"])" + + # # # TRANSFORMER + # # @info "$(j["name"])" + # # # @info "$(j["f_bus"])" + # # @info "$(j["f_connections"])" + # # # @info "$(j["t_bus"])" + # # @info "$(j["t_connections"])" + # # @info "$(j["polarity"])" + # # # @info "$(j["status"])" + # # # @info "$(j["index"])" + # # # @info "$(j["configuration"])" + # # @info "$(j["sm_ub"])" + # # # @info "$(j["cm_ub"])" + # # # @info "$(j["f_vbase"])" + # # # @info "$(j["t_vbase"])" + # # @info "++++++++++++++++++++++++++++++" + + + # # if (j["index"] == 479) + # # @info "$(j["name"])" + # # @info "$(j)" + # # @info "++++++++++++++++++++++++++++++" + + # # end + + + # # if (j["f_connections"] != j["t_connections"]) + + # # @info "$(j["name"])" + # # # @info "$(j["f_bus"])" + # # @info "$(j["f_connections"])" + # # # @info "$(j["t_bus"])" + # # @info "$(j["t_connections"])" + # # @info "$(j["polarity"])" + # # # @info "$(j["status"])" + # # # @info "$(j["index"])" + # # # @info "$(j["configuration"])" + # # @info "$(j["sm_ub"])" + # # # @info "$(j["cm_ub"])" + # # # @info "$(j["f_vbase"])" + # # # @info "$(j["t_vbase"])" + # # @info "++++++++++++++++++++++++++++++" + + # # end + + # # # LOAD + # # @info "$(j["name"])" + # # @info "$(j["model"])" + # # @info "$(j["pd"])" + # # @info "$(j["qd"])" + # # @info "$(j["vbase"])" + # # @info "$(j["vnom_kv"])" + # # @info "$(j["load_bus"])" + # # @info "$(j["index"])" + # # @info "$(j["configuration"])" + # # @info "$(j["connections"])" + + # end + # DEFINIDOEN_instantiate_mc_model_ravens return _IM.instantiate_model( From ff883463a14d57efd4adc4f9d67b949f995104f8 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 24 Mar 2025 16:24:53 -0600 Subject: [PATCH 44/99] ADD: ratiotapchanger regulators to transformers. --- src/data_model/transformations/ravens2math.jl | 127 +++++++++++++++--- 1 file changed, 109 insertions(+), 18 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 926476efc..a3e758ecc 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -611,7 +611,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data g_sh = zeros(Float64, nrw) b_sh = zeros(Float64, nrw) - # Regulator set init + # Init RatioTapChanger data (default) tm_set = Vector{Vector{Float64}}(undef, nrw) tm_lb = Vector{Vector{Float64}}(undef, nrw) tm_ub = Vector{Vector{Float64}}(undef, nrw) @@ -684,8 +684,40 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data g_sh[wdg_id] = get(transf_core_impedance, "TransformerCoreAdmittance.g", 0.0) b_sh[wdg_id] = - get(transf_core_impedance, "TransformerCoreAdmittance.b", 0.0) - # TODO: RatioTapChanger - if haskey(wdgs[wdg_id], "TransformerEnd.RatioTapChanger") + + # Set RatioTapChanger in specific wdg + if haskey(wdgs[wdg_endNumber], "TransformerEnd.RatioTapChanger") + + rtc_name = _extract_name(wdgs[wdg_endNumber]["TransformerEnd.RatioTapChanger"]) + rtc_data = data_ravens["PowerSystemResource"]["TapChanger"]["RatioTapChanger"][rtc_name] + + # tm_step + hstep = get(rtc_data, "TapChanger.highStep", 16) + lstep = get(rtc_data, "TapChanger.lowStep", -16) + step_dist = abs(hstep) + abs(lstep) + step_tap = 1/step_dist + tm_step[wdg_endNumber] = fill(step_tap, nphases) + + # tm_set + step = get(rtc_data, "TapChanger.step", 1.0) # Starting Tap changer position/step + tm_set[wdg_endNumber] = fill(step, nphases) + + # tm_fix + ltcFlag = get(rtc_data, "TapChanger.ltcFlag", false) + if (ltcFlag == true) + tm_fix[wdg_endNumber] = zeros(Bool, nphases) + else + tm_fix[wdg_endNumber] = ones(Bool, nphases) + end + + # tm_ub/tm_lb + neutralVoltPu = get(rtc_data, "TapChanger.neutralU", vnom[wdg_endNumber])/vnom[wdg_endNumber] + step_volt_increment = get(rtc_data, "RatioTapChanger.stepVoltageIncrement", 100.0) + volt_lb = neutralVoltPu + step_tap * (step_volt_increment/100.0) * lstep + volt_ub = neutralVoltPu + step_tap * (step_volt_increment/100.0) * hstep + tm_lb[wdg_endNumber] = fill(volt_lb, nphases) + tm_ub[wdg_endNumber] = fill(volt_ub, nphases) + else # default tm_set[wdg_id] = fill(1.0, nphases) tm_lb[wdg_id] = fill(0.9, nphases) @@ -828,6 +860,13 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data configuration_prev = [] vnom_prev = [] + # Init RatioTapChanger data (default) + tm_set = Vector{Vector{Float64}}(fill(fill(1.0, nphases), nrw)) + tm_lb = Vector{Vector{Float64}}(fill(fill(0.9, nphases), nrw)) + tm_ub = Vector{Vector{Float64}}(fill(fill(1.1, nphases), nrw)) + tm_fix = Vector{Vector{Bool}}(fill(ones(Bool, nphases), nrw)) + tm_step = Vector{Vector{Float64}}(fill(fill(1/32, nphases), nrw)) + for tank_id in 1:ntanks # Get wdg data @@ -921,6 +960,40 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data cm_ub[wdg_endNumber] = cm_wdg end + # Set RatioTapChanger in specific wdg + if haskey(wdgs[wdg_endNumber], "TransformerEnd.RatioTapChanger") + + rtc_name = _extract_name(wdgs[wdg_endNumber]["TransformerEnd.RatioTapChanger"]) + rtc_data = data_ravens["PowerSystemResource"]["TapChanger"]["RatioTapChanger"][rtc_name] + + # tm_step + hstep = get(rtc_data, "TapChanger.highStep", 16) + lstep = get(rtc_data, "TapChanger.lowStep", -16) + step_dist = abs(hstep) + abs(lstep) + step_tap = 1/step_dist + tm_step[wdg_endNumber] = fill(step_tap, nphases) + + # tm_set + step = get(rtc_data, "TapChanger.step", 1.0) # Starting Tap changer position/step + tm_set[wdg_endNumber] = fill(step, nphases) + + # tm_fix + ltcFlag = get(rtc_data, "TapChanger.ltcFlag", false) + if (ltcFlag == true) + tm_fix[wdg_endNumber] = zeros(Bool, nphases) + else + tm_fix[wdg_endNumber] = ones(Bool, nphases) + end + + # tm_ub/tm_lb + neutralVoltPu = get(rtc_data, "TapChanger.neutralU", vnom[wdg_endNumber])/vnom[wdg_endNumber] + step_volt_increment = get(rtc_data, "RatioTapChanger.stepVoltageIncrement", 100.0) + volt_lb = neutralVoltPu + step_tap * (step_volt_increment/100.0) * lstep + volt_ub = neutralVoltPu + step_tap * (step_volt_increment/100.0) * hstep + tm_lb[wdg_endNumber] = fill(volt_lb, nphases) + tm_ub[wdg_endNumber] = fill(volt_ub, nphases) + end + end ### --- Consistency checks across tanks --- @@ -978,13 +1051,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data y_sh = g_sh + im*b_sh z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) - # TODO: RatioTapChanger - How to get wdg_Data correctly? - tm_set = Vector{Vector{Float64}}(fill(fill(1.0, nphases), nrw)) - tm_lb = Vector{Vector{Float64}}(fill(fill(0.9, nphases), nrw)) - tm_ub = Vector{Vector{Float64}}(fill(fill(1.1, nphases), nrw)) - tm_fix = Vector{Vector{Bool}}(fill(ones(Bool, nphases), nrw)) - tm_step = Vector{Vector{Float64}}(fill(fill(1/32, nphases), nrw)) - # TODO: Polarity polarity = fill(1, nrw) @@ -1076,7 +1142,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # configurations wdgs_confs = Vector{ConnConfig}(undef, nrw) - # Regulator set init + # Init RatioTapChanger data (default) tm_set = Vector{Vector{Float64}}(undef, nrw) tm_lb = Vector{Vector{Float64}}(undef, nrw) tm_ub = Vector{Vector{Float64}}(undef, nrw) @@ -1167,14 +1233,39 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data @error("PowerTransformer ConnectionKind not supported yet!") end - # TODO: RatioTapChanger + # Set RatioTapChanger in specific wdg if haskey(wdgs_data[wdg_endNumber], "TransformerEnd.RatioTapChanger") - # TODO: default for now, but needs to be corrected! - tm_set[wdg_endNumber] = fill(1.0, nphases) - tm_lb[wdg_endNumber] = fill(0.9, nphases) - tm_ub[wdg_endNumber] = fill(1.1, nphases) - tm_fix[wdg_endNumber] = ones(Bool, nphases) - tm_step[wdg_endNumber] = fill(1/32, nphases) + + rtc_name = _extract_name(wdgs_data[wdg_endNumber]["TransformerEnd.RatioTapChanger"]) + rtc_data = data_ravens["PowerSystemResource"]["TapChanger"]["RatioTapChanger"][rtc_name] + + # tm_step + hstep = get(rtc_data, "TapChanger.highStep", 16) + lstep = get(rtc_data, "TapChanger.lowStep", -16) + step_dist = abs(hstep) + abs(lstep) + step_tap = 1/step_dist + tm_step[wdg_endNumber] = fill(step_tap, nphases) + + # tm_set + step = get(rtc_data, "TapChanger.step", 1.0) # Starting Tap changer position/step + tm_set[wdg_endNumber] = fill(step, nphases) + + # tm_fix + ltcFlag = get(rtc_data, "TapChanger.ltcFlag", false) + if (ltcFlag == true) + tm_fix[wdg_endNumber] = zeros(Bool, nphases) + else + tm_fix[wdg_endNumber] = ones(Bool, nphases) + end + + # tm_ub/tm_lb + neutralVoltPu = get(rtc_data, "TapChanger.neutralU", vnom[wdg_endNumber])/vnom[wdg_endNumber] + step_volt_increment = get(rtc_data, "RatioTapChanger.stepVoltageIncrement", 100.0) + volt_lb = neutralVoltPu + step_tap * (step_volt_increment/100.0) * lstep + volt_ub = neutralVoltPu + step_tap * (step_volt_increment/100.0) * hstep + tm_lb[wdg_endNumber] = fill(volt_lb, nphases) + tm_ub[wdg_endNumber] = fill(volt_ub, nphases) + else # default tm_set[wdg_endNumber] = fill(1.0, nphases) tm_lb[wdg_endNumber] = fill(0.9, nphases) From 62e5bef9da31f99de902c363a8b79dbf717cf268 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 25 Mar 2025 13:43:21 -0600 Subject: [PATCH 45/99] ADD: RatioTapChanger operations and control ravens parsing. --- src/data_model/transformations/ravens2math.jl | 82 +++++++++++++++---- 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index a3e758ecc..194b58a47 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -602,6 +602,10 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # configurations wdgs_confs = Vector{ConnConfig}(undef, nrw) + # RegulatorControls flag + reg_controls = [false for _ in 1:nrw] + reg_obj = [Dict() for _ in 1:nrw] + # Transformer data for each winding vnom = Vector{Float64}(undef, nrw) snom = Vector{Float64}(undef, nrw) @@ -718,6 +722,19 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data tm_lb[wdg_endNumber] = fill(volt_lb, nphases) tm_ub[wdg_endNumber] = fill(volt_ub, nphases) + # Regulator Control + if haskey(rtc_data, "TapChanger.TapChangerControl") && !all(tm_fix[wdg_endNumber]) + reg_controls[wdg_endNumber] = true + reg_obj[wdg_endNumber] = Dict{String,Any}( + "vreg" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetValue"], nphases), + "band" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetDeadband"], nphases), + "ptratio" => fill(rtc_data["TapChanger.ptRatio"], nphases), + "ctprim" => fill(rtc_data["TapChanger.ctRating"], nphases), + "r" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropR"], nphases), + "x" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropX"], nphases) + ) + end + else # default tm_set[wdg_id] = fill(1.0, nphases) tm_lb[wdg_id] = fill(0.9, nphases) @@ -801,9 +818,10 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj - ## TODO: Regulator Control - # if haskey(eng_obj,"controls") && !all(data_math["transformer"]["$(transformer_2wa_obj["index"])"]["tm_fix"]) - # end + # Add Regulator Controls (only if flag is true) + if (reg_controls[wdg_id] == true) + data_math["transformer"]["$(transformer_2wa_obj["index"])"]["controls"] = reg_obj[wdg_id] + end # TODO: Center-Tapped Transformers (3 Windings) # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start @@ -852,6 +870,10 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # init configuration - default WYE-WYE configuration = [WYE for _ in 1:nrw] + # RegulatorControls flag + reg_controls = [false for _ in 1:nrw] + reg_obj = [Dict() for _ in 1:nrw] + # init vnom for all windings vnom = zeros(Float64, nrw) @@ -992,6 +1014,20 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data volt_ub = neutralVoltPu + step_tap * (step_volt_increment/100.0) * hstep tm_lb[wdg_endNumber] = fill(volt_lb, nphases) tm_ub[wdg_endNumber] = fill(volt_ub, nphases) + + # Regulator Control + if haskey(rtc_data, "TapChanger.TapChangerControl") && !all(tm_fix[wdg_endNumber]) + reg_controls[wdg_endNumber] = true + reg_obj[wdg_endNumber] = Dict{String,Any}( + "vreg" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetValue"], nphases), + "band" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetDeadband"], nphases), + "ptratio" => fill(rtc_data["TapChanger.ptRatio"], nphases), + "ctprim" => fill(rtc_data["TapChanger.ctRating"], nphases), + "r" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropR"], nphases), + "x" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropX"], nphases) + ) + end + end end @@ -1099,16 +1135,17 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data "index" => length(data_math["transformer"])+1 ) - # TODO: RatioTapChanger + # RatioTapChanger transformer_2wa_obj["tm_lb"] = tm_lb[wdg_id] transformer_2wa_obj["tm_ub"] = tm_ub[wdg_id] transformer_2wa_obj["tm_step"] = tm_step[wdg_id] data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj - ## TODO: Regulator Control - # if haskey(eng_obj,"controls") && !all(data_math["transformer"]["$(transformer_2wa_obj["index"])"]["tm_fix"]) - # end + # Add Regulator Controls (only if flag is true) + if (reg_controls[wdg_id] == true) + data_math["transformer"]["$(transformer_2wa_obj["index"])"]["controls"] = reg_obj[wdg_id] + end # TODO: Center-Tapped Transformers (3 Windings) # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start @@ -1142,6 +1179,10 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # configurations wdgs_confs = Vector{ConnConfig}(undef, nrw) + # RegulatorControls flag + reg_controls = [false for _ in 1:nrw] + reg_obj = [Dict() for _ in 1:nrw] # init + # Init RatioTapChanger data (default) tm_set = Vector{Vector{Float64}}(undef, nrw) tm_lb = Vector{Vector{Float64}}(undef, nrw) @@ -1266,6 +1307,19 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data tm_lb[wdg_endNumber] = fill(volt_lb, nphases) tm_ub[wdg_endNumber] = fill(volt_ub, nphases) + # Regulator Control + if haskey(rtc_data, "TapChanger.TapChangerControl") && !all(tm_fix[wdg_endNumber]) + reg_controls[wdg_endNumber] = true + reg_obj[wdg_endNumber] = Dict{String,Any}( + "vreg" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetValue"], nphases), + "band" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetDeadband"], nphases), + "ptratio" => fill(rtc_data["TapChanger.ptRatio"], nphases), + "ctprim" => fill(rtc_data["TapChanger.ctRating"], nphases), + "r" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropR"], nphases), + "x" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropX"], nphases) + ) + end + else # default tm_set[wdg_endNumber] = fill(1.0, nphases) tm_lb[wdg_endNumber] = fill(0.9, nphases) @@ -1338,21 +1392,17 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data "index" => length(data_math["transformer"])+1 ) - # TODO: RatioTapChanger - for prop in [pass_props] - if haskey(wdg_info[wdg_id], prop) - transformer_2wa_obj[prop] = wdg_info[wdg_id][prop] - end - end + # RatioTapChanger transformer_2wa_obj["tm_lb"] = tm_lb[wdg_id] transformer_2wa_obj["tm_ub"] = tm_ub[wdg_id] transformer_2wa_obj["tm_step"] = tm_step[wdg_id] data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj - ## TODO: Regulator Control - # if haskey(eng_obj,"controls") && !all(data_math["transformer"]["$(transformer_2wa_obj["index"])"]["tm_fix"]) - # end + # Add Regulator Controls (only if flag is true) + if (reg_controls[wdg_id] == true) + data_math["transformer"]["$(transformer_2wa_obj["index"])"]["controls"] = reg_obj[wdg_id] + end # TODO: Center-Tapped Transformers (3 Windings) # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start From dca0510e12243baa4698716e6791dc969e8dc4e9 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 25 Mar 2025 15:14:22 -0600 Subject: [PATCH 46/99] ADD: SwitchInfo support. --- src/data_model/transformations/ravens2math.jl | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 194b58a47..841462067 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1606,7 +1606,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r # Correct (if needed) single-phase DELTA connections if (math_obj["configuration"] == DELTA) && (nphases == 1) math_obj["configuration"] = WYE - @warn "EnergyConsumer (load): $name has DELTA configuration but only 1 connection (phase). DELTA configurations must have at least 2 or 3 connections!" + @warn "EnergyConsumer (load): $name has DELTA configuration but only 1 connection (phase). DELTA configurations must have at least 2 or 3 connections!. EnergyConsumer converted to WYE connection." end # Set status, dispatchable flag, and index @@ -2146,9 +2146,19 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di # TODO: Dispatchable math_obj["dispatchable"] = Int(get(ravens_obj, "dispatchable", YES)) - # TODO: OPF bounds - Do we really need all of these values? - for (f_key, t_key) in [("Switch.ratedCurrent", "current_rating"), ("cm_ub_b", "c_rating_b"), ("cm_ub_c", "c_rating_c"), - ("sm_ub", "thermal_rating"), ("sm_ub_b", "rate_b"), ("sm_ub_c", "rate_c")] + # Current and Power Limits + if haskey(ravens_obj, "PowerSystemResource.AssetDatasheet") + swinfo_name = _extract_name(ravens_obj["PowerSystemResource.AssetDatasheet"]) + swinfo_data = data_ravens["AssetInfo"]["SwitchInfo"][swinfo_name] + math_obj["current_rating"] = fill(get(swinfo_data, "SwitchInfo.ratedCurrent", Inf), nphases) + math_obj["sm_ub"] = math_obj["current_rating"] .* get(swinfo_data, "SwitchInfo.ratedVoltage", Inf) + else + math_obj["current_rating"] = fill(get(ravens_obj, "Switch.ratedCurrent", Inf), nphases) + math_obj["sm_ub"] = math_obj["current_rating"] .* get(ravens_obj, "Switch.ratedVoltage", Inf) + end + + # TODO: not found on CIM - kron reductions + for (f_key, t_key) in [("cm_ub_b", "c_rating_b"), ("cm_ub_c", "c_rating_c"), ("sm_ub_b", "rate_b"), ("sm_ub_c", "rate_c")] math_obj[t_key] = haskey(ravens_obj, f_key) ? fill(ravens_obj[f_key], nphases) : fill(Inf, nphases) end @@ -2165,6 +2175,7 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di )) end + end From 3ae8b5d7cac3e7f29eb3faad2b71bf14c35cfbf3 Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 26 Mar 2025 10:34:53 -0600 Subject: [PATCH 47/99] FIX: minor changes to assigning terminals in edge elements. --- src/data_model/transformations/ravens2math.jl | 48 +++++++------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 841462067..09ef06c81 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -312,7 +312,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: nphases = nconds end - # TODO: Revise if the elseif is needed! + # Assign terminals and vmin/vmax for bus in [math_obj["f_bus"], math_obj["t_bus"]] if !(haskey(data_math["bus"][string(bus)], "terminals")) data_math["bus"][string(bus)]["terminals"] = bus_terminals @@ -641,8 +641,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # nphases nphases = length(connections[wdg_endNumber]) - # add terminals and voltage limits info. if missing - # TODO: Revise if the elseif is needed! + # Add terminals and voltage limits info. if missing node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) bus = data_math["bus_lookup"][node] if !(haskey(data_math["bus"][string(bus)], "terminals")) @@ -1061,7 +1060,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data for i in 1:length(nodes) n = nodes[i] bus = data_math["bus_lookup"][n] - # TODO: Revise if the elseif is needed! if !(haskey(data_math["bus"][string(bus)], "terminals")) data_math["bus"][string(bus)]["terminals"] = connections[i] data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) @@ -1208,7 +1206,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data @error("PhaseCode not supported yet!") end - # TODO: Revise if the elseif is needed! + # Add vmin/vmax/terminals info. if missing nphases = length(wdg_connections) if !(haskey(data_math["bus"][string(bus)], "terminals")) data_math["bus"][string(bus)]["terminals"] = wdg_connections @@ -2107,34 +2105,22 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di math_obj["f_bus"] = data_math["bus_lookup"][f_node] math_obj["t_bus"] = data_math["bus_lookup"][t_node] - # Add vmin/vmax/terminals infor to fbus and tbus if missing - # TODO: Revise if the elseif is needed! - if !(haskey(data_math["bus"][string(math_obj["f_bus"])], "terminals")) - data_math["bus"][string(math_obj["f_bus"])]["terminals"] = f_conns - data_math["bus"][string(math_obj["f_bus"])]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(math_obj["f_bus"])]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(math_obj["f_bus"])]["grounded"] = zeros(Bool, nphases) - elseif (length(data_math["bus"][string(math_obj["f_bus"])]["terminals"]) < length(f_conns)) - data_math["bus"][string(math_obj["f_bus"])]["terminals"] = f_conns - data_math["bus"][string(math_obj["f_bus"])]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(math_obj["f_bus"])]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(math_obj["f_bus"])]["grounded"] = zeros(Bool, nphases) - end - - # TODO: Revise if the elseif is needed! - if !(haskey(data_math["bus"][string(math_obj["t_bus"])], "terminals")) - data_math["bus"][string(math_obj["t_bus"])]["terminals"] = t_conns - data_math["bus"][string(math_obj["t_bus"])]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(math_obj["t_bus"])]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(math_obj["t_bus"])]["grounded"] = zeros(Bool, nphases) - elseif (length(data_math["bus"][string(math_obj["t_bus"])]["terminals"]) < length(t_conns)) - data_math["bus"][string(math_obj["t_bus"])]["terminals"] = t_conns - data_math["bus"][string(math_obj["t_bus"])]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(math_obj["t_bus"])]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(math_obj["t_bus"])]["grounded"] = zeros(Bool, nphases) + # Add vmin/vmax/terminals info to fbus and tbus if missing + for bus in [math_obj["f_bus"], math_obj["t_bus"]] + if !(haskey(data_math["bus"][string(bus)], "terminals")) + data_math["bus"][string(bus)]["terminals"] = f_conns + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + elseif (length(data_math["bus"][string(bus)]["terminals"]) < length(f_conns)) + data_math["bus"][string(bus)]["terminals"] = f_conns + data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) + data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) + data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + end end - # TODO: Status + # Status math_obj["status"] = get(ravens_obj, "Equipment.inService", true) math_obj["status"] = status = math_obj["status"] == true ? 1 : 0 From df8ef48c5067d9f54712f0af4aad60fb8d809dda Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 26 Mar 2025 13:24:56 -0600 Subject: [PATCH 48/99] FIX: bug on constraint_mc_transformer_power_dy for LPUBFDiagModel. --- src/form/bf.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/form/bf.jl b/src/form/bf.jl index 7a1f11a2f..828b5d7cc 100644 --- a/src/form/bf.jl +++ b/src/form/bf.jl @@ -109,10 +109,10 @@ function constraint_mc_transformer_power_dy(pm::LPUBFDiagModel, nw::Int, trans_i tm = [tm_fixed[idx] ? tm_set[idx] : var(pm, nw, :tap, trans_id)[fc] for (idx,(fc,tc)) in enumerate(zip(f_connections,t_connections))] nph = length(tm_set) - p_fr = [var(pm, nw, :pt, f_idx)[c] for c in f_connections] - p_to = [var(pm, nw, :pt, t_idx)[c] for c in t_connections] - q_fr = [var(pm, nw, :qt, f_idx)[c] for c in f_connections] - q_to = [var(pm, nw, :qt, t_idx)[c] for c in t_connections] + p_fr = var(pm, nw, :pt, f_idx) + p_to = var(pm, nw, :pt, t_idx) + q_fr = var(pm, nw, :qt, f_idx) + q_to = var(pm, nw, :qt, t_idx) w_fr = var(pm, nw, :w)[f_bus] w_to = var(pm, nw, :w)[t_bus] From 800368df94ddf1bac263d84ec66cb9ed8e0e930a Mon Sep 17 00:00:00 2001 From: Juan Ospina Date: Fri, 28 Mar 2025 14:25:07 -0600 Subject: [PATCH 49/99] Revise ravens parser (#5) * REF: code to reduce ifs in checking terminals vmin vmax definitions. * FIX: bug in ravens switch parser. * REF: small changes in ravens2math and clean comments --- src/data_model/transformations/ravens2math.jl | 189 ++++++------------ src/prob/common.jl | 186 ----------------- 2 files changed, 61 insertions(+), 314 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 09ef06c81..239477e22 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -53,7 +53,6 @@ function transform_data_model_ravens( global_keys=global_keys, ) - # TODO: Correct network data transforms a lot of the values of lines/branches (other values maybe too) correct_network_data && correct_network_data!(data_math; make_pu=make_pu, make_pu_extensions=make_pu_extensions) return data_math @@ -183,12 +182,11 @@ function _map_ravens2math_nw!(data_math::Dict{String,<:Any}, data_ravens::Dict{S _init_base_components!(data_math) - ## TODO - # for property in get(ravens2math_passthrough, "root", String[]) - # if haskey(data_ravens, property) - # data_math[property] = deepcopy(data_ravens[property]) - # end - # end + for property in get(ravens2math_passthrough, "root", String[]) + if haskey(data_ravens, property) + data_math[property] = deepcopy(data_ravens[property]) + end + end for type in pmd_ravens_asset_types getfield(PowerModelsDistribution, Symbol("_map_ravens2math_$(type)!"))(data_math, data_ravens; pass_props=get(ravens2math_passthrough, type, String[])) @@ -211,12 +209,11 @@ function _map_ravens2math_nw!(data_math::Dict{String,<:Any}, data_ravens::Dict{S _init_base_components!(data_math[string(nw)]) - ## TODO - # for property in get(ravens2math_passthrough, "root", String[]) - # if haskey(data_ravens, property) - # data_math[property] = deepcopy(data_ravens[property]) - # end - # end + for property in get(ravens2math_passthrough, "root", String[]) + if haskey(data_ravens, property) + data_math[property] = deepcopy(data_ravens[property]) + end + end for type in pmd_ravens_asset_types getfield(PowerModelsDistribution, Symbol("_map_ravens2math_$(type)!"))(data_math[string(nw)], data_ravens; pass_props=get(ravens2math_passthrough, type, String[]), nw=nw) @@ -312,18 +309,14 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: nphases = nconds end - # Assign terminals and vmin/vmax + # Add vmin/vmax/terminals info to fbus and tbus if missing for bus in [math_obj["f_bus"], math_obj["t_bus"]] - if !(haskey(data_math["bus"][string(bus)], "terminals")) - data_math["bus"][string(bus)]["terminals"] = bus_terminals - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) - elseif (length(data_math["bus"][string(bus)]["terminals"]) < length(bus_terminals)) - data_math["bus"][string(bus)]["terminals"] = bus_terminals - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + bus_data = data_math["bus"][string(bus)] + if !(haskey(bus_data, "terminals")) || (length(bus_data["terminals"]) < length(bus_terminals)) + bus_data["terminals"] = bus_terminals + bus_data["vmin"] = fill(0.0, nphases) + bus_data["vmax"] = fill(Inf, nphases) + bus_data["grounded"] = zeros(Bool, nphases) end end @@ -357,7 +350,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: x_coords = Vector{Float64}(undef, num_of_wires) y_coords = Vector{Float64}(undef, num_of_wires) - Threads.@threads for i in 1:1:num_of_wires + for i in 1:1:num_of_wires x_coords[i] = get(wire_positions[i], "WirePosition.xCoord", 0.0) y_coords[i] = get(wire_positions[i], "WirePosition.yCoord", 0.0) end @@ -452,32 +445,6 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: # rho (default) - ρ = earth resistivity = 100 Ω-m rho = 100 - # @info "*********************************" - # @info "NAME: $(name)" - # @info "XCOORDS: $(x_coords)" - # @info "YCOORDS: $(y_coords)" - # @info "W: $(ω)" - # @info "GMR: $(gmr)" - # @info "RADIUS: $(radius)" - # @info "NCONDS: $(nconds)" - # @info "EARTH: $(earth_model)" - # @info "RAC: $(rac)" - # @info "WO: $(ω₀)" - # @info "RDC: $(rdc)" - # @info "RHO: $(rho)" - # @info "NPHASES: $(nphases)" - # @info "RSTRAND: $(rstrand)" - # @info "NSTRAND: $(nstrand)" - # @info "DCABLE: $(dcable)" - # @info "DTRAND: $(dstrand)" - # @info "GMRSTRAND: $(gmrstrand)" - # @info "EPSR: $(epsr)" - # @info "DINS: $(dins)" - # @info "TINS: $(tins)" - # @info "DIASHIELD: $(diashield)" - # @info "TAPELAYER: $(tapelayer)" - # @info "TAPELAP: $(tapelap)" - # Calculate line constants z, y = calculate_line_constants( x_coords, @@ -485,13 +452,13 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: ω, gmr, radius, - nconds, # TODO: check if nwires or nconds + nconds, earth_model, rac, ω₀, rdc, rho, - nphases, # TODO: check if nconds or nphases + nphases, rstrand, nstrand, dcable, @@ -505,7 +472,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: tapelap ) - # TODO: Kron reduction + # Kron reduction if reduce z, y = _kron(z, y, nphases) end @@ -527,15 +494,6 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj["g_fr"] = _admittance_conversion_ravens(ravens_obj, g_fr) math_obj["g_to"] = _admittance_conversion_ravens(ravens_obj, g_to) - # @info "$( math_obj["br_r"])" - # @info "$( math_obj["br_x"])" - # @info "$( math_obj["b_fr"])" - # @info "$( math_obj["b_to"])" - # @info "$( math_obj["g_fr"])" - # @info "$( math_obj["g_to"])" - # @info "*********************************" - - end math_obj["angmin"] = get(ravens_obj, "vad_lb", fill(-60.0, nphases)) @@ -644,16 +602,12 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Add terminals and voltage limits info. if missing node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) bus = data_math["bus_lookup"][node] - if !(haskey(data_math["bus"][string(bus)], "terminals")) - data_math["bus"][string(bus)]["terminals"] = connections[wdg_endNumber] - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) - elseif (length(data_math["bus"][string(bus)]["terminals"]) < length(connections[wdg_endNumber])) - data_math["bus"][string(bus)]["terminals"] = connections[wdg_endNumber] - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + bus_data = data_math["bus"][string(bus)] + if !(haskey(bus_data, "terminals")) || (length(bus_data["terminals"]) < length(connections[wdg_endNumber])) + bus_data["terminals"] = connections[wdg_endNumber] + bus_data["vmin"] = fill(0.0, nphases) + bus_data["vmax"] = fill(Inf, nphases) + bus_data["grounded"] = zeros(Bool, nphases) end # wdgs configurations @@ -1055,21 +1009,16 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data end - # Add information about bus/node if missing for i in 1:length(nodes) - n = nodes[i] - bus = data_math["bus_lookup"][n] - if !(haskey(data_math["bus"][string(bus)], "terminals")) - data_math["bus"][string(bus)]["terminals"] = connections[i] - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) - elseif (length(data_math["bus"][string(bus)]["terminals"]) < length(connections[i])) - data_math["bus"][string(bus)]["terminals"] = connections[i] - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + node = nodes[i] + bus = data_math["bus_lookup"][node] + bus_data = data_math["bus"][string(bus)] + if !(haskey(bus_data, "terminals")) || (length(bus_data["terminals"]) < length(connections[i])) + bus_data["terminals"] = connections[i] + bus_data["vmin"] = fill(0.0, nphases) + bus_data["vmax"] = fill(Inf, nphases) + bus_data["grounded"] = zeros(Bool, nphases) end # Add vnom info to bus data_math["settings"]["vbases_network"][string(bus)] = deepcopy(vnom[i]/voltage_scale_factor) @@ -1085,7 +1034,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data y_sh = g_sh + im*b_sh z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) - # TODO: Polarity + # init Polarity polarity = fill(1, nrw) # Status @@ -1194,10 +1143,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data wdg_phasecode = wdg_terminals["Terminal.phases"] wdg_endNumber = wdgs_data[wdg_id]["TransformerEnd.endNumber"] - # from-and-to-nodes for wdg - node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) - bus = data_math["bus_lookup"][node] - # connections (based on _phasecode_map) if haskey(_phasecode_map, wdg_phasecode) wdg_connections = _phasecode_map[wdg_phasecode] @@ -1206,18 +1151,18 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data @error("PhaseCode not supported yet!") end - # Add vmin/vmax/terminals info. if missing + # from-and-to-nodes for wdg nphases = length(wdg_connections) - if !(haskey(data_math["bus"][string(bus)], "terminals")) - data_math["bus"][string(bus)]["terminals"] = wdg_connections - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) - elseif (length(data_math["bus"][string(bus)]["terminals"]) < length(wdg_connections)) - data_math["bus"][string(bus)]["terminals"] = wdg_connections - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) + bus = data_math["bus_lookup"][node] + bus_data = data_math["bus"][string(bus)] + + # Add vmin/vmax/terminals info. if missing + if !(haskey(bus_data, "terminals")) || (length(bus_data["terminals"]) < length(wdg_connections)) + bus_data["terminals"] = wdg_connections + bus_data["vmin"] = fill(0.0, nphases) + bus_data["vmax"] = fill(Inf, nphases) + bus_data["grounded"] = zeros(Bool, nphases) end # transformer tank end info. @@ -1335,7 +1280,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # dimensions dims = length(tm_set[1]) - # TODO: polarity + # init polarity polarity = fill(1, nrw) # Status @@ -1579,7 +1524,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end end - # Multipliers instead of actual values - TODO: add support for EnergyConsumerPhase data + # Multipliers instead of actual values if !haskey(schdl, "BasicIntervalSchedule.value1Unit") math_obj["pd"] = get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 1.0) .* active_power ./ power_scale_factor math_obj["qd"] = get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 1.0) .* reactive_power ./ power_scale_factor @@ -1796,12 +1741,7 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ math_obj = _init_math_obj_ravens("rotating_machine", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) # Connections/phases obtained from Terminals - if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") - phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] - connections = _phasecode_map[phasecode] - else - connections = [1, 2, 3] # default - end + connections = _phasecode_map[get(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases", "PhaseCode.ABC")] nconductors = length(connections) math_obj["connections"] = connections @@ -1906,8 +1846,9 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data math_obj = _init_math_obj_ravens("photovoltaic_unit", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) - # TODO: connections/phases do not exist in the RAVENS-CIM (Need to be added) - should come from terminals - connections = [1, 2, 3] # TODO + # Connections/phases + connections = _phasecode_map[get(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases", "PhaseCode.ABC")] + nconductors = length(connections) math_obj["connections"] = connections @@ -2107,16 +2048,12 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di # Add vmin/vmax/terminals info to fbus and tbus if missing for bus in [math_obj["f_bus"], math_obj["t_bus"]] - if !(haskey(data_math["bus"][string(bus)], "terminals")) - data_math["bus"][string(bus)]["terminals"] = f_conns - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) - elseif (length(data_math["bus"][string(bus)]["terminals"]) < length(f_conns)) - data_math["bus"][string(bus)]["terminals"] = f_conns - data_math["bus"][string(bus)]["vmin"] = fill(0.0, nphases) - data_math["bus"][string(bus)]["vmax"] = fill(Inf, nphases) - data_math["bus"][string(bus)]["grounded"] = zeros(Bool, nphases) + bus_data = data_math["bus"][string(bus)] + if !(haskey(bus_data, "terminals")) || (length(bus_data["terminals"]) < length(f_conns)) + bus_data["terminals"] = f_conns + bus_data["vmin"] = fill(0.0, nphases) + bus_data["vmax"] = fill(Inf, nphases) + bus_data["grounded"] = zeros(Bool, nphases) end end @@ -2187,12 +2124,8 @@ function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data math_obj["status"] = status == true ? 1 : 0 # Connections/phases obtained from Terminals - if haskey(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases") - phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] - connections = _phasecode_map[phasecode] - else - connections = [1, 2, 3] # default - end + connections = _phasecode_map[get(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases", "PhaseCode.ABC")] + math_obj["connections"] = connections terminals = connections diff --git a/src/prob/common.jl b/src/prob/common.jl index 7ed75d4d5..36ffbc65b 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -116,82 +116,6 @@ function instantiate_mc_model( ) end - # for (i,j) in data["transformer"] - - # # @info "Name: $(i)" - # # @info "Data: $(j)" - - # # # BRANCHES - # # @info "$(j["name"])" - # # @info "$(j["f_bus"])" - # # @info "$(j["f_connections"])" - # # @info "$(j["t_bus"])" - # # @info "$(j["t_connections"])" - # # @info "$(j["br_status"])" - - # # # BUS - # # @info "$(j["name"])" - # # @info "$(j["grounded"])" - # # @info "$(j["vmin"])" - # # @info "$(j["vmax"])" - # # @info "$(j["bus_i"])" - # # @info "$(j["terminals"])" - # # @info "$(j["index"])" - # # @info "$(j["bus_type"])" - - # # # GENS - # # @info "$(j["name"])" - # # @info "$(j["model"])" - # # @info "$(j["connections"])" - # # @info "$(j["configuration"])" - # # @info "$(j["gen_bus"])" - # # @info "$(j["gen_status"])" - # # @info "$(j["control_mode"])" - # # @info "$(j["pmin"])" - # # @info "$(j["pmax"])" - # # @info "$(j["qmin"])" - # # @info "$(j["qmax"])" - - # # # SWITCHES - # # @info "$(j["name"])" - # # @info "$(j["f_bus"])" - # # @info "$(j["f_connections"])" - # # @info "$(j["t_bus"])" - # # @info "$(j["t_connections"])" - # # @info "$(j["vbase"])" - # # @info "$(j["status"])" - - # # # TRANSFORMER - # # @info "$(j["name"])" - # # @info "$(j["f_bus"])" - # # @info "$(j["f_connections"])" - # # @info "$(j["t_bus"])" - # # @info "$(j["t_connections"])" - # # @info "$(j["polarity"])" - # # @info "$(j["status"])" - # # @info "$(j["index"])" - # # @info "$(j["configuration"])" - # # @info "$(j["sm_ub"])" - # # @info "$(j["cm_ub"])" - # # @info "$(j["f_vbase"])" - # # @info "$(j["t_vbase"])" - - # # # LOAD - # # @info "$(j["name"])" - # # @info "$(j["model"])" - # # @info "$(j["pd"])" - # # @info "$(j["qd"])" - # # @info "$(j["vbase"])" - # # @info "$(j["vnom_kv"])" - # # @info "$(j["load_bus"])" - # # @info "$(j["index"])" - # # @info "$(j["configuration"])" - # # @info "$(j["connections"])" - - # end - - # DEFINIDOEN_instantiate_mc_model - return _IM.instantiate_model( data, model_type, @@ -230,116 +154,6 @@ function instantiate_mc_model_ravens( make_pu_extensions=make_pu_extensions, ) - - - # for (i,j) in data["transformer"] - - - # # @info "Name: $(i)" - # # @info "Data: $(j)" - - # # # BRANCHES - # # @info "$(j["name"])" - # # @info "$(j["f_bus"])" - # # @info "$(j["f_connections"])" - # # @info "$(j["t_bus"])" - # # @info "$(j["t_connections"])" - # # @info "$(j["br_status"])" - - # # # BUS - # # @info "$(j["name"])" - # # @info "$(j["grounded"])" - # # @info "$(j["vmin"])" - # # @info "$(j["vmax"])" - # # @info "$(j["bus_i"])" - # # @info "$(j["terminals"])" - # # @info "$(j["index"])" - # # @info "$(j["bus_type"])" - - # # # GENS - # # @info "$(j["name"])" - # # @info "$(j["model"])" - # # @info "$(j["connections"])" - # # @info "$(j["configuration"])" - # # @info "$(j["gen_bus"])" - # # @info "$(j["gen_status"])" - # # @info "$(j["control_mode"])" - # # @info "$(j["pmin"])" - # # @info "$(j["pmax"])" - # # @info "$(j["qmin"])" - # # @info "$(j["qmax"])" - - # # # SWITCHES - # # @info "$(j["name"])" - # # @info "$(j["f_bus"])" - # # @info "$(j["f_connections"])" - # # @info "$(j["t_bus"])" - # # @info "$(j["t_connections"])" - # # @info "$(j["vbase"])" - # # @info "$(j["status"])" - - # # # TRANSFORMER - # # @info "$(j["name"])" - # # # @info "$(j["f_bus"])" - # # @info "$(j["f_connections"])" - # # # @info "$(j["t_bus"])" - # # @info "$(j["t_connections"])" - # # @info "$(j["polarity"])" - # # # @info "$(j["status"])" - # # # @info "$(j["index"])" - # # # @info "$(j["configuration"])" - # # @info "$(j["sm_ub"])" - # # # @info "$(j["cm_ub"])" - # # # @info "$(j["f_vbase"])" - # # # @info "$(j["t_vbase"])" - # # @info "++++++++++++++++++++++++++++++" - - - # # if (j["index"] == 479) - # # @info "$(j["name"])" - # # @info "$(j)" - # # @info "++++++++++++++++++++++++++++++" - - # # end - - - # # if (j["f_connections"] != j["t_connections"]) - - # # @info "$(j["name"])" - # # # @info "$(j["f_bus"])" - # # @info "$(j["f_connections"])" - # # # @info "$(j["t_bus"])" - # # @info "$(j["t_connections"])" - # # @info "$(j["polarity"])" - # # # @info "$(j["status"])" - # # # @info "$(j["index"])" - # # # @info "$(j["configuration"])" - # # @info "$(j["sm_ub"])" - # # # @info "$(j["cm_ub"])" - # # # @info "$(j["f_vbase"])" - # # # @info "$(j["t_vbase"])" - # # @info "++++++++++++++++++++++++++++++" - - # # end - - # # # LOAD - # # @info "$(j["name"])" - # # @info "$(j["model"])" - # # @info "$(j["pd"])" - # # @info "$(j["qd"])" - # # @info "$(j["vbase"])" - # # @info "$(j["vnom_kv"])" - # # @info "$(j["load_bus"])" - # # @info "$(j["index"])" - # # @info "$(j["configuration"])" - # # @info "$(j["connections"])" - - - # end - - - # DEFINIDOEN_instantiate_mc_model_ravens - return _IM.instantiate_model( data, model_type, From 2b388d6d0d127ee60985a015cd21b1adb9254bd1 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 31 Mar 2025 16:01:53 -0600 Subject: [PATCH 50/99] FIX: sign convention issues in rotatingmachines. --- src/data_model/transformations/ravens2math.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 239477e22..a731d1add 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1803,8 +1803,8 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ end # Set pg and qg - math_obj["pg"] = (get(ravens_obj, "RotatingMachine.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) - math_obj["qg"] = (get(ravens_obj, "RotatingMachine.q", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["pg"] = (get(ravens_obj, "RotatingMachine.p", 0.0) * -ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["qg"] = (get(ravens_obj, "RotatingMachine.q", 0.0) * -ones(nconductors) ./ nconductors)./(power_scale_factor) # TODO: add a polynomial parameters to be added to gen cost _add_gen_cost_model!(math_obj, ravens_obj) From 5bfa64dcf0656b73362c90fc8a3fb4353dccbf84 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 1 Apr 2025 10:23:55 -0600 Subject: [PATCH 51/99] FIX: gens rated information. --- src/data_model/transformations/ravens2math.jl | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index a731d1add..04a03a3a7 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1760,7 +1760,7 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ math_obj["pmax"] = ((get(ravens_obj["RotatingMachine.GeneratingUnit"], "GeneratingUnit.maxOperatingP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) else math_obj["pmin"] = (zeros(nconductors) ./ nconductors)./(power_scale_factor) - math_obj["pmax"] = ((get(ravens_obj, "RotatingMachine.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + math_obj["pmax"] = ((get(ravens_obj, "RotatingMachine.ratedS", Inf) * get(ravens_obj, "RotatingMachine.ratedPowerFactor", 1.0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) end # Set bus type @@ -1790,6 +1790,11 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ math_obj["qmin"] = ((ravens_obj["RotatingMachine.minQ"] * ones(nconductors)) ./ nconductors)./(power_scale_factor) elseif haskey(ravens_obj, "SynchronousMachine.minQ") math_obj["qmin"] = ((ravens_obj["SynchronousMachine.minQ"] * ones(nconductors)) ./ nconductors)./(power_scale_factor) + elseif haskey(ravens_obj, "RotatingMachine.ratedPowerFactor") + Srated = get(ravens_obj, "RotatingMachine.ratedS", Inf) + PFrated = get(ravens_obj, "RotatingMachine.ratedPowerFactor", 1.0) + Prated = Srated*PFrated + math_obj["qmax"] = -((sqrt(Srated^2 - Prated^2) * ones(nconductors)) ./ nconductors) ./ (power_scale_factor) else math_obj["qmin"] = fill(-Inf, nconductors) end @@ -1798,6 +1803,11 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ math_obj["qmax"] = ((ravens_obj["RotatingMachine.maxQ"] * ones(nconductors)) ./ nconductors)./(power_scale_factor) elseif haskey(ravens_obj, "SynchronousMachine.maxQ") math_obj["qmax"] = ((ravens_obj["SynchronousMachine.maxQ"] * ones(nconductors)) ./ nconductors)./(power_scale_factor) + elseif haskey(ravens_obj, "RotatingMachine.ratedPowerFactor") + Srated = get(ravens_obj, "RotatingMachine.ratedS", Inf) + PFrated = get(ravens_obj, "RotatingMachine.ratedPowerFactor", 1.0) + Prated = Srated*PFrated + math_obj["qmax"] = ((sqrt(Srated^2 - Prated^2) * ones(nconductors)) ./ nconductors) ./ (power_scale_factor) else math_obj["qmax"] = fill(Inf, nconductors) end From 8564b531deaa7979345df14d29e3ff480d9c0d59 Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 2 Apr 2025 12:44:08 -0600 Subject: [PATCH 52/99] FIX: small typo in energyconsumer mn ravens definition. --- src/data_model/transformations/ravens2math.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 04a03a3a7..64a6be52c 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1483,7 +1483,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end else active_power = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / (power_scale_factor*nphases), nphases) - reactive_power = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / (power_scale_factor*nphases), nphases) + reactive_power = fill(get(ravens_obj, "EnergyConsumer.q", 0.0) / (power_scale_factor*nphases), nphases) end schdl_name = _extract_name(ravens_obj["EnergyConsumer.LoadProfile"]) From 13a232549d5c4876a4f5bb3ed39b3007f0d411b5 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 3 Apr 2025 13:01:52 -0600 Subject: [PATCH 53/99] FIX: typo for qmin in gens. --- src/data_model/transformations/ravens2math.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 64a6be52c..fc77d58cd 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1794,7 +1794,7 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ Srated = get(ravens_obj, "RotatingMachine.ratedS", Inf) PFrated = get(ravens_obj, "RotatingMachine.ratedPowerFactor", 1.0) Prated = Srated*PFrated - math_obj["qmax"] = -((sqrt(Srated^2 - Prated^2) * ones(nconductors)) ./ nconductors) ./ (power_scale_factor) + math_obj["qmin"] = -((sqrt(Srated^2 - Prated^2) * ones(nconductors)) ./ nconductors) ./ (power_scale_factor) else math_obj["qmin"] = fill(-Inf, nconductors) end From b6f5fe83c5c47629ae3e0058ea1bb35c462819c3 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 8 Apr 2025 12:53:51 -0600 Subject: [PATCH 54/99] ADD: support for tape shield cables and fix issue to handle three phase TransformerTanks with all phases in one tank by default. --- src/data_model/transformations/ravens2math.jl | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index fc77d58cd..daf8e2806 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -393,7 +393,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: @assert radius[i] != NaN "WireInfo radius not found! using NaN. Revise data." # Note: gets rewritten as missing if not needed - dcable[i] = radius[i] * 2.0 + dcable[i] = get(wireinfo_data, "ConcentricNeutralCableInfo.diameterOverNeutral", radius[i] * 2.0) gmr[i] = get(wireinfo_data, "WireInfo.gmr", radius[i] * 0.778) @@ -405,6 +405,10 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: rdc[i] = get(wireinfo_data, "WireInfo.rDC20", NaN) @assert rdc[i] != NaN "WireInfo rDC20 resistance is not found! using NaN. Revise input data." rac[i] = rdc[i] * 1.02 + elseif wireinfo_data["Ravens.cimObjectType"] == "TapeShieldCableInfo" + rdc[i] = get(wireinfo_data, "WireInfo.rDC20", NaN) + @assert rdc[i] != NaN "WireInfo rDC20 resistance is not found! using NaN. Revise input data." + rac[i] = rdc[i] * 1.02 else @error("Cable type not supported. Resistances (AC or DC) not found!") end @@ -419,10 +423,10 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: dins[i] = get(wireinfo_data, "CableInfo.diameterOverJacket", NaN) tins[i] = get(wireinfo_data, "WireInfo.insulationThickness", NaN) - # TODO: tape shielded cables information - diashield[i] = NaN - tapelayer[i] = NaN - tapelap[i] = NaN + # Tape shielded cables information + diashield[i] = get(wireinfo_data, "CableInfo.diameterOverJacket", NaN) # diameter over tape shield + tapelayer[i] = get(wireinfo_data, "TapeShieldCableInfo.tapeThickness", NaN) # tape shield thickness + tapelap[i] = get(wireinfo_data, "TapeShieldCableInfo.tapeLap", NaN) #tape lap (default 20.0) end @@ -435,8 +439,8 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: epsr = findfirst(isnan, dins) !== nothing ? missing : ones(nconds).*2.3 # use dins as signal for epsr to be missing dins = findfirst(isnan, dins) !== nothing ? missing : dins tins = findfirst(isnan, tins) !== nothing ? missing : tins - diashield = findfirst(isnan, diashield) !== nothing ? missing : diashield - tapelayer = findfirst(isnan, tapelayer) !== nothing ? missing : tapelayer + diashield = findfirst(isnan, tapelayer) !== nothing ? missing : diashield + tapelayer = findfirst(isnan, tapelayer) !== nothing ? missing : tapelayer # use tapelayer as signal for diashield to be missing tapelap = findfirst(isnan, tapelap) !== nothing ? missing : tapelap # TODO: earth model (using default) @@ -800,8 +804,12 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # TODO: IMPORTANT ASSUMPTIONS # 1) assume there is at least 1 tank and that all tanks have the same number of windings (i.e., TransformerTankEnds) - # 2) assume the number of phases is equal to the number of tanks - nphases = length(tanks) # assume nphases == ntanks + # 2) assume the number of phases is equal to the number of tanks - DEPRECATED + # 3) assumes number of phases are indicated correctly in terminal # 1 + phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] # terminal 1 phasecode + nphases = length(_phasecode_map[phasecode]) + # nphases = length(tanks) # assume nphases == ntanks + nrw = length(tanks[1]["TransformerTank.TransformerTankEnd"]) # init connections vector for combined transformer windings From ab492ce0da7de87ab8e88e2797ddd403c34dff63 Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 9 Apr 2025 15:39:21 -0600 Subject: [PATCH 55/99] FIX: bugs in transformer impedance and conductance calculations, kron reduction in lines, and delta connected loads vnom kv. --- src/data_model/transformations/eng2math.jl | 102 +++++++++--------- src/data_model/transformations/ravens2math.jl | 32 ++++-- 2 files changed, 74 insertions(+), 60 deletions(-) diff --git a/src/data_model/transformations/eng2math.jl b/src/data_model/transformations/eng2math.jl index 60e75bf2e..e8c799f0a 100644 --- a/src/data_model/transformations/eng2math.jl +++ b/src/data_model/transformations/eng2math.jl @@ -579,57 +579,57 @@ function _map_eng2math_switch!(data_math::Dict{String,<:Any}, data_eng::Dict{Str _apply_linecode!(eng_obj, data_eng) end - if !(all(isapprox.(get(eng_obj, "rs", zeros(1, 1)), 0)) && all(isapprox.(get(eng_obj, "xs", zeros(1, 1)), 0))) - # build virtual bus - - f_bus = deepcopy(data_math["bus"]["$(math_obj["f_bus"])"]) - t_bus = deepcopy(data_math["bus"]["$(math_obj["t_bus"])"]) - - N = length(eng_obj["t_connections"]) - bus_obj = Dict{String,Any}( - "name" => "_virtual_bus.switch.$name", - "bus_i" => length(data_math["bus"])+1, - "bus_type" => eng_obj["status"] == DISABLED ? 4 : 1, - "terminals" => eng_obj["t_connections"], # connected to the switch on the to-side - "grounded" => fill(false, N), # connected to the switch on the to-side - "vmin" => fill(0.0, N), - "vmax" => fill(Inf, N), - "vm_pair_lb" => Tuple{Any,Any,Real}[], - "vm_pair_ub" => Tuple{Any,Any,Real}[], - "source_id" => "switch.$name", - "index" => length(data_math["bus"])+1, - ) - - math_obj["t_bus"] = bus_obj["bus_i"] - data_math["bus"]["$(bus_obj["index"])"] = bus_obj - - branch_obj = _init_math_obj("line", name, eng_obj, length(data_math["branch"])+1) - - _branch_obj = Dict{String,Any}( - "name" => "_virtual_branch.switch.$name", - "source_id" => "switch.$name", - "f_bus" => bus_obj["bus_i"], - "t_bus" => data_math["bus_lookup"][eng_obj["t_bus"]], - "f_connections" => eng_obj["t_connections"], # the virtual branch connects to the switch on the to-side - "t_connections" => eng_obj["t_connections"], # should be identical to the switch's to-side connections - "br_r" => _impedance_conversion(data_eng, eng_obj, "rs"), - "br_x" => _impedance_conversion(data_eng, eng_obj, "xs"), - "g_fr" => _admittance_conversion(data_eng, eng_obj, "g_fr"), - "g_to" => _admittance_conversion(data_eng, eng_obj, "g_to"), - "b_fr" => _admittance_conversion(data_eng, eng_obj, "b_fr"), - "b_to" => _admittance_conversion(data_eng, eng_obj, "b_to"), - "angmin" => fill(-10.0, nphases), - "angmax" => fill( 10.0, nphases), - "c_rating_a" => fill(Inf, nphases), - "br_status" => eng_obj["status"] == DISABLED ? 0 : 1, - ) - - merge!(branch_obj, _branch_obj) - - data_math["branch"]["$(branch_obj["index"])"] = branch_obj - - map_to = [map_to, "bus.$(bus_obj["index"])", "branch.$(branch_obj["index"])"] - end + # if !(all(isapprox.(get(eng_obj, "rs", zeros(1, 1)), 0)) && all(isapprox.(get(eng_obj, "xs", zeros(1, 1)), 0))) + # # build virtual bus + + # f_bus = deepcopy(data_math["bus"]["$(math_obj["f_bus"])"]) + # t_bus = deepcopy(data_math["bus"]["$(math_obj["t_bus"])"]) + + # N = length(eng_obj["t_connections"]) + # bus_obj = Dict{String,Any}( + # "name" => "_virtual_bus.switch.$name", + # "bus_i" => length(data_math["bus"])+1, + # "bus_type" => eng_obj["status"] == DISABLED ? 4 : 1, + # "terminals" => eng_obj["t_connections"], # connected to the switch on the to-side + # "grounded" => fill(false, N), # connected to the switch on the to-side + # "vmin" => fill(0.0, N), + # "vmax" => fill(Inf, N), + # "vm_pair_lb" => Tuple{Any,Any,Real}[], + # "vm_pair_ub" => Tuple{Any,Any,Real}[], + # "source_id" => "switch.$name", + # "index" => length(data_math["bus"])+1, + # ) + + # math_obj["t_bus"] = bus_obj["bus_i"] + # data_math["bus"]["$(bus_obj["index"])"] = bus_obj + + # branch_obj = _init_math_obj("line", name, eng_obj, length(data_math["branch"])+1) + + # _branch_obj = Dict{String,Any}( + # "name" => "_virtual_branch.switch.$name", + # "source_id" => "switch.$name", + # "f_bus" => bus_obj["bus_i"], + # "t_bus" => data_math["bus_lookup"][eng_obj["t_bus"]], + # "f_connections" => eng_obj["t_connections"], # the virtual branch connects to the switch on the to-side + # "t_connections" => eng_obj["t_connections"], # should be identical to the switch's to-side connections + # "br_r" => _impedance_conversion(data_eng, eng_obj, "rs"), + # "br_x" => _impedance_conversion(data_eng, eng_obj, "xs"), + # "g_fr" => _admittance_conversion(data_eng, eng_obj, "g_fr"), + # "g_to" => _admittance_conversion(data_eng, eng_obj, "g_to"), + # "b_fr" => _admittance_conversion(data_eng, eng_obj, "b_fr"), + # "b_to" => _admittance_conversion(data_eng, eng_obj, "b_to"), + # "angmin" => fill(-10.0, nphases), + # "angmax" => fill( 10.0, nphases), + # "c_rating_a" => fill(Inf, nphases), + # "br_status" => eng_obj["status"] == DISABLED ? 0 : 1, + # ) + + # merge!(branch_obj, _branch_obj) + + # data_math["branch"]["$(branch_obj["index"])"] = branch_obj + + # map_to = [map_to, "bus.$(bus_obj["index"])", "branch.$(branch_obj["index"])"] + # end data_math["switch"]["$(math_obj["index"])"] = math_obj diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index daf8e2806..ac092e2da 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -346,13 +346,19 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: wire_positions = spacinginfo_data["WireSpacingInfo.WirePositions"] num_of_wires = length(wire_positions) + # Kron reduce bus terminals by removing conn 4 based on number of wires + if num_of_wires > nconds + reduce = true + end + # Coordinates x_coords = Vector{Float64}(undef, num_of_wires) y_coords = Vector{Float64}(undef, num_of_wires) for i in 1:1:num_of_wires - x_coords[i] = get(wire_positions[i], "WirePosition.xCoord", 0.0) - y_coords[i] = get(wire_positions[i], "WirePosition.yCoord", 0.0) + seq_num = wire_positions[i]["WirePosition.sequenceNumber"] + x_coords[seq_num] = get(wire_positions[i], "WirePosition.xCoord", 0.0) + y_coords[seq_num] = get(wire_positions[i], "WirePosition.yCoord", 0.0) end # angular frequency @@ -897,7 +903,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) r_s[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)) - r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios^2 # reactance computation x_sc[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.x", @@ -905,17 +910,22 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # -- alternative computation of xsc using sc tests if haskey(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndShortCircuitTests") leak_impedance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] - x_sc[wdg_endNumber][tank_id] = (sqrt((leak_impedance_wdg / zbase)^2 - ((r_s[wdg_endNumber][tank_id]*100.0 / zbase)*2)^2)/100.0)*zbase + rs_pct = (r_s[wdg_endNumber][tank_id]/zbase)*100.0 + x_sc[wdg_endNumber][tank_id] = (sqrt((leak_impedance_wdg/zbase)^2 - (rs_pct+rs_pct)^2)/100)*zbase end + + # RS and XSC computation based on ratios + r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios^2 x_sc[wdg_endNumber][tank_id] = (x_sc[wdg_endNumber][tank_id]/ratios^2) # g_sh always with respect to wdg #1 always if wdg_endNumber == 1 transf_end_noloadtest = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndNoLoadTests", [Dict()]) loss = get(transf_end_noloadtest[1], "NoLoadTest.loss", 0.0) - g_sh_tank = (loss*snom_wdg)/zbase + g_sh_tank = (loss/(0.01*(snom_wdg/1000.0)))/zbase exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", 0.0) - b_sh_tank = -((sqrt(abs((exct_current)^2 - (loss/(0.01*snom_wdg))^2)))/(100.0*zbase)) + cmag = sqrt(exct_current^2 - (loss*100.0/(0.01*(snom_wdg/1000.0)))^2)/100 + b_sh_tank = -(cmag*snom_wdg)/(vnom_wdg^2) # data is measured externally, but we now refer it to the internal side g_sh[tank_id] = g_sh_tank*ratios^2 b_sh[tank_id] = b_sh_tank*ratios^2 @@ -1555,9 +1565,13 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end # Correct (if needed) single-phase DELTA connections - if (math_obj["configuration"] == DELTA) && (nphases == 1) - math_obj["configuration"] = WYE - @warn "EnergyConsumer (load): $name has DELTA configuration but only 1 connection (phase). DELTA configurations must have at least 2 or 3 connections!. EnergyConsumer converted to WYE connection." + if (math_obj["configuration"] == DELTA) + math_obj["vnom_kv"] = math_obj["vnom_kv"]*sqrt(3) + if (nphases == 1) + math_obj["configuration"] = WYE + @warn "EnergyConsumer (load): $name has DELTA configuration but only 1 connection (phase). DELTA configurations must have at least 2 or 3 connections!. EnergyConsumer converted to WYE connection." + math_obj["vnom_kv"] = math_obj["vnom_kv"]/sqrt(3) + end end # Set status, dispatchable flag, and index From 9c399ebb0599d2a62ef64a42951d21bda933d696 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 10 Apr 2025 09:14:35 -0600 Subject: [PATCH 56/99] FIX: issues with sequence numbers in JSON files missing, and exciting current being calculated incorrectly when missing. --- src/data_model/transformations/ravens2math.jl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index ac092e2da..3e84a2699 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -346,7 +346,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: wire_positions = spacinginfo_data["WireSpacingInfo.WirePositions"] num_of_wires = length(wire_positions) - # Kron reduce bus terminals by removing conn 4 based on number of wires + # TODO: Kron reduce bus terminals by removing conn 4 based on number of wires if num_of_wires > nconds reduce = true end @@ -356,7 +356,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: y_coords = Vector{Float64}(undef, num_of_wires) for i in 1:1:num_of_wires - seq_num = wire_positions[i]["WirePosition.sequenceNumber"] + seq_num = get(wire_positions[i], "WirePosition.sequenceNumber", i) x_coords[seq_num] = get(wire_positions[i], "WirePosition.xCoord", 0.0) y_coords[seq_num] = get(wire_positions[i], "WirePosition.yCoord", 0.0) end @@ -923,8 +923,9 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data transf_end_noloadtest = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndNoLoadTests", [Dict()]) loss = get(transf_end_noloadtest[1], "NoLoadTest.loss", 0.0) g_sh_tank = (loss/(0.01*(snom_wdg/1000.0)))/zbase - exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", 0.0) - cmag = sqrt(exct_current^2 - (loss*100.0/(0.01*(snom_wdg/1000.0)))^2)/100 + pctNoLoadLoss = loss*100.0/(0.01*(snom_wdg/1000.0)) + exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", pctNoLoadLoss) + cmag = sqrt(exct_current^2 - pctNoLoadLoss^2)/100 b_sh_tank = -(cmag*snom_wdg)/(vnom_wdg^2) # data is measured externally, but we now refer it to the internal side g_sh[tank_id] = g_sh_tank*ratios^2 From 112518031269eccb6e036c2df73fe613c003cfb7 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 10 Apr 2025 09:37:23 -0600 Subject: [PATCH 57/99] FIX: comment out eng2math block of code that needs to always run. --- src/data_model/transformations/eng2math.jl | 102 ++++++++++----------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/data_model/transformations/eng2math.jl b/src/data_model/transformations/eng2math.jl index e8c799f0a..60e75bf2e 100644 --- a/src/data_model/transformations/eng2math.jl +++ b/src/data_model/transformations/eng2math.jl @@ -579,57 +579,57 @@ function _map_eng2math_switch!(data_math::Dict{String,<:Any}, data_eng::Dict{Str _apply_linecode!(eng_obj, data_eng) end - # if !(all(isapprox.(get(eng_obj, "rs", zeros(1, 1)), 0)) && all(isapprox.(get(eng_obj, "xs", zeros(1, 1)), 0))) - # # build virtual bus - - # f_bus = deepcopy(data_math["bus"]["$(math_obj["f_bus"])"]) - # t_bus = deepcopy(data_math["bus"]["$(math_obj["t_bus"])"]) - - # N = length(eng_obj["t_connections"]) - # bus_obj = Dict{String,Any}( - # "name" => "_virtual_bus.switch.$name", - # "bus_i" => length(data_math["bus"])+1, - # "bus_type" => eng_obj["status"] == DISABLED ? 4 : 1, - # "terminals" => eng_obj["t_connections"], # connected to the switch on the to-side - # "grounded" => fill(false, N), # connected to the switch on the to-side - # "vmin" => fill(0.0, N), - # "vmax" => fill(Inf, N), - # "vm_pair_lb" => Tuple{Any,Any,Real}[], - # "vm_pair_ub" => Tuple{Any,Any,Real}[], - # "source_id" => "switch.$name", - # "index" => length(data_math["bus"])+1, - # ) - - # math_obj["t_bus"] = bus_obj["bus_i"] - # data_math["bus"]["$(bus_obj["index"])"] = bus_obj - - # branch_obj = _init_math_obj("line", name, eng_obj, length(data_math["branch"])+1) - - # _branch_obj = Dict{String,Any}( - # "name" => "_virtual_branch.switch.$name", - # "source_id" => "switch.$name", - # "f_bus" => bus_obj["bus_i"], - # "t_bus" => data_math["bus_lookup"][eng_obj["t_bus"]], - # "f_connections" => eng_obj["t_connections"], # the virtual branch connects to the switch on the to-side - # "t_connections" => eng_obj["t_connections"], # should be identical to the switch's to-side connections - # "br_r" => _impedance_conversion(data_eng, eng_obj, "rs"), - # "br_x" => _impedance_conversion(data_eng, eng_obj, "xs"), - # "g_fr" => _admittance_conversion(data_eng, eng_obj, "g_fr"), - # "g_to" => _admittance_conversion(data_eng, eng_obj, "g_to"), - # "b_fr" => _admittance_conversion(data_eng, eng_obj, "b_fr"), - # "b_to" => _admittance_conversion(data_eng, eng_obj, "b_to"), - # "angmin" => fill(-10.0, nphases), - # "angmax" => fill( 10.0, nphases), - # "c_rating_a" => fill(Inf, nphases), - # "br_status" => eng_obj["status"] == DISABLED ? 0 : 1, - # ) - - # merge!(branch_obj, _branch_obj) - - # data_math["branch"]["$(branch_obj["index"])"] = branch_obj - - # map_to = [map_to, "bus.$(bus_obj["index"])", "branch.$(branch_obj["index"])"] - # end + if !(all(isapprox.(get(eng_obj, "rs", zeros(1, 1)), 0)) && all(isapprox.(get(eng_obj, "xs", zeros(1, 1)), 0))) + # build virtual bus + + f_bus = deepcopy(data_math["bus"]["$(math_obj["f_bus"])"]) + t_bus = deepcopy(data_math["bus"]["$(math_obj["t_bus"])"]) + + N = length(eng_obj["t_connections"]) + bus_obj = Dict{String,Any}( + "name" => "_virtual_bus.switch.$name", + "bus_i" => length(data_math["bus"])+1, + "bus_type" => eng_obj["status"] == DISABLED ? 4 : 1, + "terminals" => eng_obj["t_connections"], # connected to the switch on the to-side + "grounded" => fill(false, N), # connected to the switch on the to-side + "vmin" => fill(0.0, N), + "vmax" => fill(Inf, N), + "vm_pair_lb" => Tuple{Any,Any,Real}[], + "vm_pair_ub" => Tuple{Any,Any,Real}[], + "source_id" => "switch.$name", + "index" => length(data_math["bus"])+1, + ) + + math_obj["t_bus"] = bus_obj["bus_i"] + data_math["bus"]["$(bus_obj["index"])"] = bus_obj + + branch_obj = _init_math_obj("line", name, eng_obj, length(data_math["branch"])+1) + + _branch_obj = Dict{String,Any}( + "name" => "_virtual_branch.switch.$name", + "source_id" => "switch.$name", + "f_bus" => bus_obj["bus_i"], + "t_bus" => data_math["bus_lookup"][eng_obj["t_bus"]], + "f_connections" => eng_obj["t_connections"], # the virtual branch connects to the switch on the to-side + "t_connections" => eng_obj["t_connections"], # should be identical to the switch's to-side connections + "br_r" => _impedance_conversion(data_eng, eng_obj, "rs"), + "br_x" => _impedance_conversion(data_eng, eng_obj, "xs"), + "g_fr" => _admittance_conversion(data_eng, eng_obj, "g_fr"), + "g_to" => _admittance_conversion(data_eng, eng_obj, "g_to"), + "b_fr" => _admittance_conversion(data_eng, eng_obj, "b_fr"), + "b_to" => _admittance_conversion(data_eng, eng_obj, "b_to"), + "angmin" => fill(-10.0, nphases), + "angmax" => fill( 10.0, nphases), + "c_rating_a" => fill(Inf, nphases), + "br_status" => eng_obj["status"] == DISABLED ? 0 : 1, + ) + + merge!(branch_obj, _branch_obj) + + data_math["branch"]["$(branch_obj["index"])"] = branch_obj + + map_to = [map_to, "bus.$(bus_obj["index"])", "branch.$(branch_obj["index"])"] + end data_math["switch"]["$(math_obj["index"])"] = math_obj From 3da40236fb839b79d7f7594a0aad98defddbafc9 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 10 Apr 2025 11:52:45 -0600 Subject: [PATCH 58/99] FIX: operational limit set to get the largest one in lines. --- src/data_model/transformations/ravens2math.jl | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 3e84a2699..516fb3d43 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -511,16 +511,24 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: if (haskey(terminals[1], "ACDCTerminal.OperationalLimitSet")) oplimitset_id = _extract_name(terminals[1]["ACDCTerminal.OperationalLimitSet"]) - oplimitset = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][1] # [1] emerg, [2] normal + oplimitset_valslist = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"] + oplimitset = Vector{Dict}(undef, length(oplimitset_valslist)) + for i in 1:length(oplimitset_valslist) + oplimitset[i] = data_ravens["OperationalLimitSet"][oplimitset_id]["OperationalLimitSet.OperationalLimitValue"][i] + end else - oplimitset = Dict() + oplimitset =[Dict()] end limit_keys = [("CurrentLimit.value", "c_rating_a"), ("CurrentLimit.value", "c_rating_b"), ("CurrentLimit.value", "c_rating_c"), ("ApparentPowerLimit.value", "rate_a"), ("ApparentPowerLimit.value", "rate_b"), ("ApparentPowerLimit.value", "rate_c")] - for (f_key, t_key) in limit_keys - math_obj[t_key] = haskey(oplimitset, f_key) ? fill(oplimitset[f_key], nphases) : fill(Inf, nphases) + for i in 1:length(oplimitset) + val = fill(0.0, nphases) + for (f_key, t_key) in limit_keys + val = haskey(oplimitset[i], f_key) && val[1] <= oplimitset[i][f_key] ? fill(oplimitset[i][f_key], nphases) : fill(Inf, nphases) + math_obj[t_key] = val + end end math_obj["br_status"] = get(ravens_obj, "Equipment.inService", true) == true ? 1 : 0 From 069e9895a41de1968b9819063a886f17f58cf034 Mon Sep 17 00:00:00 2001 From: jjospina Date: Fri, 11 Apr 2025 11:14:44 -0600 Subject: [PATCH 59/99] FIX: minor fixes to switches and pecs. --- src/data_model/transformations/ravens2math.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 516fb3d43..2e930a2d9 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1948,8 +1948,8 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data # Set pg and qg - math_obj["pg"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) - math_obj["qg"] = (get(ravens_obj, "PowerElectronicsConnection.q", 0.0) * ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["pg"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0) * -ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["qg"] = (get(ravens_obj, "PowerElectronicsConnection.q", 0.0) * -ones(nconductors) ./ nconductors)./(power_scale_factor) # TODO: add a polynomial parameters to be added to gen cost _add_gen_cost_model!(math_obj, ravens_obj) @@ -2020,8 +2020,8 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) # Set the ps and qs - math_obj["ps"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0))./(power_scale_factor) - math_obj["qs"] = (get(ravens_obj, "PowerElectronicsConnection.q", 0.0))./(power_scale_factor) + math_obj["ps"] = (-get(ravens_obj, "PowerElectronicsConnection.p", 0.0))./(power_scale_factor) + math_obj["qs"] = (-get(ravens_obj, "PowerElectronicsConnection.q", 0.0))./(power_scale_factor) # Set bus type bus_type = data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] @@ -2114,10 +2114,10 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di if haskey(ravens_obj, "PowerSystemResource.AssetDatasheet") swinfo_name = _extract_name(ravens_obj["PowerSystemResource.AssetDatasheet"]) swinfo_data = data_ravens["AssetInfo"]["SwitchInfo"][swinfo_name] - math_obj["current_rating"] = fill(get(swinfo_data, "SwitchInfo.ratedCurrent", Inf), nphases) + math_obj["current_rating"] = fill(get(swinfo_data, "SwitchInfo.breakingCapacity", get(swinfo_data, "SwitchInfo.ratedCurrent", Inf)), nphases) math_obj["sm_ub"] = math_obj["current_rating"] .* get(swinfo_data, "SwitchInfo.ratedVoltage", Inf) else - math_obj["current_rating"] = fill(get(ravens_obj, "Switch.ratedCurrent", Inf), nphases) + math_obj["current_rating"] = fill(get(swinfo_data, "SwitchInfo.breakingCapacity", get(swinfo_data, "SwitchInfo.ratedCurrent", Inf)), nphases) math_obj["sm_ub"] = math_obj["current_rating"] .* get(ravens_obj, "Switch.ratedVoltage", Inf) end From b7f332516bb320e35a8527d409a36e30bba091f6 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 15 Apr 2025 14:22:29 -0600 Subject: [PATCH 60/99] FIX: unmapping funcs for converting back to ENG model. --- src/data_model/transformations/ravens2math.jl | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 2e930a2d9..626a74e6c 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -177,7 +177,7 @@ function _map_ravens2math_nw!(data_math::Dict{String,<:Any}, data_ravens::Dict{S if nw==0 data_math["map"] = Vector{Dict{String,Any}}([ - Dict{String,Any}("unmap_function" => "_map_math2ravens_root!") + Dict{String,Any}("unmap_function" => "_map_math2eng_root!") ]) _init_base_components!(data_math) @@ -204,7 +204,7 @@ function _map_ravens2math_nw!(data_math::Dict{String,<:Any}, data_ravens::Dict{S else data_math[string(nw)]["map"] = Vector{Dict{String,Any}}([ - Dict{String,Any}("unmap_function" => "_map_math2ravens_root!") + Dict{String,Any}("unmap_function" => "_map_math2eng_root!") ]) _init_base_components!(data_math[string(nw)]) @@ -271,7 +271,7 @@ function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data push!(data_math["map"], Dict( "from" => name, "to" => "bus.$index", - "unmap_function" => "_map_math2ravens_bus!" + "unmap_function" => "_map_math2eng_bus!" )) end end @@ -537,7 +537,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => "branch.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_line!", + "unmap_function" => "_map_math2eng_line!", )) end @@ -561,7 +561,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => String[], - "unmap_function" => "_map_math2ravens_transformer!", + "unmap_function" => "_map_math2eng_transformer!", )) to_map = data_math["map"][end]["to"] @@ -1605,7 +1605,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => "load.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_load!", + "unmap_function" => "_map_math2eng_load!", )) end end @@ -1750,7 +1750,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => map_to, - "unmap_function" => "_map_math2ravens_energy_source!", + "unmap_function" => "_map_math2eng_voltage_source!", )) end end @@ -1859,7 +1859,7 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => "gen.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_rotating_machine!", + "unmap_function" => "_map_math2eng_generator!", )) end @@ -1960,7 +1960,7 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => "gen.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_photovoltaic_unit!", + "unmap_function" => "_map_math2eng_solar!", )) elseif (pec_type == "BatteryUnit") @@ -2036,7 +2036,7 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => "storage.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_battery_unit!", + "unmap_function" => "_map_math2eng_solar!", )) end end @@ -2135,7 +2135,7 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => map_to, - "unmap_function" => "_map_math2ravens_switch!", + "unmap_function" => "_map_math2eng_switch!", )) end @@ -2196,7 +2196,7 @@ function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => "shunt.$(math_obj["index"])", - "unmap_function" => "_map_math2ravens_shunt!", + "unmap_function" => "_map_math2eng_shunt!", )) end end From 234b9cc19d6284d7aca2bff4bcc4ccd5adc6ef6b Mon Sep 17 00:00:00 2001 From: jjospina Date: Fri, 25 Apr 2025 08:15:45 -0600 Subject: [PATCH 61/99] ADD: option to do Kron reduction to the Linecodes when kron=y is passed on DSS file. --- src/data_model/transformations/dss2eng.jl | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/data_model/transformations/dss2eng.jl b/src/data_model/transformations/dss2eng.jl index 59f4b2d96..ea2b29376 100644 --- a/src/data_model/transformations/dss2eng.jl +++ b/src/data_model/transformations/dss2eng.jl @@ -410,6 +410,24 @@ function _dss2eng_linecode!(data_eng::Dict{String,<:Any}, data_dss::OpenDssDataM _import_all!(eng_obj, dss_obj) end + # kron reduction on linecode only if kron key is found + reduce = get(dss_obj, "kron", false) + if reduce == true + nphases = nphases - 1 + Z = eng_obj["rs"] + im*eng_obj["xs"] + Y = (eng_obj["g_fr"].* 2.0) + (im*eng_obj["b_fr"] .* 2.0) + z, y = _kron(Z, Y, nphases) + rs, xs = real(z), imag(z) + g, b = real(y), imag(y) + eng_obj["rs"] = rs + eng_obj["xs"] = xs + eng_obj["b_fr"] = b ./ 2.0 + eng_obj["b_to"] = b ./ 2.0 + eng_obj["g_fr"] = g ./ 2.0 + eng_obj["g_to"] = g ./ 2.0 + eng_obj["cm_ub"] = fill(dss_obj["emergamps"], nphases) + end + _add_eng_obj!(data_eng, "linecode", id, eng_obj) end end From 4c9c98f2bbd2600f20fa662631fd079f2f9dcf9b Mon Sep 17 00:00:00 2001 From: jjospina Date: Fri, 25 Apr 2025 08:56:49 -0600 Subject: [PATCH 62/99] RM: deprecated redundant separation of TransformerTanks in ravens2math. --- src/data_model/transformations/ravens2math.jl | 762 ++++++------------ 1 file changed, 251 insertions(+), 511 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 626a74e6c..f63db1283 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -546,7 +546,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: end -# TODO: Transformers need a lot of changes/refactors!!! + "converts ravens n-winding transformers into mathematical ideal 2-winding lossless transformer branches and impedance branches to represent the loss model" function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data_ravens::Dict{String,<:Any}; pass_props::Vector{String}=String[], nw::Int=nw_id_default) @@ -807,582 +807,322 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Get tanks data tanks = ravens_obj["PowerTransformer.TransformerTank"] - # TODO: flag for debugging TransformerTanks models - combine_tanks = true - - # Combine tanks into a single transformer model (default) - if (combine_tanks == true) - - # number of tanks - ntanks = length(tanks) - - # TODO: IMPORTANT ASSUMPTIONS - # 1) assume there is at least 1 tank and that all tanks have the same number of windings (i.e., TransformerTankEnds) - # 2) assume the number of phases is equal to the number of tanks - DEPRECATED - # 3) assumes number of phases are indicated correctly in terminal # 1 - phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] # terminal 1 phasecode - nphases = length(_phasecode_map[phasecode]) - # nphases = length(tanks) # assume nphases == ntanks + # number of tanks + ntanks = length(tanks) - nrw = length(tanks[1]["TransformerTank.TransformerTankEnd"]) + # TODO: IMPORTANT ASSUMPTIONS + # 1) assume there is at least 1 tank and that all tanks have the same number of windings (i.e., TransformerTankEnds) + # 2) assume the number of phases is equal to the number of tanks - DEPRECATED + # 3) assumes number of phases are indicated correctly in terminal # 1 + phasecode = ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.phases"] # terminal 1 phasecode + nphases = length(_phasecode_map[phasecode]) + # nphases = length(tanks) # assume nphases == ntanks - # init connections vector for combined transformer windings - connections = [zeros(Int64, nphases) for _ in 1:nrw] + nrw = length(tanks[1]["TransformerTank.TransformerTankEnd"]) - # init nodes vector for combined transformer windings - nodes = ["" for _ in 1:nrw] + # init connections vector for combined transformer windings + connections = [zeros(Int64, nphases) for _ in 1:nrw] - # init rs, x_sc, g_sh, and b_sh data per wdg/tank(phase) - r_s = [zeros(Float64, nphases) for _ in 1:nrw] - x_sc = [zeros(Float64, nphases) for _ in 1:nrw] - g_sh = zeros(Float64, nphases) - b_sh = zeros(Float64, nphases) + # init nodes vector for combined transformer windings + nodes = ["" for _ in 1:nrw] - # init sm_ub and cm_ub - sm_ub = zeros(Float64, nrw) - cm_ub = zeros(Float64, nrw) + # init rs, x_sc, g_sh, and b_sh data per wdg/tank(phase) + r_s = [zeros(Float64, nphases) for _ in 1:nrw] + x_sc = [zeros(Float64, nphases) for _ in 1:nrw] + g_sh = zeros(Float64, nphases) + b_sh = zeros(Float64, nphases) - # init configuration - default WYE-WYE - configuration = [WYE for _ in 1:nrw] + # init sm_ub and cm_ub + sm_ub = zeros(Float64, nrw) + cm_ub = zeros(Float64, nrw) - # RegulatorControls flag - reg_controls = [false for _ in 1:nrw] - reg_obj = [Dict() for _ in 1:nrw] + # init configuration - default WYE-WYE + configuration = [WYE for _ in 1:nrw] - # init vnom for all windings - vnom = zeros(Float64, nrw) - - # temp store previous for checking - nodes_prev = [] - configuration_prev = [] - vnom_prev = [] - - # Init RatioTapChanger data (default) - tm_set = Vector{Vector{Float64}}(fill(fill(1.0, nphases), nrw)) - tm_lb = Vector{Vector{Float64}}(fill(fill(0.9, nphases), nrw)) - tm_ub = Vector{Vector{Float64}}(fill(fill(1.1, nphases), nrw)) - tm_fix = Vector{Vector{Bool}}(fill(ones(Bool, nphases), nrw)) - tm_step = Vector{Vector{Float64}}(fill(fill(1/32, nphases), nrw)) + # RegulatorControls flag + reg_controls = [false for _ in 1:nrw] + reg_obj = [Dict() for _ in 1:nrw] - for tank_id in 1:ntanks + # init vnom for all windings + vnom = zeros(Float64, nrw) - # Get wdg data - wdgs = tanks[tank_id]["TransformerTank.TransformerTankEnd"] + # temp store previous for checking + nodes_prev = [] + configuration_prev = [] + vnom_prev = [] - # Tank Asset - tank_asset_name = _extract_name(tanks[tank_id]["PowerSystemResource.AssetDatasheet"]) - tank_asset_data = data_ravens["AssetInfo"]["PowerTransformerInfo"][tank_asset_name] + # Init RatioTapChanger data (default) + tm_set = Vector{Vector{Float64}}(fill(fill(1.0, nphases), nrw)) + tm_lb = Vector{Vector{Float64}}(fill(fill(0.9, nphases), nrw)) + tm_ub = Vector{Vector{Float64}}(fill(fill(1.1, nphases), nrw)) + tm_fix = Vector{Vector{Bool}}(fill(ones(Bool, nphases), nrw)) + tm_step = Vector{Vector{Float64}}(fill(fill(1/32, nphases), nrw)) - for wdg_id in 1:nrw + for tank_id in 1:ntanks - # wdg terminals & phasecode - wdg_terminals = ravens_obj["ConductingEquipment.Terminals"][wdg_id] - wdg_phasecode = wdg_terminals["Terminal.phases"] + # Get wdg data + wdgs = tanks[tank_id]["TransformerTank.TransformerTankEnd"] - # wdg endNumber - wdg_endNumber = wdgs[wdg_id]["TransformerEnd.endNumber"] + # Tank Asset + tank_asset_name = _extract_name(tanks[tank_id]["PowerSystemResource.AssetDatasheet"]) + tank_asset_data = data_ravens["AssetInfo"]["PowerTransformerInfo"][tank_asset_name] - # from-and-to-nodes for wdgs - nodes[wdg_endNumber] = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) + for wdg_id in 1:nrw - # Connections (based on _phasecode_map) - if haskey(_phasecode_map, wdg_phasecode) - phasecode_conns = _phasecode_map[wdg_phasecode] - if !(length(phasecode_conns)>1) - connections[wdg_endNumber][tank_id] = phasecode_conns[1] - else - connections[wdg_endNumber] = phasecode_conns - end - else - @error("PhaseCode not supported yet!") - end + # wdg terminals & phasecode + wdg_terminals = ravens_obj["ConductingEquipment.Terminals"][wdg_id] + wdg_phasecode = wdg_terminals["Terminal.phases"] - # transformer tank end info. - transf_end_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] - vnom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedU"] - snom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedS"] - zbase = (vnom_wdg^2) / snom_wdg - ratios = vnom_wdg/voltage_scale_factor - - # assign vnom_wdg to vnom for transformer - vnom[wdg_endNumber] = vnom_wdg - - # resistance computation - transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) - r_s[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", - get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)) - - # reactance computation - x_sc[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.x", - get(transf_star_impedance, "TransformerStarImpedance.x", 0.0)) - # -- alternative computation of xsc using sc tests - if haskey(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndShortCircuitTests") - leak_impedance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] - rs_pct = (r_s[wdg_endNumber][tank_id]/zbase)*100.0 - x_sc[wdg_endNumber][tank_id] = (sqrt((leak_impedance_wdg/zbase)^2 - (rs_pct+rs_pct)^2)/100)*zbase - end + # wdg endNumber + wdg_endNumber = wdgs[wdg_id]["TransformerEnd.endNumber"] - # RS and XSC computation based on ratios - r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios^2 - x_sc[wdg_endNumber][tank_id] = (x_sc[wdg_endNumber][tank_id]/ratios^2) - - # g_sh always with respect to wdg #1 always - if wdg_endNumber == 1 - transf_end_noloadtest = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndNoLoadTests", [Dict()]) - loss = get(transf_end_noloadtest[1], "NoLoadTest.loss", 0.0) - g_sh_tank = (loss/(0.01*(snom_wdg/1000.0)))/zbase - pctNoLoadLoss = loss*100.0/(0.01*(snom_wdg/1000.0)) - exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", pctNoLoadLoss) - cmag = sqrt(exct_current^2 - pctNoLoadLoss^2)/100 - b_sh_tank = -(cmag*snom_wdg)/(vnom_wdg^2) - # data is measured externally, but we now refer it to the internal side - g_sh[tank_id] = g_sh_tank*ratios^2 - b_sh[tank_id] = b_sh_tank*ratios^2 - end + # from-and-to-nodes for wdgs + nodes[wdg_endNumber] = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) - # configuration - conf = transf_end_info[wdg_endNumber]["TransformerEndInfo.connectionKind"] - if conf == "WindingConnection.Y" || conf == "WindingConnection.I" || conf == "WindingConnection.Yn" - configuration[wdg_endNumber] = WYE - elseif conf == "WindingConnection.D" - configuration[wdg_endNumber] = DELTA + # Connections (based on _phasecode_map) + if haskey(_phasecode_map, wdg_phasecode) + phasecode_conns = _phasecode_map[wdg_phasecode] + if !(length(phasecode_conns)>1) + connections[wdg_endNumber][tank_id] = phasecode_conns[1] else - @error("TransformerTank ConnectionKind not supported yet!") + connections[wdg_endNumber] = phasecode_conns end + else + @error("PhaseCode not supported yet!") + end - # add sm_ub if greater than existing (assumes the greatest value as the ratings for all phases in wdg) - semerg_wdg = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.emergencyS", Inf) - if semerg_wdg > sm_ub[wdg_endNumber] - sm_ub[wdg_endNumber] = semerg_wdg - end + # transformer tank end info. + transf_end_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] + vnom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedU"] + snom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedS"] + zbase = (vnom_wdg^2) / snom_wdg + ratios = vnom_wdg/voltage_scale_factor - # add cm_ub if greater than existing for winding (assumes the greatest value as the ratings for all phases in wdg) - cm_wdg = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.ratedI", Inf) - if cm_wdg > cm_ub[wdg_endNumber] - cm_ub[wdg_endNumber] = cm_wdg - end + # assign vnom_wdg to vnom for transformer + vnom[wdg_endNumber] = vnom_wdg - # Set RatioTapChanger in specific wdg - if haskey(wdgs[wdg_endNumber], "TransformerEnd.RatioTapChanger") - - rtc_name = _extract_name(wdgs[wdg_endNumber]["TransformerEnd.RatioTapChanger"]) - rtc_data = data_ravens["PowerSystemResource"]["TapChanger"]["RatioTapChanger"][rtc_name] - - # tm_step - hstep = get(rtc_data, "TapChanger.highStep", 16) - lstep = get(rtc_data, "TapChanger.lowStep", -16) - step_dist = abs(hstep) + abs(lstep) - step_tap = 1/step_dist - tm_step[wdg_endNumber] = fill(step_tap, nphases) - - # tm_set - step = get(rtc_data, "TapChanger.step", 1.0) # Starting Tap changer position/step - tm_set[wdg_endNumber] = fill(step, nphases) - - # tm_fix - ltcFlag = get(rtc_data, "TapChanger.ltcFlag", false) - if (ltcFlag == true) - tm_fix[wdg_endNumber] = zeros(Bool, nphases) - else - tm_fix[wdg_endNumber] = ones(Bool, nphases) - end - - # tm_ub/tm_lb - neutralVoltPu = get(rtc_data, "TapChanger.neutralU", vnom[wdg_endNumber])/vnom[wdg_endNumber] - step_volt_increment = get(rtc_data, "RatioTapChanger.stepVoltageIncrement", 100.0) - volt_lb = neutralVoltPu + step_tap * (step_volt_increment/100.0) * lstep - volt_ub = neutralVoltPu + step_tap * (step_volt_increment/100.0) * hstep - tm_lb[wdg_endNumber] = fill(volt_lb, nphases) - tm_ub[wdg_endNumber] = fill(volt_ub, nphases) - - # Regulator Control - if haskey(rtc_data, "TapChanger.TapChangerControl") && !all(tm_fix[wdg_endNumber]) - reg_controls[wdg_endNumber] = true - reg_obj[wdg_endNumber] = Dict{String,Any}( - "vreg" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetValue"], nphases), - "band" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetDeadband"], nphases), - "ptratio" => fill(rtc_data["TapChanger.ptRatio"], nphases), - "ctprim" => fill(rtc_data["TapChanger.ctRating"], nphases), - "r" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropR"], nphases), - "x" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropX"], nphases) - ) - end - - end + # resistance computation + transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) + r_s[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", + get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)) + # reactance computation + x_sc[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.x", + get(transf_star_impedance, "TransformerStarImpedance.x", 0.0)) + # -- alternative computation of xsc using sc tests + if haskey(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndShortCircuitTests") + leak_impedance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] + rs_pct = (r_s[wdg_endNumber][tank_id]/zbase)*100.0 + x_sc[wdg_endNumber][tank_id] = (sqrt((leak_impedance_wdg/zbase)^2 - (rs_pct+rs_pct)^2)/100)*zbase end - ### --- Consistency checks across tanks --- - # check that nodes are the same after first tank iter - if tank_id != 1 - @assert nodes == nodes_prev "nodes are not the same for all tanks! check ConnectivityNodes." # check if node names are the same as expected - else - nodes_prev = deepcopy(nodes) + # RS and XSC computation based on ratios + r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios^2 + x_sc[wdg_endNumber][tank_id] = (x_sc[wdg_endNumber][tank_id]/ratios^2) + + # g_sh always with respect to wdg #1 always + if wdg_endNumber == 1 + transf_end_noloadtest = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndNoLoadTests", [Dict()]) + loss = get(transf_end_noloadtest[1], "NoLoadTest.loss", 0.0) + g_sh_tank = (loss/(0.01*(snom_wdg/1000.0)))/zbase + pctNoLoadLoss = loss*100.0/(0.01*(snom_wdg/1000.0)) + exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", pctNoLoadLoss) + cmag = sqrt(exct_current^2 - pctNoLoadLoss^2)/100 + b_sh_tank = -(cmag*snom_wdg)/(vnom_wdg^2) + # data is measured externally, but we now refer it to the internal side + g_sh[tank_id] = g_sh_tank*ratios^2 + b_sh[tank_id] = b_sh_tank*ratios^2 end - # check that configurations across tanks are consistent - if tank_id != 1 - @assert configuration == configuration_prev "Configurations (e.g., WYE, DELTA) are not the same for all tanks and windings! check Configurations." # check if node names are the same as expected + # configuration + conf = transf_end_info[wdg_endNumber]["TransformerEndInfo.connectionKind"] + if conf == "WindingConnection.Y" || conf == "WindingConnection.I" || conf == "WindingConnection.Yn" + configuration[wdg_endNumber] = WYE + elseif conf == "WindingConnection.D" + configuration[wdg_endNumber] = DELTA else - configuration_prev = deepcopy(configuration) + @error("TransformerTank ConnectionKind not supported yet!") end - # check that vnoms across tanks are consistent for wdgs - if tank_id != 1 - @assert vnom == vnom_prev "rated Voltages are not consistent for all tanks and windings! check TransformerEndInfo.ratedU values." # check if node names are the same as expected - else - vnom_prev = deepcopy(vnom) + # add sm_ub if greater than existing (assumes the greatest value as the ratings for all phases in wdg) + semerg_wdg = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.emergencyS", Inf) + if semerg_wdg > sm_ub[wdg_endNumber] + sm_ub[wdg_endNumber] = semerg_wdg end - end - - # Add information about bus/node if missing - for i in 1:length(nodes) - node = nodes[i] - bus = data_math["bus_lookup"][node] - bus_data = data_math["bus"][string(bus)] - if !(haskey(bus_data, "terminals")) || (length(bus_data["terminals"]) < length(connections[i])) - bus_data["terminals"] = connections[i] - bus_data["vmin"] = fill(0.0, nphases) - bus_data["vmax"] = fill(Inf, nphases) - bus_data["grounded"] = zeros(Bool, nphases) + # add cm_ub if greater than existing for winding (assumes the greatest value as the ratings for all phases in wdg) + cm_wdg = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.ratedI", Inf) + if cm_wdg > cm_ub[wdg_endNumber] + cm_ub[wdg_endNumber] = cm_wdg end - # Add vnom info to bus - data_math["settings"]["vbases_network"][string(bus)] = deepcopy(vnom[i]/voltage_scale_factor) - end - # wdg i, tank 1 - assumes tank 1 always exists - r_s = [r_s[i][1] for i in 1:nrw] - x_sc = [x_sc[1][1]] # wrt to wdg 1 - g_sh = g_sh[1] # wrt to wdg 1 - b_sh = b_sh[1] # wrt to wdg 1 + # Set RatioTapChanger in specific wdg + if haskey(wdgs[wdg_endNumber], "TransformerEnd.RatioTapChanger") - # convert x_sc from list of upper triangle elements to an explicit dict - y_sh = g_sh + im*b_sh - z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) + rtc_name = _extract_name(wdgs[wdg_endNumber]["TransformerEnd.RatioTapChanger"]) + rtc_data = data_ravens["PowerSystemResource"]["TapChanger"]["RatioTapChanger"][rtc_name] - # init Polarity - polarity = fill(1, nrw) + # tm_step + hstep = get(rtc_data, "TapChanger.highStep", 16) + lstep = get(rtc_data, "TapChanger.lowStep", -16) + step_dist = abs(hstep) + abs(lstep) + step_tap = 1/step_dist + tm_step[wdg_endNumber] = fill(step_tap, nphases) - # Status - status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true - status = status == true ? 1 : 0 + # tm_set + step = get(rtc_data, "TapChanger.step", 1.0) # Starting Tap changer position/step + tm_set[wdg_endNumber] = fill(step, nphases) - # Build loss model - transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=nphases, status=status) - - # Mathematical model for transformer - for wdg_id in 1:nrw - # 2-WINDING TRANSFORMER - - # correct polarity and connections - if wdg_id>1 - if configuration[1] == DELTA && configuration[wdg_id] == WYE - polarity[wdg_id] = -1 - connections[wdg_id] = _barrel_roll(connections[wdg_id][1:end], 1) - end - if configuration[1] == WYE && configuration[wdg_id] == DELTA - polarity[wdg_id] = -1 - connections[wdg_id] = _barrel_roll(connections[wdg_id], -1) + # tm_fix + ltcFlag = get(rtc_data, "TapChanger.ltcFlag", false) + if (ltcFlag == true) + tm_fix[wdg_endNumber] = zeros(Bool, nphases) + else + tm_fix[wdg_endNumber] = ones(Bool, nphases) end - end - # tm_nom depending on wdg configuration - tm_nom = configuration[wdg_id]==DELTA ? vnom[wdg_id]*sqrt(3)/voltage_scale_factor : vnom[wdg_id]/voltage_scale_factor - - # Transformer Object - transformer_2wa_obj = Dict{String,Any}( - "name" => "_virtual_transformer.$name.$wdg_id", - "source_id" => "_virtual_transformer.transformer.$name.$wdg_id", - "f_bus" => data_math["bus_lookup"][nodes[wdg_id]], - "t_bus" => transformer_t_bus_w[wdg_id], - "tm_nom" => tm_nom, - "f_connections" => connections[wdg_id], - "t_connections" => connections[1], - "configuration" => configuration[wdg_id], - "polarity" => polarity[wdg_id], - "tm_set" => tm_set[wdg_id], - "tm_fix" => tm_fix[wdg_id], - "sm_ub" => sm_ub[wdg_id]/power_scale_factor, - "cm_ub" => cm_ub[wdg_id], # TODO: this may need scaling - "status" => status, - "index" => length(data_math["transformer"])+1 - ) - - # RatioTapChanger - transformer_2wa_obj["tm_lb"] = tm_lb[wdg_id] - transformer_2wa_obj["tm_ub"] = tm_ub[wdg_id] - transformer_2wa_obj["tm_step"] = tm_step[wdg_id] - - data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj + # tm_ub/tm_lb + neutralVoltPu = get(rtc_data, "TapChanger.neutralU", vnom[wdg_endNumber])/vnom[wdg_endNumber] + step_volt_increment = get(rtc_data, "RatioTapChanger.stepVoltageIncrement", 100.0) + volt_lb = neutralVoltPu + step_tap * (step_volt_increment/100.0) * lstep + volt_ub = neutralVoltPu + step_tap * (step_volt_increment/100.0) * hstep + tm_lb[wdg_endNumber] = fill(volt_lb, nphases) + tm_ub[wdg_endNumber] = fill(volt_ub, nphases) + + # Regulator Control + if haskey(rtc_data, "TapChanger.TapChangerControl") && !all(tm_fix[wdg_endNumber]) + reg_controls[wdg_endNumber] = true + reg_obj[wdg_endNumber] = Dict{String,Any}( + "vreg" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetValue"], nphases), + "band" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetDeadband"], nphases), + "ptratio" => fill(rtc_data["TapChanger.ptRatio"], nphases), + "ctprim" => fill(rtc_data["TapChanger.ctRating"], nphases), + "r" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropR"], nphases), + "x" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropX"], nphases) + ) + end - # Add Regulator Controls (only if flag is true) - if (reg_controls[wdg_id] == true) - data_math["transformer"]["$(transformer_2wa_obj["index"])"]["controls"] = reg_obj[wdg_id] end - # TODO: Center-Tapped Transformers (3 Windings) - # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start - # end - - push!(to_map, "transformer.$(transformer_2wa_obj["index"])") + end + ### --- Consistency checks across tanks --- + # check that nodes are the same after first tank iter + if tank_id != 1 + @assert nodes == nodes_prev "nodes are not the same for all tanks! check ConnectivityNodes." # check if node names are the same as expected + else + nodes_prev = deepcopy(nodes) end - else # Create a transformer for each tank - for tank_id in 1:length(tanks) - - tank_data = tanks[tank_id] # tank data - wdgs_data = tank_data["TransformerTank.TransformerTankEnd"] # wdgs data - tank_asset_name = _extract_name(tanks[tank_id]["PowerSystemResource.AssetDatasheet"]) # tank asset name - tank_asset_data = data_ravens["AssetInfo"]["PowerTransformerInfo"][tank_asset_name] # tank asset data - nrw = length(tank_data["TransformerTank.TransformerTankEnd"]) # number of windings - nphases = 0 # init nphases var - - # per tank windings connections - connections = Vector{Vector{Int64}}(undef, nrw) - - # wdgs data vectors - vnom = zeros(Float64, nrw) - # init rs, x_sc, g_sh, and b_sh data per wdg - r_s = zeros(Float64, nrw) - x_sc = zeros(Float64, nrw) - g_sh = 0.0 - b_sh = 0.0 - - # configurations - wdgs_confs = Vector{ConnConfig}(undef, nrw) - - # RegulatorControls flag - reg_controls = [false for _ in 1:nrw] - reg_obj = [Dict() for _ in 1:nrw] # init - - # Init RatioTapChanger data (default) - tm_set = Vector{Vector{Float64}}(undef, nrw) - tm_lb = Vector{Vector{Float64}}(undef, nrw) - tm_ub = Vector{Vector{Float64}}(undef, nrw) - tm_fix = Vector{Vector{Bool}}(undef, nrw) - tm_step = Vector{Vector{Float64}}(undef, nrw) - - for wdg_id in 1:nrw - - wdg_terminals = ravens_obj["ConductingEquipment.Terminals"][wdg_id] - wdg_phasecode = wdg_terminals["Terminal.phases"] - wdg_endNumber = wdgs_data[wdg_id]["TransformerEnd.endNumber"] - - # connections (based on _phasecode_map) - if haskey(_phasecode_map, wdg_phasecode) - wdg_connections = _phasecode_map[wdg_phasecode] - connections[wdg_endNumber] = wdg_connections - else - @error("PhaseCode not supported yet!") - end + # check that configurations across tanks are consistent + if tank_id != 1 + @assert configuration == configuration_prev "Configurations (e.g., WYE, DELTA) are not the same for all tanks and windings! check Configurations." # check if node names are the same as expected + else + configuration_prev = deepcopy(configuration) + end - # from-and-to-nodes for wdg - nphases = length(wdg_connections) - node = _extract_name(wdg_terminals["Terminal.ConnectivityNode"]) - bus = data_math["bus_lookup"][node] - bus_data = data_math["bus"][string(bus)] - - # Add vmin/vmax/terminals info. if missing - if !(haskey(bus_data, "terminals")) || (length(bus_data["terminals"]) < length(wdg_connections)) - bus_data["terminals"] = wdg_connections - bus_data["vmin"] = fill(0.0, nphases) - bus_data["vmax"] = fill(Inf, nphases) - bus_data["grounded"] = zeros(Bool, nphases) - end + # check that vnoms across tanks are consistent for wdgs + if tank_id != 1 + @assert vnom == vnom_prev "rated Voltages are not consistent for all tanks and windings! check TransformerEndInfo.ratedU values." # check if node names are the same as expected + else + vnom_prev = deepcopy(vnom) + end - # transformer tank end info. - transf_end_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] - vnom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedU"] - snom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedS"] + end - zbase = (vnom_wdg^2) / snom_wdg - ratios = vnom_wdg/voltage_scale_factor + # Add information about bus/node if missing + for i in 1:length(nodes) + node = nodes[i] + bus = data_math["bus_lookup"][node] + bus_data = data_math["bus"][string(bus)] + if !(haskey(bus_data, "terminals")) || (length(bus_data["terminals"]) < length(connections[i])) + bus_data["terminals"] = connections[i] + bus_data["vmin"] = fill(0.0, nphases) + bus_data["vmax"] = fill(Inf, nphases) + bus_data["grounded"] = zeros(Bool, nphases) + end + # Add vnom info to bus + data_math["settings"]["vbases_network"][string(bus)] = deepcopy(vnom[i]/voltage_scale_factor) + end - # assign vnom_wdg to vnom for transformer - vnom[wdg_endNumber] = vnom_wdg + # wdg i, tank 1 - assumes tank 1 always exists + r_s = [r_s[i][1] for i in 1:nrw] + x_sc = [x_sc[1][1]] # wrt to wdg 1 + g_sh = g_sh[1] # wrt to wdg 1 + b_sh = b_sh[1] # wrt to wdg 1 - # Add vnom info to bus - data_math["settings"]["vbases_network"][string(bus)] = deepcopy(vnom_wdg/voltage_scale_factor) + # convert x_sc from list of upper triangle elements to an explicit dict + y_sh = g_sh + im*b_sh + z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) - # resistance computation - transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) - r_s[wdg_endNumber] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", - get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)) - r_s[wdg_endNumber] = r_s[wdg_endNumber]/ratios^2 + # init Polarity + polarity = fill(1, nrw) - # reactance computation - x_sc[wdg_endNumber] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.x", - get(transf_star_impedance, "TransformerStarImpedance.x", 0.0)) - # -- alternative computation of xsc using sc tests - if haskey(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndShortCircuitTests") - leak_impedance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] - x_sc[wdg_endNumber] = (sqrt((leak_impedance_wdg / zbase)^2 - ((r_s[wdg_endNumber]*100.0 / zbase)*2)^2)/100.0)*zbase - end - x_sc[wdg_endNumber] = (x_sc[wdg_endNumber]/ratios^2) - - # g_sh always with respect to wdg #1 always - if wdg_endNumber == 1 - transf_end_noloadtest = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndNoLoadTests", [Dict()]) - loss = get(transf_end_noloadtest[1], "NoLoadTest.loss", 0.0) - g_sh_tank = (loss*snom_wdg)/zbase - exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", 0.0) - b_sh_tank = -((sqrt(abs((exct_current)^2 - (loss/(0.01*snom_wdg))^2)))/(100.0*zbase)) - # data is measured externally, but we now refer it to the internal side - g_sh = g_sh_tank*ratios^2 - b_sh = b_sh_tank*ratios^2 - end + # Status + status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true + status = status == true ? 1 : 0 - # wdgs configurations - wdg_conf = transf_end_info[wdg_endNumber]["TransformerEndInfo.connectionKind"] # extract wdg conf - if wdg_conf == "WindingConnection.Y" || wdg_conf == "WindingConnection.I" || wdg_conf == "WindingConnection.Yn" - wdgs_confs[wdg_endNumber] = WYE - elseif wdg_conf == "WindingConnection.D" - wdgs_confs[wdg_endNumber] = DELTA - else - @error("PowerTransformer ConnectionKind not supported yet!") - end + # Build loss model + transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=nphases, status=status) - # Set RatioTapChanger in specific wdg - if haskey(wdgs_data[wdg_endNumber], "TransformerEnd.RatioTapChanger") - - rtc_name = _extract_name(wdgs_data[wdg_endNumber]["TransformerEnd.RatioTapChanger"]) - rtc_data = data_ravens["PowerSystemResource"]["TapChanger"]["RatioTapChanger"][rtc_name] - - # tm_step - hstep = get(rtc_data, "TapChanger.highStep", 16) - lstep = get(rtc_data, "TapChanger.lowStep", -16) - step_dist = abs(hstep) + abs(lstep) - step_tap = 1/step_dist - tm_step[wdg_endNumber] = fill(step_tap, nphases) - - # tm_set - step = get(rtc_data, "TapChanger.step", 1.0) # Starting Tap changer position/step - tm_set[wdg_endNumber] = fill(step, nphases) - - # tm_fix - ltcFlag = get(rtc_data, "TapChanger.ltcFlag", false) - if (ltcFlag == true) - tm_fix[wdg_endNumber] = zeros(Bool, nphases) - else - tm_fix[wdg_endNumber] = ones(Bool, nphases) - end - - # tm_ub/tm_lb - neutralVoltPu = get(rtc_data, "TapChanger.neutralU", vnom[wdg_endNumber])/vnom[wdg_endNumber] - step_volt_increment = get(rtc_data, "RatioTapChanger.stepVoltageIncrement", 100.0) - volt_lb = neutralVoltPu + step_tap * (step_volt_increment/100.0) * lstep - volt_ub = neutralVoltPu + step_tap * (step_volt_increment/100.0) * hstep - tm_lb[wdg_endNumber] = fill(volt_lb, nphases) - tm_ub[wdg_endNumber] = fill(volt_ub, nphases) - - # Regulator Control - if haskey(rtc_data, "TapChanger.TapChangerControl") && !all(tm_fix[wdg_endNumber]) - reg_controls[wdg_endNumber] = true - reg_obj[wdg_endNumber] = Dict{String,Any}( - "vreg" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetValue"], nphases), - "band" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetDeadband"], nphases), - "ptratio" => fill(rtc_data["TapChanger.ptRatio"], nphases), - "ctprim" => fill(rtc_data["TapChanger.ctRating"], nphases), - "r" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropR"], nphases), - "x" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropX"], nphases) - ) - end - - else # default - tm_set[wdg_endNumber] = fill(1.0, nphases) - tm_lb[wdg_endNumber] = fill(0.9, nphases) - tm_ub[wdg_endNumber] = fill(1.1, nphases) - tm_fix[wdg_endNumber] = ones(Bool, nphases) - tm_step[wdg_endNumber] = fill(1/32, nphases) - end + # Mathematical model for transformer + for wdg_id in 1:nrw + # 2-WINDING TRANSFORMER + # correct polarity and connections + if wdg_id>1 + if configuration[1] == DELTA && configuration[wdg_id] == WYE + polarity[wdg_id] = -1 + connections[wdg_id] = _barrel_roll(connections[wdg_id][1:end], 1) + end + if configuration[1] == WYE && configuration[wdg_id] == DELTA + polarity[wdg_id] = -1 + connections[wdg_id] = _barrel_roll(connections[wdg_id], -1) end + end - # convert x_sc from list of upper triangle elements to an explicit dict - y_sh = g_sh + im*b_sh - z_sc = Dict([(key, im*x_sc[i]) for (i,key) in enumerate([(i,j) for i in 1:nrw for j in i+1:nrw])]) - - # dimensions - dims = length(tm_set[1]) - - # init polarity - polarity = fill(1, nrw) - - # Status - status = haskey(tanks[tank_id], "Equipment.inService") ? tanks[tank_id]["Equipment.inService"] : true - status = status == true ? 1 : 0 - - # Build loss model - transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=dims, status=status) - - # Mathematical model for transformer - for wdg_id in 1:1:nrw - # 2-WINDING TRANSFORMER - - # correct polarity and connections - if wdg_id>1 - if wdgs_confs[1] == DELTA && wdgs_confs[wdg_id] == WYE - polarity[wdg_id] = -1 - connections[wdg_id] = _barrel_roll(connections[wdg_id][1:end], 1) - end - if wdgs_confs[1] == WYE && wdgs_confs[wdg_id] == DELTA - polarity[wdg_id] = -1 - connections[wdg_id] = _barrel_roll(connections[wdg_id], -1) - end - end + # tm_nom depending on wdg configuration + tm_nom = configuration[wdg_id]==DELTA ? vnom[wdg_id]*sqrt(3)/voltage_scale_factor : vnom[wdg_id]/voltage_scale_factor - # tank asset data - wdg_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] - - # make virtual bus and mark it for reduction - tm_nom = wdgs_confs[wdg_id]==DELTA ? vnom[wdg_id]*sqrt(3)/voltage_scale_factor : vnom[wdg_id]/voltage_scale_factor - - # Get correct f_node for winding - wdg_term = ravens_obj["ConductingEquipment.Terminals"][wdg_id] - f_node_wdgterm = _extract_name(wdg_term["Terminal.ConnectivityNode"]) - - # Transformer Object - transformer_2wa_obj = Dict{String,Any}( - "name" => "_virtual_transformer.$name.$wdg_id.$(connections[wdg_id])", - "source_id" => "_virtual_transformer.transformer.$name.$wdg_id.$(connections[wdg_id])", - "f_bus" => data_math["bus_lookup"][f_node_wdgterm], - "t_bus" => transformer_t_bus_w[wdg_id], - "tm_nom" => tm_nom, - "f_connections" => connections[wdg_id], - "t_connections" => connections[1], - "configuration" => wdgs_confs[wdg_id], - "polarity" => polarity[wdg_id], - "tm_set" => tm_set[wdg_id], - "tm_fix" => tm_fix[wdg_id], - "sm_ub" => get(wdg_info[wdg_id], "TransformerEndInfo.emergencyS", Inf)/power_scale_factor, - "cm_ub" => get(wdg_info[wdg_id], "TransformerEndInfo.ratedI", Inf), - "status" => status, - "index" => length(data_math["transformer"])+1 - ) - - # RatioTapChanger - transformer_2wa_obj["tm_lb"] = tm_lb[wdg_id] - transformer_2wa_obj["tm_ub"] = tm_ub[wdg_id] - transformer_2wa_obj["tm_step"] = tm_step[wdg_id] - - data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj - - # Add Regulator Controls (only if flag is true) - if (reg_controls[wdg_id] == true) - data_math["transformer"]["$(transformer_2wa_obj["index"])"]["controls"] = reg_obj[wdg_id] - end + # Transformer Object + transformer_2wa_obj = Dict{String,Any}( + "name" => "_virtual_transformer.$name.$wdg_id", + "source_id" => "_virtual_transformer.transformer.$name.$wdg_id", + "f_bus" => data_math["bus_lookup"][nodes[wdg_id]], + "t_bus" => transformer_t_bus_w[wdg_id], + "tm_nom" => tm_nom, + "f_connections" => connections[wdg_id], + "t_connections" => connections[1], + "configuration" => configuration[wdg_id], + "polarity" => polarity[wdg_id], + "tm_set" => tm_set[wdg_id], + "tm_fix" => tm_fix[wdg_id], + "sm_ub" => sm_ub[wdg_id]/power_scale_factor, + "cm_ub" => cm_ub[wdg_id], # TODO: this may need scaling + "status" => status, + "index" => length(data_math["transformer"])+1 + ) - # TODO: Center-Tapped Transformers (3 Windings) - # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start - # end + # RatioTapChanger + transformer_2wa_obj["tm_lb"] = tm_lb[wdg_id] + transformer_2wa_obj["tm_ub"] = tm_ub[wdg_id] + transformer_2wa_obj["tm_step"] = tm_step[wdg_id] - push!(to_map, "transformer.$(transformer_2wa_obj["index"])") + data_math["transformer"]["$(transformer_2wa_obj["index"])"] = transformer_2wa_obj - end + # Add Regulator Controls (only if flag is true) + if (reg_controls[wdg_id] == true) + data_math["transformer"]["$(transformer_2wa_obj["index"])"]["controls"] = reg_obj[wdg_id] end + + # TODO: Center-Tapped Transformers (3 Windings) + # if w==3 && eng_obj["polarity"][w]==-1 # identify center-tapped transformer and mark all secondary-side nodes as triplex by adding va_start + # end + + push!(to_map, "transformer.$(transformer_2wa_obj["index"])") + end + end end From 71e397f15a484c3ed245d32f8ac8a39bff96c399 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 28 Apr 2025 11:55:01 -0600 Subject: [PATCH 63/99] FIX: issue of not computing rs and xsc for second winding correctly due to information missing for second windings. --- src/data_model/transformations/ravens2math.jl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index f63db1283..ed74c171a 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -858,6 +858,9 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data tm_fix = Vector{Vector{Bool}}(fill(ones(Bool, nphases), nrw)) tm_step = Vector{Vector{Float64}}(fill(fill(1/32, nphases), nrw)) + # Init transf_star_impedance + transf_star_impedance = Dict() + for tank_id in 1:ntanks # Get wdg data @@ -901,14 +904,22 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # assign vnom_wdg to vnom for transformer vnom[wdg_endNumber] = vnom_wdg + # Transformer star impedance when values are missing for other windings. + if (wdg_endNumber != 1 && transf_star_impedance != Dict()) + transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", transf_end_info[wdg_endNumber-1]["TransformerEndInfo.TransformerStarImpedance"]) + ratios = vnom[wdg_endNumber-1]/voltage_scale_factor + else + transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) + end + # resistance computation - transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) r_s[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)) # reactance computation x_sc[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.x", get(transf_star_impedance, "TransformerStarImpedance.x", 0.0)) + # -- alternative computation of xsc using sc tests if haskey(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndShortCircuitTests") leak_impedance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] From a4e4ea1f338970d274c5a289ad7d226cb1a44fee Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 28 Apr 2025 18:00:29 -0600 Subject: [PATCH 64/99] FIX: bug for considering neutral phase. --- src/data_model/transformations/ravens2math.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index ed74c171a..6590ab1a7 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -297,7 +297,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: math_obj["f_bus"] = data_math["bus_lookup"][f_node] math_obj["t_bus"] = data_math["bus_lookup"][t_node] - bus_terminals = nconds >= 3 ? collect(1:nconds) : [_phase_map[phase["ACLineSegmentPhase.phase"]] for phase in ravens_obj["ACLineSegment.ACLineSegmentPhase"]] + bus_terminals = nconds >= 4 ? collect(1:nconds) : [_phase_map[phase["ACLineSegmentPhase.phase"]] for phase in ravens_obj["ACLineSegment.ACLineSegmentPhase"]] # TODO: Kron reduce bus terminals by removing conn 4 reduce = false # flag for Kron reduction From d25545d3a71e66b516ba31d673f1cb91018b915d Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 29 Apr 2025 14:31:03 -0600 Subject: [PATCH 65/99] FIX: missing division by 2 when parsing Transformer MeshImpedance or StarImpedance resistance values. --- src/data_model/transformations/ravens2math.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 6590ab1a7..e079e8245 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -646,11 +646,13 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # resistance transf_star_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.StarImpedance", Dict()) + transf_mesh_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.MeshImpedance", Dict()) + r_s[wdg_endNumber] = get(wdgs[wdg_endNumber], "PowerTransformerEnd.r", - get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)) + get(transf_star_impedance, "TransformerStarImpedance.r", + get(transf_mesh_impedance, "TransformerMeshImpedance.r", 0.0))./2) # divide by 2 because XFRMR Star Resistance includes both windings. # reactance - transf_mesh_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.MeshImpedance", Dict()) x_sc[wdg_endNumber] = get(transf_mesh_impedance, "TransformerMeshImpedance.x", get(transf_star_impedance, "TransformerStarImpedance.x", 0.0)) @@ -914,7 +916,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # resistance computation r_s[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", - get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)) + get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)./2) # divide by 2 because XFRMR Star Resistance includes both windings. # reactance computation x_sc[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.x", From f5884c7fa7c994cebbfac47fbab0ee08b25afdbe Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 6 May 2025 14:20:29 -0600 Subject: [PATCH 66/99] REF: revise powerelectronicsconnection to compute basevoltage when not available. --- src/data_model/transformations/ravens2math.jl | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index e079e8245..e650ddb60 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1659,10 +1659,16 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) # Set the nominal voltage - base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) - nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - base_voltage = nominal_voltage / sqrt(nconductors) - math_obj["vbase"] = base_voltage / voltage_scale_factor + bus_conn = data_math["bus"]["$(math_obj["gen_bus"])"] + if haskey(ravens_obj, "ConductingEquipment.BaseVoltage") + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) + nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + base_voltage = nominal_voltage / sqrt(nconductors) + math_obj["vbase"] = base_voltage / voltage_scale_factor + else + math_obj["vbase"] = data_math["settings"]["vbases_buses"][string(math_obj["gen_bus"])] + nominal_voltage = math_obj["vbase"] * voltage_scale_factor * sqrt(nconductors) + end if control_mode == Int(ISOCHRONOUS) && status == 1 data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) @@ -1720,8 +1726,8 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data math_obj = _init_math_obj_ravens("storage", name, ravens_obj, length(data_math["storage"])+1; pass_props=pass_props) - # TODO: connections/phases do not exist in the RAVENS-CIM (Need to be added) - should come from terminals - connections = [1, 2, 3] # TODO + # Connections/phases + connections = _phasecode_map[get(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases", "PhaseCode.ABC")] nconductors = length(connections) math_obj["connections"] = connections @@ -1789,7 +1795,7 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data push!(data_math["map"], Dict{String,Any}( "from" => name, "to" => "storage.$(math_obj["index"])", - "unmap_function" => "_map_math2eng_solar!", + "unmap_function" => "_map_math2eng_storage!", )) end end From e0cea53fc768328869dfca9bce32700b85a9b2e6 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 8 May 2025 13:38:48 -0600 Subject: [PATCH 67/99] REF: TapChangerRatio values using new UML schema. --- src/data_model/transformations/ravens2math.jl | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index e650ddb60..98d2125de 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -698,14 +698,23 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Regulator Control if haskey(rtc_data, "TapChanger.TapChangerControl") && !all(tm_fix[wdg_endNumber]) reg_controls[wdg_endNumber] = true + + if haskey(rtc_data, "TapChanger.TapChangerRatio") + ptRatio = get(rtc_data["TapChanger.TapChangerRatio"], "TapChanger.ptRatio", 60.0) + ctRating = get(rtc_data["TapChanger.TapChangerRatio"], "TapChanger.ctRating", 0.2) + else + ptRatio = 60.0 + ctRating = 0.2 + end + reg_obj[wdg_endNumber] = Dict{String,Any}( "vreg" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetValue"], nphases), "band" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetDeadband"], nphases), - "ptratio" => fill(rtc_data["TapChanger.ptRatio"], nphases), - "ctprim" => fill(rtc_data["TapChanger.ctRating"], nphases), + "ptratio" => fill(ptRatio, nphases), + "ctprim" => fill(ctRating, nphases), "r" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropR"], nphases), "x" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropX"], nphases) - ) + ) end else # default @@ -1005,14 +1014,23 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Regulator Control if haskey(rtc_data, "TapChanger.TapChangerControl") && !all(tm_fix[wdg_endNumber]) reg_controls[wdg_endNumber] = true + + if haskey(rtc_data, "TapChanger.TapChangerRatio") + ptRatio = get(rtc_data["TapChanger.TapChangerRatio"], "TapChanger.ptRatio", 60.0) + ctRating = get(rtc_data["TapChanger.TapChangerRatio"], "TapChanger.ctRating", 0.2) + else + ptRatio = 60.0 + ctRating = 0.2 + end + reg_obj[wdg_endNumber] = Dict{String,Any}( "vreg" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetValue"], nphases), "band" => fill(rtc_data["TapChanger.TapChangerControl"]["RegulatingControl.targetDeadband"], nphases), - "ptratio" => fill(rtc_data["TapChanger.ptRatio"], nphases), - "ctprim" => fill(rtc_data["TapChanger.ctRating"], nphases), + "ptratio" => fill(ptRatio, nphases), + "ctprim" => fill(ctRating, nphases), "r" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropR"], nphases), "x" => fill(rtc_data["TapChanger.TapChangerControl"]["TapChangerControl.lineDropX"], nphases) - ) + ) end end From c6b667673838cda3a898fd5b426106b705db078b Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 14 May 2025 14:14:37 -0600 Subject: [PATCH 68/99] FIX: issue related to transformer reactance computation when doing ravens2math conversion. --- src/data_model/transformations/ravens2math.jl | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 98d2125de..b83137c30 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -729,7 +729,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # data is measured externally, but we now refer it to the internal side - some values are referred to wdg 1 ratios = vnom/voltage_scale_factor - x_sc = (x_sc[1]./ratios[1]^2)./100.0 + x_sc = (x_sc[1]./ratios[1]^2) r_s = r_s./ratios.^2 g_sh = g_sh[1]*ratios[1]^2 b_sh = b_sh[1]*ratios[1]^2 @@ -911,16 +911,19 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data snom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedS"] zbase = (vnom_wdg^2) / snom_wdg ratios = vnom_wdg/voltage_scale_factor + ratios_wdg1 = ratios # assign vnom_wdg to vnom for transformer vnom[wdg_endNumber] = vnom_wdg # Transformer star impedance when values are missing for other windings. - if (wdg_endNumber != 1 && transf_star_impedance != Dict()) - transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", transf_end_info[wdg_endNumber-1]["TransformerEndInfo.TransformerStarImpedance"]) - ratios = vnom[wdg_endNumber-1]/voltage_scale_factor - else - transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) + if (wdg_endNumber != 1) + ratios_wdg1 = vnom[1]/voltage_scale_factor # HV wdg1 + if (transf_star_impedance != Dict()) + transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", transf_end_info[wdg_endNumber-1]["TransformerEndInfo.TransformerStarImpedance"]) + else + transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) + end end # resistance computation @@ -940,7 +943,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # RS and XSC computation based on ratios r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios^2 - x_sc[wdg_endNumber][tank_id] = (x_sc[wdg_endNumber][tank_id]/ratios^2) + x_sc[wdg_endNumber][tank_id] = (x_sc[wdg_endNumber][tank_id]/ratios_wdg1^2) # g_sh always with respect to wdg #1 always if wdg_endNumber == 1 @@ -952,8 +955,8 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data cmag = sqrt(exct_current^2 - pctNoLoadLoss^2)/100 b_sh_tank = -(cmag*snom_wdg)/(vnom_wdg^2) # data is measured externally, but we now refer it to the internal side - g_sh[tank_id] = g_sh_tank*ratios^2 - b_sh[tank_id] = b_sh_tank*ratios^2 + g_sh[tank_id] = g_sh_tank*ratios_wdg1^2 + b_sh[tank_id] = b_sh_tank*ratios_wdg1^2 end # configuration From 62913c1540d4e482f79ffcbd7e14d3d5518e548e Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 15 May 2025 16:01:31 -0600 Subject: [PATCH 69/99] FIX: Fix and refactor computation of resistances and reactances for transformers with and without tanks. Windings were being assigned 0.0 resistance and ony for winding number 1. --- src/data_model/transformations/ravens2math.jl | 98 +++++++++++-------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index b83137c30..46de0d3b9 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -640,21 +640,38 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Transformer data for each winding vnom[wdg_endNumber] = wdgs[wdg_endNumber]["PowerTransformerEnd.ratedU"] snom[wdg_endNumber] = wdgs[wdg_endNumber]["PowerTransformerEnd.ratedS"] + zbase[wdg_endNumber] = (vnom[wdg_endNumber]^2)/snom[wdg_endNumber] # Add vnom info to vbases data_math["settings"]["vbases_network"][string(bus)] = deepcopy(vnom[wdg_endNumber]/voltage_scale_factor) - # resistance - transf_star_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.StarImpedance", Dict()) - transf_mesh_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.MeshImpedance", Dict()) + # Transformer impedance when values are missing for other windings. + xfmr_star_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.StarImpedance", Dict()) + xfmr_star_impedance_r = get(xfmr_star_impedance, "TransformerStarImpedance.r", 0.0) + + if (xfmr_star_impedance == Dict()) + xfmr_star_impedance_wdg1 = get(wdgs[1], "TransformerEnd.StarImpedance", Dict()) + if (xfmr_star_impedance_wdg1 != Dict()) + xfmr_star_impedance_r = get(xfmr_star_impedance_wdg1, "TransformerStarImpedance.r", 0.0).*(zbase[wdg_endNumber]/zbase[1]) + end + end - r_s[wdg_endNumber] = get(wdgs[wdg_endNumber], "PowerTransformerEnd.r", - get(transf_star_impedance, "TransformerStarImpedance.r", - get(transf_mesh_impedance, "TransformerMeshImpedance.r", 0.0))./2) # divide by 2 because XFRMR Star Resistance includes both windings. + xfmr_mesh_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.MeshImpedance", Dict()) + xfmr_mesh_impedance_r = get(xfmr_mesh_impedance, "TransformerMeshImpedance.r", 0.0) + + if (xfmr_mesh_impedance == Dict()) + xfmr_mesh_impedance_wdg1 = get(wdgs[1], "TransformerEnd.MeshImpedance", Dict()) + if (xfmr_mesh_impedance_wdg1 != Dict()) + xfmr_mesh_impedance_r = get(xfmr_mesh_impedance_wdg1, "TransformerMeshImpedance.r", 0.0).*(zbase[wdg_endNumber]/zbase[1]) + end + end + + # resistance + r_s[wdg_endNumber] = get(wdgs[wdg_endNumber], "PowerTransformerEnd.r", (xfmr_star_impedance_r != 0.0 ? xfmr_star_impedance_r : xfmr_mesh_impedance_r)./2) # divide by 2 because XFRMR Star Resistance includes both windings. # reactance - x_sc[wdg_endNumber] = get(transf_mesh_impedance, "TransformerMeshImpedance.x", - get(transf_star_impedance, "TransformerStarImpedance.x", 0.0)) + x_sc[wdg_endNumber] = get(xfmr_mesh_impedance, "TransformerMeshImpedance.x", + get(xfmr_star_impedance, "TransformerStarImpedance.x", 0.0)) # admittance transf_core_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.CoreAdmittance", Dict()) @@ -856,6 +873,8 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # init vnom for all windings vnom = zeros(Float64, nrw) + ratios = zeros(Float64, nrw) + zbase = zeros(Float64, nrw) # temp store previous for checking nodes_prev = [] @@ -869,9 +888,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data tm_fix = Vector{Vector{Bool}}(fill(ones(Bool, nphases), nrw)) tm_step = Vector{Vector{Float64}}(fill(fill(1/32, nphases), nrw)) - # Init transf_star_impedance - transf_star_impedance = Dict() - for tank_id in 1:ntanks # Get wdg data @@ -907,56 +923,53 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # transformer tank end info. transf_end_info = tank_asset_data["PowerTransformerInfo.TransformerTankInfos"][tank_asset_name]["TransformerTankInfo.TransformerEndInfos"] - vnom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedU"] + vnom[wdg_endNumber] = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedU"] snom_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.ratedS"] - zbase = (vnom_wdg^2) / snom_wdg - ratios = vnom_wdg/voltage_scale_factor - ratios_wdg1 = ratios + zbase[wdg_endNumber] = (vnom[wdg_endNumber]^2) / snom_wdg - # assign vnom_wdg to vnom for transformer - vnom[wdg_endNumber] = vnom_wdg + # Compute voltage ratios + ratios[wdg_endNumber] = vnom[wdg_endNumber]/voltage_scale_factor # Transformer star impedance when values are missing for other windings. - if (wdg_endNumber != 1) - ratios_wdg1 = vnom[1]/voltage_scale_factor # HV wdg1 - if (transf_star_impedance != Dict()) - transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", transf_end_info[wdg_endNumber-1]["TransformerEndInfo.TransformerStarImpedance"]) - else - transf_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) + xfmr_star_impedance = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.TransformerStarImpedance", Dict()) + xfmr_star_impedance_r = get(xfmr_star_impedance, "TransformerStarImpedance.r", 0.0) + if (xfmr_star_impedance == Dict()) + xfmr_star_impedance_wdg1 = get(transf_end_info[1], "TransformerEndInfo.TransformerStarImpedance", Dict()) + if (xfmr_star_impedance_wdg1 != Dict()) + xfmr_star_impedance_r = get(xfmr_star_impedance_wdg1, "TransformerStarImpedance.r", 0.0).*(zbase[wdg_endNumber]/zbase[1]) end end # resistance computation - r_s[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", - get(transf_star_impedance, "TransformerStarImpedance.r", 0.0)./2) # divide by 2 because XFRMR Star Resistance includes both windings. + r_s[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.r", xfmr_star_impedance_r./2) # divide by 2 because XFRMR Star Resistance includes both windings. # reactance computation x_sc[wdg_endNumber][tank_id] = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.x", - get(transf_star_impedance, "TransformerStarImpedance.x", 0.0)) + get(xfmr_star_impedance, "TransformerStarImpedance.x", 0.0)) # -- alternative computation of xsc using sc tests if haskey(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndShortCircuitTests") leak_impedance_wdg = transf_end_info[wdg_endNumber]["TransformerEndInfo.EnergisedEndShortCircuitTests"][1]["ShortCircuitTest.leakageImpedance"] - rs_pct = (r_s[wdg_endNumber][tank_id]/zbase)*100.0 - x_sc[wdg_endNumber][tank_id] = (sqrt((leak_impedance_wdg/zbase)^2 - (rs_pct+rs_pct)^2)/100)*zbase + rs_pct = (r_s[wdg_endNumber][tank_id]/zbase[wdg_endNumber])*100.0 + x_sc[wdg_endNumber][tank_id] = (sqrt((leak_impedance_wdg/zbase[wdg_endNumber])^2 - (rs_pct+rs_pct)^2)/100)*zbase[wdg_endNumber] end # RS and XSC computation based on ratios - r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios^2 - x_sc[wdg_endNumber][tank_id] = (x_sc[wdg_endNumber][tank_id]/ratios_wdg1^2) + r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios[wdg_endNumber]^2 + x_sc[wdg_endNumber][tank_id] = (x_sc[wdg_endNumber][tank_id]/ratios[1]^2) # w.r.t wdg1 # g_sh always with respect to wdg #1 always if wdg_endNumber == 1 transf_end_noloadtest = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndNoLoadTests", [Dict()]) loss = get(transf_end_noloadtest[1], "NoLoadTest.loss", 0.0) - g_sh_tank = (loss/(0.01*(snom_wdg/1000.0)))/zbase + g_sh_tank = (loss/(0.01*(snom_wdg/1000.0)))/zbase[wdg_endNumber] pctNoLoadLoss = loss*100.0/(0.01*(snom_wdg/1000.0)) exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", pctNoLoadLoss) cmag = sqrt(exct_current^2 - pctNoLoadLoss^2)/100 - b_sh_tank = -(cmag*snom_wdg)/(vnom_wdg^2) + b_sh_tank = -(cmag*snom_wdg)/(vnom[wdg_endNumber]^2) # data is measured externally, but we now refer it to the internal side - g_sh[tank_id] = g_sh_tank*ratios_wdg1^2 - b_sh[tank_id] = b_sh_tank*ratios_wdg1^2 + g_sh[tank_id] = g_sh_tank*ratios[1]^2 # w.r.t wdg1 + b_sh[tank_id] = b_sh_tank*ratios[1]^2 # w.r.t wdg1 end # configuration @@ -970,7 +983,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data end # add sm_ub if greater than existing (assumes the greatest value as the ratings for all phases in wdg) - semerg_wdg = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.emergencyS", Inf) + semerg_wdg = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.emergencyS", get(transf_end_info[wdg_endNumber], "TransformerEndInfo.ratedS", Inf)) if semerg_wdg > sm_ub[wdg_endNumber] sm_ub[wdg_endNumber] = semerg_wdg end @@ -1080,10 +1093,11 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data end # wdg i, tank 1 - assumes tank 1 always exists - r_s = [r_s[i][1] for i in 1:nrw] - x_sc = [x_sc[1][1]] # wrt to wdg 1 - g_sh = g_sh[1] # wrt to wdg 1 - b_sh = b_sh[1] # wrt to wdg 1 + r_s = [sum(r_s[i]) for i in 1:nrw] + x_sc = [sum(x_sc[i]) for i in 1:nrw] # sum the x_sc for all tanks per wdg + x_sc = [x_sc[1]] # get x_sc wrt to wdg 1 + g_sh = sum(g_sh) # wrt to wdg 1 + b_sh = sum(b_sh) # wrt to wdg 1 # convert x_sc from list of upper triangle elements to an explicit dict y_sh = g_sh + im*b_sh @@ -1099,6 +1113,10 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Build loss model transformer_t_bus_w = _build_loss_model!(data_math, name, to_map, r_s, z_sc, y_sh, connections[1]; nphases=nphases, status=status) + # Compute total upper bounds based on number of tanks + sm_ub = sm_ub.*ntanks + cm_ub = cm_ub.*ntanks + # Mathematical model for transformer for wdg_id in 1:nrw # 2-WINDING TRANSFORMER @@ -1897,7 +1915,7 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di math_obj["current_rating"] = fill(get(swinfo_data, "SwitchInfo.breakingCapacity", get(swinfo_data, "SwitchInfo.ratedCurrent", Inf)), nphases) math_obj["sm_ub"] = math_obj["current_rating"] .* get(swinfo_data, "SwitchInfo.ratedVoltage", Inf) else - math_obj["current_rating"] = fill(get(swinfo_data, "SwitchInfo.breakingCapacity", get(swinfo_data, "SwitchInfo.ratedCurrent", Inf)), nphases) + math_obj["current_rating"] = fill(get(ravens_obj, "Switch.ratedCurrent", Inf)) math_obj["sm_ub"] = math_obj["current_rating"] .* get(ravens_obj, "Switch.ratedVoltage", Inf) end From d022615c3e8274dcda5c46a596f53dabbecca4f7 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 15 May 2025 17:37:46 -0600 Subject: [PATCH 70/99] FIX: computation of b_sh and g_sh for TransformerTanks. --- src/data_model/transformations/ravens2math.jl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 46de0d3b9..fdc1f311f 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -958,15 +958,16 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data r_s[wdg_endNumber][tank_id] = r_s[wdg_endNumber][tank_id]/ratios[wdg_endNumber]^2 x_sc[wdg_endNumber][tank_id] = (x_sc[wdg_endNumber][tank_id]/ratios[1]^2) # w.r.t wdg1 - # g_sh always with respect to wdg #1 always + # b_sh and g_sh are always w.r.t wdg #1 if wdg_endNumber == 1 transf_end_noloadtest = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndNoLoadTests", [Dict()]) loss = get(transf_end_noloadtest[1], "NoLoadTest.loss", 0.0) - g_sh_tank = (loss/(0.01*(snom_wdg/1000.0)))/zbase[wdg_endNumber] - pctNoLoadLoss = loss*100.0/(0.01*(snom_wdg/1000.0)) + pctNoLoadLoss = (loss*100)/(snom_wdg/1000.0) # TODO: if loss is in kW, then you need snom_wdg/1000.0, if is in Watts, then snom_wdg + noLoadLoss = pctNoLoadLoss/100.0 + g_sh_tank = noLoadLoss/zbase[wdg_endNumber] exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", pctNoLoadLoss) - cmag = sqrt(exct_current^2 - pctNoLoadLoss^2)/100 - b_sh_tank = -(cmag*snom_wdg)/(vnom[wdg_endNumber]^2) + cmag = sqrt(exct_current^2 - pctNoLoadLoss^2)/100 # cmag = pctImag/100 = sqrt(pctIexc^2 - pctNoLoadLoss^2)/100 + b_sh_tank = -(cmag)/zbase[wdg_endNumber] # data is measured externally, but we now refer it to the internal side g_sh[tank_id] = g_sh_tank*ratios[1]^2 # w.r.t wdg1 b_sh[tank_id] = b_sh_tank*ratios[1]^2 # w.r.t wdg1 From afbfd6269d9f680eb8d3afd16688e228fe4ffcb0 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 19 May 2025 09:19:12 -0600 Subject: [PATCH 71/99] DOC: removed TODO for noloadloss unit in ravens2math. --- src/data_model/transformations/ravens2math.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index fdc1f311f..275b01ec0 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -962,7 +962,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data if wdg_endNumber == 1 transf_end_noloadtest = get(transf_end_info[wdg_endNumber], "TransformerEndInfo.EnergisedEndNoLoadTests", [Dict()]) loss = get(transf_end_noloadtest[1], "NoLoadTest.loss", 0.0) - pctNoLoadLoss = (loss*100)/(snom_wdg/1000.0) # TODO: if loss is in kW, then you need snom_wdg/1000.0, if is in Watts, then snom_wdg + pctNoLoadLoss = (loss*100)/(snom_wdg/1000.0) # loss is in kW, thus snom_wdg/1000.0 noLoadLoss = pctNoLoadLoss/100.0 g_sh_tank = noLoadLoss/zbase[wdg_endNumber] exct_current = get(transf_end_noloadtest[1], "NoLoadTest.excitingCurrent", pctNoLoadLoss) From c8d6fcc742837f666df78d333cf2702b8f132cf7 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 20 May 2025 14:30:35 -0600 Subject: [PATCH 72/99] FIX: get func missing when getting p and q from load forecast EnergyConsumerPhase. --- src/data_model/transformations/ravens2math.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 275b01ec0..46ba1a614 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1298,8 +1298,8 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r if haskey(ravens_obj, "EnergyConsumer.EnergyConsumerPhase") for id in 1:nphases phase_info = ravens_obj["EnergyConsumer.EnergyConsumerPhase"][id] - active_power[id] = phase_info["EnergyConsumerPhase.p"] - reactive_power[id] = phase_info["EnergyConsumerPhase.q"] + active_power[id] = get(phase_info, "EnergyConsumerPhase.p", 0.0) + reactive_power[id] = get(phase_info, "EnergyConsumerPhase.q", 0.0) end else active_power = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / (power_scale_factor*nphases), nphases) From c7079eecf013eeea5a3832b5abc6926a5898f278 Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 21 May 2025 09:37:50 -0600 Subject: [PATCH 73/99] ADD: check for mathematical model type before instantiating model. --- src/data_model/transformations/ravens2math.jl | 2 -- src/prob/common.jl | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 46ba1a614..951e9c719 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -41,8 +41,6 @@ function transform_data_model_ravens( correct_network_data::Bool=true, )::Dict{String,Any} - current_data_model = get(data, "data_model", MATHEMATICAL) - data_math = _map_ravens2math( data; multinetwork=multinetwork, diff --git a/src/prob/common.jl b/src/prob/common.jl index 36ffbc65b..d4cec9dcc 100644 --- a/src/prob/common.jl +++ b/src/prob/common.jl @@ -143,16 +143,17 @@ function instantiate_mc_model_ravens( kwargs... ) - @info "Converting CIM-RAVENS data model to MATHEMATICAL first to build JuMP model" - - data = transform_data_model_ravens( - data; - multinetwork=multinetwork, - global_keys=global_keys, - ravens2math_extensions=ravens2math_extensions, - ravens2math_passthrough=ravens2math_passthrough, - make_pu_extensions=make_pu_extensions, + if !ismath(data) + @info "Converting CIM-RAVENS data model to MATHEMATICAL first to build JuMP model" + data = transform_data_model_ravens( + data; + multinetwork=multinetwork, + global_keys=global_keys, + ravens2math_extensions=ravens2math_extensions, + ravens2math_passthrough=ravens2math_passthrough, + make_pu_extensions=make_pu_extensions, ) + end return _IM.instantiate_model( data, From 36f4fa8746a06fce8343a4f042707133b7128c47 Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 21 May 2025 10:05:54 -0600 Subject: [PATCH 74/99] ADD: util function to apply voltage bounds to MATH model in pu. --- src/data_model/utils_ravens.jl | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 7f831563e..34f758b6f 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -135,3 +135,29 @@ function _calc_shunt_admittance_matrix(terminals, b) return _shunt_matrix end + + +""" + apply_voltage_bounds_math!(data::Dict{String,<:Any}; vm_lb::Union{Real,Missing}=0.9, vm_ub::Union{Real,Missing}=1.1) + +add voltage bounds to all buses based on per-unit upper (`vm_ub`) and lower (`vm_lb`), in MATHEMATICAL. +""" +function apply_voltage_bounds_math!(data::Dict{String,<:Any}; vm_lb::Union{Real,Missing}=0.9, vm_ub::Union{Real,Missing}=1.1) + if ismultinetwork(data) + for (_, nw_data) in data["nw"] + for (_, bus_data) in nw_data["bus"] + if (bus_data["bus_type"] != 3) + bus_data["vmin"] = ones(length(bus_data["vmin"])).*vm_lb + bus_data["vmax"] = ones(length(bus_data["vmax"])).*vm_ub + end + end + end + else + for (_, bus_data) in data["bus"] + if (bus_data["bus_type"] != 3) + bus_data["vmin"] = ones(length(bus_data["vmin"])).*vm_lb + bus_data["vmax"] = ones(length(bus_data["vmax"])).*vm_ub + end + end + end +end From bf1e6000258857651eeb5d8eb70ebd2013b4e7ab Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 29 May 2025 14:59:15 -0600 Subject: [PATCH 75/99] REF: switch state and dispatchable information parsing from RAVENS JSON format. --- src/data_model/transformations/ravens2math.jl | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 951e9c719..63229754c 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1900,12 +1900,23 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di math_obj["status"] = status = math_obj["status"] == true ? 1 : 0 # State - sw_state = get(ravens_obj, "Switch.open", false) - sw_state = sw_state == false ? CLOSED : OPEN + sw_state = CLOSED + if (haskey(ravens_obj, "Switch.SwitchPhase")) + sw_state = get(ravens_obj["Switch.SwitchPhase"][1], "SwitchPhase.closed", true) + sw_state = sw_state == true ? CLOSED : OPEN + else + sw_state = get(ravens_obj, "Switch.open", false) + sw_state = sw_state == false ? CLOSED : OPEN + end math_obj["state"] = Int(sw_state) - # TODO: Dispatchable - math_obj["dispatchable"] = Int(get(ravens_obj, "dispatchable", YES)) + # Dispatchable + sw_type = get(ravens_obj, "Ravens.cimObjectType", "Switch") + if (sw_type == "Fuse" || sw_type == "Jumper") + math_obj["dispatchable"] = Int(NO) + else + math_obj["dispatchable"] = Int(YES) + end # Current and Power Limits if haskey(ravens_obj, "PowerSystemResource.AssetDatasheet") From f094e372e51447caf11baf91df340ca644415c7a Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 19 Jun 2025 13:48:30 -0600 Subject: [PATCH 76/99] REF: switch status definition to assume open when not specified. --- src/data_model/transformations/ravens2math.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 63229754c..ebecbf92c 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1896,17 +1896,17 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di end # Status - math_obj["status"] = get(ravens_obj, "Equipment.inService", true) - math_obj["status"] = status = math_obj["status"] == true ? 1 : 0 + status = get(ravens_obj, "Equipment.inService", true) + math_obj["status"] = status == true ? 1 : 0 # State sw_state = CLOSED if (haskey(ravens_obj, "Switch.SwitchPhase")) - sw_state = get(ravens_obj["Switch.SwitchPhase"][1], "SwitchPhase.closed", true) - sw_state = sw_state == true ? CLOSED : OPEN + sw_closed = get(ravens_obj["Switch.SwitchPhase"][1], "SwitchPhase.closed", false) + sw_state = sw_closed == true ? CLOSED : OPEN else - sw_state = get(ravens_obj, "Switch.open", false) - sw_state = sw_state == false ? CLOSED : OPEN + sw_open = get(ravens_obj, "Switch.open", true) + sw_state = sw_open == false ? CLOSED : OPEN end math_obj["state"] = Int(sw_state) From 961153d725f25a2359e5e396a7839bbc5fad01f3 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 23 Jun 2025 10:27:26 -0600 Subject: [PATCH 77/99] REF: switch and fuses open or close by default. --- src/data_model/transformations/ravens2math.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index ebecbf92c..cdb402014 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1902,10 +1902,10 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di # State sw_state = CLOSED if (haskey(ravens_obj, "Switch.SwitchPhase")) - sw_closed = get(ravens_obj["Switch.SwitchPhase"][1], "SwitchPhase.closed", false) + sw_closed = get(ravens_obj["Switch.SwitchPhase"][1], "SwitchPhase.closed", true) sw_state = sw_closed == true ? CLOSED : OPEN else - sw_open = get(ravens_obj, "Switch.open", true) + sw_open = get(ravens_obj, "Switch.open", false) sw_state = sw_open == false ? CLOSED : OPEN end math_obj["state"] = Int(sw_state) From 3837480ae1f40afff507ac15b3516dfe1f70f1b2 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 26 Jun 2025 16:13:47 -0600 Subject: [PATCH 78/99] TEST: basemva=1 --- src/data_model/transformations/ravens2math.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index cdb402014..e1f18c1ba 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -72,7 +72,7 @@ function _map_ravens2math( _data_ravens = deepcopy(data_ravens) # TODO: Add settings (defaults) - basemva = 100 + basemva = 1 _settings = Dict("sbase_default" => basemva * 1e3, "voltage_scale_factor" => 1e3, "power_scale_factor" => 1e3, From 2f154b68f607e667dd9dc6a5ed3fbf10ee476c45 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 30 Jun 2025 13:07:09 -0600 Subject: [PATCH 79/99] FIX: parsing errors derived from 3 winding xfrmrs and single-phase lines connected to vsource. --- src/data_model/transformations/ravens2math.jl | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index e1f18c1ba..c6594028c 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -744,7 +744,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # data is measured externally, but we now refer it to the internal side - some values are referred to wdg 1 ratios = vnom/voltage_scale_factor - x_sc = (x_sc[1]./ratios[1]^2) + x_sc = (x_sc./ratios[1]^2) r_s = r_s./ratios.^2 g_sh = g_sh[1]*ratios[1]^2 b_sh = b_sh[1]*ratios[1]^2 @@ -1423,7 +1423,6 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav # Handle phase-specific or three-phase connection connections = Vector{Int64}() - nconductors = length(get(ravens_obj, "EnergySource.EnergySourcePhase", bus_conn["terminals"])) if haskey(ravens_obj, "EnergySource.EnergySourcePhase") for phase_info in ravens_obj["EnergySource.EnergySourcePhase"] @@ -1441,6 +1440,18 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav end end + # Check that connections and bus terminals have the same number of phases, if not, assume connections is correct + if (bus_conn["terminals"] != math_obj["connections"]) + bus_conn["terminals"] = math_obj["connections"] + nphases = length(bus_conn["terminals"]) + # Add vmin and vmax to bus if missing (correct number of terminals) + bus_conn["vmin"] = fill(0.0, nphases) + bus_conn["vmax"] = fill(Inf, nphases) + bus_conn["grounded"] = zeros(Bool, nphases) + end + + nconductors = length(get(ravens_obj, "EnergySource.EnergySourcePhase", bus_conn["terminals"])) + # Generator status and configuration math_obj["gen_status"] = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true math_obj["gen_status"] = math_obj["gen_status"] == true ? 1 : 0 From d412503bab34487c0ba01bf439e1f24a8ee2a5cf Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 2 Jul 2025 11:52:45 -0600 Subject: [PATCH 80/99] REF: source id names for MATH objects based on RAVENS names. --- src/data_model/transformations/ravens2math.jl | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index c6594028c..ccd94ade2 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -240,11 +240,11 @@ function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data for (name, ravens_obj) in connectivity_nodes index = length(data_math["bus"]) + 1 - math_obj = _init_math_obj_ravens("bus", name, ravens_obj, index; pass_props=pass_props) + math_obj = _init_math_obj_ravens("ConnectivityNode", name, ravens_obj, index; pass_props=pass_props) # Set basic bus properties math_obj["bus_i"] = index - math_obj["source_id"] = "bus.$name" + math_obj["source_id"] = "ConnectivityNode.$name" math_obj["bus_type"] = 1 # Default bus_type, will be modified as needed math_obj["vm_pair_lb"] = Tuple{Any, Any, Real}[] math_obj["vm_pair_ub"] = Tuple{Any, Any, Real}[] @@ -284,7 +284,7 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: conductors = data_ravens["PowerSystemResource"]["Equipment"]["ConductingEquipment"]["Conductor"] for (name, ravens_obj) in get(conductors, "ACLineSegment", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj_ravens("conductor", name, ravens_obj, length(data_math["branch"]) + 1; pass_props=pass_props) + math_obj = _init_math_obj_ravens("ACLineSegment", name, ravens_obj, length(data_math["branch"]) + 1; pass_props=pass_props) nconds = length(ravens_obj["ACLineSegment.ACLineSegmentPhase"]) # number of conductors/wires nphases = 0 # init number of phases terminals = ravens_obj["ConductingEquipment.Terminals"] @@ -792,7 +792,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Transformer Object transformer_2wa_obj = Dict{String,Any}( "name" => "_virtual_transformer.$name.$wdg_id", - "source_id" => "_virtual_transformer.transformer.$name.$wdg_id", + "source_id" => "_virtual_transformer.PowerTransformer.$name.$wdg_id", "f_bus" => data_math["bus_lookup"][f_node_wdgterm], "t_bus" => transformer_t_bus_w[wdg_id], "tm_nom" => tm_nom, @@ -1138,7 +1138,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Transformer Object transformer_2wa_obj = Dict{String,Any}( "name" => "_virtual_transformer.$name.$wdg_id", - "source_id" => "_virtual_transformer.transformer.$name.$wdg_id", + "source_id" => "_virtual_transformer.PowerTransformer.$name.$wdg_id", "f_bus" => data_math["bus_lookup"][nodes[wdg_id]], "t_bus" => transformer_t_bus_w[wdg_id], "tm_nom" => tm_nom, @@ -1194,7 +1194,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r voltage_scale_factor_sqrt3 = voltage_scale_factor * sqrt(3) for (name, ravens_obj) in get(energy_connections, "EnergyConsumer", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj_ravens("energy_consumer", name, ravens_obj, length(data_math["load"]) + 1; pass_props=pass_props) + math_obj = _init_math_obj_ravens("EnergyConsumer", name, ravens_obj, length(data_math["load"]) + 1; pass_props=pass_props) # Set the load bus based on connectivity node connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) @@ -1411,7 +1411,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav voltage_scale_factor_sqrt3 = voltage_scale_factor * sqrt(3) for (name, ravens_obj) in get(energy_connections, "EnergySource", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj_ravens("energy_source", name, ravens_obj, length(data_math["gen"]) + 1; pass_props=pass_props) + math_obj = _init_math_obj_ravens("EnergySource", name, ravens_obj, length(data_math["gen"]) + 1; pass_props=pass_props) math_obj["name"] = "_virtual_gen.energy_source.$name" # Get connectivity node info (bus info) @@ -1481,7 +1481,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav # Control mode and source ID math_obj["control_mode"] = Int(get(ravens_obj, "EnergySource.connectionKind", ISOCHRONOUS)) - math_obj["source_id"] = "energy_source.$name" + math_obj["source_id"] = "EnergySource.$name" # Add generator cost model _add_gen_cost_model!(math_obj, ravens_obj) @@ -1500,7 +1500,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav "index" => length(data_math["bus"]) + 1, "terminals" => math_obj["connections"], "grounded" => zeros(Bool, nphases), - "name" => "_virtual_bus.energy_source.$name", + "name" => "_virtual_bus.EnergySource.$name", "bus_type" => math_obj["gen_status"] == 0 ? 4 : math_obj["control_mode"] == Int(ISOCHRONOUS) ? 3 : 2, "vm" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), "va" => rad2deg.(_wrap_to_pi.([-2 * π / nphases * (i - 1) + get(ravens_obj, "EnergySource.voltageAngle", 0.0) for i in 1:nphases])), @@ -1508,15 +1508,15 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav "vmax" => fill(ravens_obj["EnergySource.voltageMagnitude"] / voltage_scale_factor_sqrt3, nphases), "vm_pair_lb" => deepcopy(get(ravens_obj, "EnergySource.vpairMin", Tuple{Any,Any,Real}[])), "vm_pair_ub" => deepcopy(get(ravens_obj, "EnergySource.vpairMax", Tuple{Any,Any,Real}[])), - "source_id" => "energy_source.$name", + "source_id" => "EnergySource.$name", ) math_obj["gen_bus"] = bus_obj["bus_i"] data_math["bus"]["$(bus_obj["index"])"] = bus_obj branch_obj = Dict( - "name" => "_virtual_branch.energy_source.$name", - "source_id" => "energy_source.$name", + "name" => "_virtual_branch.EnergySource.$name", + "source_id" => "EnergySource.$name", "f_bus" => bus_obj["bus_i"], "t_bus" => gen_bus, "f_connections" => math_obj["connections"], @@ -1571,7 +1571,7 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ for (name, ravens_obj) in get(regulating_cond_eq, "RotatingMachine", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj_ravens("rotating_machine", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) + math_obj = _init_math_obj_ravens("RotatingMachine", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) # Connections/phases obtained from Terminals connections = _phasecode_map[get(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases", "PhaseCode.ABC")] @@ -1687,7 +1687,7 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data if (pec_type == "PhotoVoltaicUnit") - math_obj = _init_math_obj_ravens("photovoltaic_unit", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) + math_obj = _init_math_obj_ravens("PhotoVoltaicUnit", name, ravens_obj, length(data_math["gen"])+1; pass_props=pass_props) # Connections/phases connections = _phasecode_map[get(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases", "PhaseCode.ABC")] @@ -1773,7 +1773,7 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data elseif (pec_type == "BatteryUnit") - math_obj = _init_math_obj_ravens("storage", name, ravens_obj, length(data_math["storage"])+1; pass_props=pass_props) + math_obj = _init_math_obj_ravens("BatteryUnit", name, ravens_obj, length(data_math["storage"])+1; pass_props=pass_props) # Connections/phases connections = _phasecode_map[get(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases", "PhaseCode.ABC")] @@ -1858,7 +1858,7 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di for (name, ravens_obj) in get(conducting_equipment, "Switch", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj_ravens("switch", name, ravens_obj, length(data_math["switch"])+1; pass_props=pass_props) + math_obj = _init_math_obj_ravens("Switch", name, ravens_obj, length(data_math["switch"])+1; pass_props=pass_props) # Terminals and phases terminals = ravens_obj["ConductingEquipment.Terminals"] @@ -1973,7 +1973,7 @@ function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data for (name, ravens_obj) in get(regulating_cond_eq, "ShuntCompensator", Dict{Any,Dict{String,Any}}()) - math_obj = _init_math_obj("shunt", name, ravens_obj, length(data_math["shunt"])+1; pass_props=pass_props) + math_obj = _init_math_obj("ShuntCompensator", name, ravens_obj, length(data_math["shunt"])+1; pass_props=pass_props) # Get connectivity node info (bus info) connectivity_node = _extract_name(ravens_obj["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]) From 0b2990cb2f865eada3779fde6f9b8bc75946ea45 Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 2 Jul 2025 13:09:46 -0600 Subject: [PATCH 81/99] ADD: dispatchability status of switch based on RAVENS locked bool. --- src/data_model/transformations/ravens2math.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index ccd94ade2..aa0f847dc 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1926,7 +1926,8 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di if (sw_type == "Fuse" || sw_type == "Jumper") math_obj["dispatchable"] = Int(NO) else - math_obj["dispatchable"] = Int(YES) + dispatch_locked = get(ravens_obj, "Switch.locked", false) + math_obj["dispatchable"] = dispatch_locked == true ? Int(NO) : Int(YES) end # Current and Power Limits From f9292509e57925375a521aa5d247ea64ef10266c Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 3 Jul 2025 14:19:33 -0600 Subject: [PATCH 82/99] ADD: support for PV forecast to be considered in multinetwork problems. Fixed a problem with load forecasts that require actual values. --- src/data_model/transformations/ravens2math.jl | 70 ++++++++++++++----- src/data_model/utils_ravens.jl | 24 +++---- 2 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index aa0f847dc..949df3e54 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1324,10 +1324,10 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r unit_symbol = schdl["BasicIntervalSchedule.value1Unit"] value1_unit = lowercase(unit_symbol[findfirst(isequal('.'), unit_symbol) + 1:end]) if value1_unit == "w" - math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / power_scale_factor, nphases) + math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / (power_scale_factor*nphases), nphases) end if value1_unit == "var" - math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / power_scale_factor, nphases) + math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value1", 0.0) * value1_multiplier / (power_scale_factor*nphases), nphases) end end @@ -1335,10 +1335,10 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r unit_symbol = schdl["BasicIntervalSchedule.value2Unit"] value2_unit = lowercase(unit_symbol[findfirst(isequal('.'), unit_symbol) + 1:end]) if value2_unit == "w" - math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / power_scale_factor, nphases) + math_obj["pd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / (power_scale_factor*nphases), nphases) end if value2_unit == "var" - math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / power_scale_factor, nphases) + math_obj["qd"] = fill(get(schdl["EnergyConsumerSchedule.RegularTimePoints"][nw], "RegularTimePoint.value2", 0.0) * value2_multiplier / (power_scale_factor*nphases), nphases) end end @@ -1741,22 +1741,60 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data # TODO: refactor the calculation of N when connections and configuration issues are solved. N = math_obj["configuration"]==DELTA && length(connections)==1 ? 1 : _infer_int_dim(connections, math_obj["configuration"], false) # if solar is delta-connected to triplex node, N can be equal to 1 - # Set pmax - if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") - math_obj["pmax"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + # Set pg/pmax and qg/qmax (w/ multinetwork support) + if nw==0 + if !haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP") + math_obj["pmax"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedS", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + else + math_obj["pmax"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + end + math_obj["pg"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0) * -ones(nconductors) ./ nconductors)./(power_scale_factor) else - math_obj["pmax"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.maxP", Inf) * ones(nconductors)) ./ nconductors)./(power_scale_factor) + + # Get timeseries schedule + if haskey(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PhotoVoltaicUnit.GenerationProfile") + + # initialization of pg values for multiplier case + pmax = zeros(Float64, nconductors) + pg = zeros(Float64, nconductors) + pmax = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0) * -ones(nconductors) ./ nconductors)./(power_scale_factor) + pg = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0) * -ones(nconductors) ./ nconductors)./(power_scale_factor) + + curve_name = _extract_name(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"]["PhotoVoltaicUnit.GenerationProfile"]) + curve = data_ravens["Curve"][curve_name] + + # multiplier modifier + if haskey(curve, "Curve.y1Multiplier") + value1_multiplier = _multipliers_map[curve["Curve.y1Multiplier"]] + else + value1_multiplier = 1.0 + end + + # Actual values + if haskey(curve, "Curve.y1Unit") + unit_symbol = curve["Curve.y1Unit"] + value1_unit = lowercase(unit_symbol[findfirst(isequal('.'), unit_symbol) + 1:end]) + if value1_unit == "w" + math_obj["pg"] = (get(curve["Curve.CurveDatas"][nw], "CurveData.y1value", 0.0) * value1_multiplier * -ones(nconductors) ./ nconductors)./(power_scale_factor) + math_obj["pmax"] = math_obj["pg"].*-1 + end + end + + # Multipliers instead of actual values + if !haskey(curve, "Curve.y1Unit") + math_obj["pg"] = -get(curve["Curve.CurveDatas"][nw], "CurveData.y1value", 1.0) .* pg + math_obj["pmax"] = math_obj["pg"].*-1 + end + + else + @error("No timeseries, dispatch profile or multinetwork information found!") + end + end - # Set pmin - math_obj["pmin"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.minP", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set qmin + + math_obj["pmin"] = ((get(ravens_obj["PowerElectronicsConnection.PowerElectronicsUnit"], "PowerElectronicsUnit.minP", 0.0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) math_obj["qmin"] = ((get(ravens_obj, "PowerElectronicsConnection.minQ", -0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - # Set qmax math_obj["qmax"] = ((get(ravens_obj, "PowerElectronicsConnection.maxQ", 0) * ones(nconductors)) ./ nconductors)./(power_scale_factor) - - - # Set pg and qg - math_obj["pg"] = (get(ravens_obj, "PowerElectronicsConnection.p", 0.0) * -ones(nconductors) ./ nconductors)./(power_scale_factor) math_obj["qg"] = (get(ravens_obj, "PowerElectronicsConnection.q", 0.0) * -ones(nconductors) ./ nconductors)./(power_scale_factor) # TODO: add a polynomial parameters to be added to gen cost diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 34f758b6f..130bbb4a5 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -20,18 +20,18 @@ _phase_map = Dict( ) const _multipliers_map = Dict( - "m" => 1e-3, - "c" => 1e-2, - "d" => 1e-1, - "da" => 1e1, - "h" => 1e2, - "k" => 1e3, - "M" => 1e6, - "G" => 1e9, - "T" => 1e12, - "P" => 1e15, - "E" => 1e18, - "Z" => 1e21 + "UnitMultiplier.m" => 1e-3, + "UnitMultiplier.c" => 1e-2, + "UnitMultiplier.d" => 1e-1, + "UnitMultiplier.da" => 1e1, + "UnitMultiplier.h" => 1e2, + "UnitMultiplier.k" => 1e3, + "UnitMultiplier.M" => 1e6, + "UnitMultiplier.G" => 1e9, + "UnitMultiplier.T" => 1e12, + "UnitMultiplier.P" => 1e15, + "UnitMultiplier.E" => 1e18, + "UnitMultiplier.Z" => 1e21 ) From fd3dc6f53acfd173d0342f4d13c3c54a52061380 Mon Sep 17 00:00:00 2001 From: David M Fobes Date: Wed, 9 Jul 2025 08:56:21 -0600 Subject: [PATCH 83/99] WIP: add base voltage calculator for ravens model --- Project.toml | 2 + src/PowerModelsDistribution.jl | 1 + src/data_model/transformations/ravens2math.jl | 4 +- src/data_model/utils_ravens.jl | 113 ++++++++++++++++++ 4 files changed, 119 insertions(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 278cb445f..47e4fdbe0 100644 --- a/Project.toml +++ b/Project.toml @@ -20,6 +20,7 @@ PolyhedralRelaxations = "2e741578-48fa-11ea-2d62-b52c946f73a0" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] CSV = "0.8.5, 0.9, 0.10" @@ -34,6 +35,7 @@ LoggingExtras = "0.4.7, 1" PolyhedralRelaxations = "0.3.5" SCS = "0.9, 1.0, 1.1" SpecialFunctions = "2" +UUIDs = "1.11.0" julia = "1.6" [extras] diff --git a/src/PowerModelsDistribution.jl b/src/PowerModelsDistribution.jl index 77669ba5f..eef595b50 100644 --- a/src/PowerModelsDistribution.jl +++ b/src/PowerModelsDistribution.jl @@ -24,6 +24,7 @@ module PowerModelsDistribution import LinearAlgebra import Statistics import SparseArrays + import UUIDs import LinearAlgebra: diagm, factorize import Statistics: mean, std diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 949df3e54..57bc3d565 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -71,6 +71,8 @@ function _map_ravens2math( _data_ravens = deepcopy(data_ravens) + add_base_voltages!(_data_ravens; overwrite=false) + # TODO: Add settings (defaults) basemva = 1 _settings = Dict("sbase_default" => basemva * 1e3, @@ -1179,7 +1181,7 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data # Checks and calculates voltage bases for elements that do not have Voltage Bases. # TODO: Revise if this is the best way to be calculate vbases for missing elements - data_math["settings"]["vbases_buses"] = calc_math_voltage_bases(data_math, data_math["settings"]["vbases_network"])[1] # [1] bus_vbase, [2] edge_vbase + # data_math["settings"]["vbases_buses"] = calc_math_voltage_bases(data_math, data_math["settings"]["vbases_network"])[1] # [1] bus_vbase, [2] edge_vbase end diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 130bbb4a5..753fe55e8 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -161,3 +161,116 @@ function apply_voltage_bounds_math!(data::Dict{String,<:Any}; vm_lb::Union{Real, end end end + + + +function build_base_voltage_graphs(data::Dict{String,<:Any})::Tuple{Dict{Int,String}, Graphs.SimpleGraph} + nodes = Dict(cn => n for (n, cn) in enumerate(keys(data["ConnectivityNode"]))) + G = Graphs.SimpleGraph(length(nodes)) + + for edge_dicts in [ + _recursive_dict_get(data, ["PowerSystemResource", "Equipment", "ConductingEquipment", "Conductor", "ACLineSegment"], Dict()), + _recursive_dict_get(data, ["PowerSystemResource", "Equipment", "ConductingEquipment", "Switch"], Dict()) + ] + for (i, edge) in edge_dicts + Graphs.add_edge!(G, nodes[match(Regex("ConnectivityNode::'(.+)'"), edge["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]).captures[1]], nodes[match(Regex("ConnectivityNode::'(.+)'"), edge["ConductingEquipment.Terminals"][2]["Terminal.ConnectivityNode"]).captures[1]]) + end + end + + return Dict{Int,String}(n => cn for (cn, n) in nodes), G +end + +function find_voltages(data::Dict{String,<:Any})::Dict{String,Any} + voltages = Dict{String,Any}() + + for (i, es) in _recursive_dict_get(data, ["PowerSystemResource", "Equipment", "ConductingEquipment", "EnergyConnection", "EnergySource"], Dict()) + nominal_voltage = get(es, "EnergySource.nominalVoltage", missing) + if !ismissing(nominal_voltage) + voltages[match(Regex("ConnectivityNode::'(.+)'"), es["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]).captures[1]] = nominal_voltage + end + end + + for (i, tr) in _recursive_dict_get(data, ["PowerSystemResource", "Equipment", "ConductingEquipment", "PowerTransformer"], Dict()) + info_name = match(Regex("TransformerTankInfo::'(.*)'"), get(get(tr, "PowerTransformer.TransformerTank", [Dict()])[1], "PowerSystemResource.AssetDatasheet", "TransformerTankInfo::''")).captures[1] + trinfos = _recursive_dict_get(data, ["AssetInfo", "PowerTransformerInfo", info_name, "PowerTransformerInfo.TransformerTankInfos", info_name, "TransformerTankInfo.TransformerEndInfos"], []) +rated_u = merge( + filter(x -> !ismissing(x.second), Dict(get(trinfo, "TransformerEndInfo.endNumber", n) => get(trinfo, "TransformerEndInfo.ratedU", missing) for (n, trinfo) in enumerate(trinfos))), + filter(x -> !ismissing(x.second), Dict(get(pte, "endNumber", n) => get(pte, "PowerTransformerEnd.ratedU", missing) for (n, pte) in enumerate(get(tr, "PowerTransformer.PowerTransformerEnd", [])))) + ) + for (n, term) in enumerate(get(tr, "ConductingEquipment.Terminals", [])) + voltages[match(Regex("ConnectivityNode::'(.+)'"), term["Terminal.ConnectivityNode"]).captures[1]] = get(rated_u, n, missing) + end + end + + return voltages +end + + +function find_base_voltages(data::Dict{String,<:Any})::Dict{String,Any} + node_lookup, G = build_base_voltage_graphs(data) + + voltages = find_voltages(data) + + ccs = Graphs.connected_components(G) + + voltage_per_cc = Dict() + for (n, cc) in enumerate(ccs) + for i in cc + if node_lookup[i] in keys(voltages) + voltage_per_cc[n] = voltages[node_lookup[i]] + break + end + end + end + + return Dict{String,Any}(node_lookup[i] => get(voltage_per_cc, n, missing) for (n, cc) in enumerate(ccs) for i in cc) +end + +function _recursive_dict_get(dict::Dict, path::Vector{<:Any}, default::Any)::Any + if length(path) > 1 + return _recursive_dict_get(get(dict, path[1], Dict()), path[2:end], default) + else + return get(dict, path[1], default) + end +end + +function _recursive_dict_set!(dict::Dict, path::Vector{<:Any}, value::Any) + if length(path) > 1 + _recursive_dict_set!(dict[path[1]], path[2:end], value) + else + dict[path[1]] = value + end +end + +function add_base_voltages!(data::Dict{String,<:Any}; overwrite::Bool=false)::Nothing + if overwrite || "BaseVoltage" ∉ keys(data) + data["BaseVoltage"] = Dict{String,Any}() + end + + base_voltages = find_base_voltages(data) + + unique_bv = unique(values(base_voltages)) + + for bv in unique_bv + data["BaseVoltage"]["RAVENS_BaseV_$(bv/1000.0)_kV"] = Dict{String,Any}( + "IdentifedObject.name" => "RAVENS_BaseV_$(bv) V", + "IdentifedObject.mRID" => "$(UUIDs.uuid4())", + "Ravens.cimObjectType" => "BaseVoltage", + "BaseVoltage.nominalVoltage" => bv + ) + end + + encon_path = ["PowerSystemResource", "Equipment", "ConductingEquipment", "EnergyConnection"] + + for path in [["EnergyConsumer"], ["EnergySource"], ["RegulatingCondEq", "PowerElectronicsConnection"], ["RegulatingCondEq", "RotatingMachine"]] + path = [encon_path..., path...] + for (i, item) in _recursive_dict_get(data, path, Dict()) + if !overwrite && "ConductingEquipment.BaseVoltage" ∈ keys(item) + continue + else + cn = match(Regex("ConnectivityNode::'(.+)'"), item["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]).captures[1] + _recursive_dict_set!(data, [path..., i, "ConductingEquipment.BaseVoltage"], "BaseVoltage::'RAVENS_BaseV_$(base_voltages[cn]/1000.0)_kV'") + end + end + end +end From b0a07d8d37024fe267edf320b882296e585edf2b Mon Sep 17 00:00:00 2001 From: David M Fobes Date: Wed, 9 Jul 2025 15:55:43 -0600 Subject: [PATCH 84/99] WIP: ADD: voltage bounds for some objects --- src/data_model/utils_ravens.jl | 107 ++++++++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 7 deletions(-) diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 753fe55e8..005d8c415 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -163,8 +163,7 @@ function apply_voltage_bounds_math!(data::Dict{String,<:Any}; vm_lb::Union{Real, end - -function build_base_voltage_graphs(data::Dict{String,<:Any})::Tuple{Dict{Int,String}, Graphs.SimpleGraph} +function build_base_voltage_graphs(data::Dict{String,<:Any})::Tuple{Dict{Int,String},Graphs.SimpleGraph} nodes = Dict(cn => n for (n, cn) in enumerate(keys(data["ConnectivityNode"]))) G = Graphs.SimpleGraph(length(nodes)) @@ -180,6 +179,7 @@ function build_base_voltage_graphs(data::Dict{String,<:Any})::Tuple{Dict{Int,Str return Dict{Int,String}(n => cn for (cn, n) in nodes), G end + function find_voltages(data::Dict{String,<:Any})::Dict{String,Any} voltages = Dict{String,Any}() @@ -193,7 +193,7 @@ function find_voltages(data::Dict{String,<:Any})::Dict{String,Any} for (i, tr) in _recursive_dict_get(data, ["PowerSystemResource", "Equipment", "ConductingEquipment", "PowerTransformer"], Dict()) info_name = match(Regex("TransformerTankInfo::'(.*)'"), get(get(tr, "PowerTransformer.TransformerTank", [Dict()])[1], "PowerSystemResource.AssetDatasheet", "TransformerTankInfo::''")).captures[1] trinfos = _recursive_dict_get(data, ["AssetInfo", "PowerTransformerInfo", info_name, "PowerTransformerInfo.TransformerTankInfos", info_name, "TransformerTankInfo.TransformerEndInfos"], []) -rated_u = merge( + rated_u = merge( filter(x -> !ismissing(x.second), Dict(get(trinfo, "TransformerEndInfo.endNumber", n) => get(trinfo, "TransformerEndInfo.ratedU", missing) for (n, trinfo) in enumerate(trinfos))), filter(x -> !ismissing(x.second), Dict(get(pte, "endNumber", n) => get(pte, "PowerTransformerEnd.ratedU", missing) for (n, pte) in enumerate(get(tr, "PowerTransformer.PowerTransformerEnd", [])))) ) @@ -226,6 +226,7 @@ function find_base_voltages(data::Dict{String,<:Any})::Dict{String,Any} return Dict{String,Any}(node_lookup[i] => get(voltage_per_cc, n, missing) for (n, cc) in enumerate(ccs) for i in cc) end + function _recursive_dict_get(dict::Dict, path::Vector{<:Any}, default::Any)::Any if length(path) > 1 return _recursive_dict_get(get(dict, path[1], Dict()), path[2:end], default) @@ -234,6 +235,7 @@ function _recursive_dict_get(dict::Dict, path::Vector{<:Any}, default::Any)::Any end end + function _recursive_dict_set!(dict::Dict, path::Vector{<:Any}, value::Any) if length(path) > 1 _recursive_dict_set!(dict[path[1]], path[2:end], value) @@ -242,6 +244,7 @@ function _recursive_dict_set!(dict::Dict, path::Vector{<:Any}, value::Any) end end + function add_base_voltages!(data::Dict{String,<:Any}; overwrite::Bool=false)::Nothing if overwrite || "BaseVoltage" ∉ keys(data) data["BaseVoltage"] = Dict{String,Any}() @@ -252,9 +255,9 @@ function add_base_voltages!(data::Dict{String,<:Any}; overwrite::Bool=false)::No unique_bv = unique(values(base_voltages)) for bv in unique_bv - data["BaseVoltage"]["RAVENS_BaseV_$(bv/1000.0)_kV"] = Dict{String,Any}( - "IdentifedObject.name" => "RAVENS_BaseV_$(bv) V", - "IdentifedObject.mRID" => "$(UUIDs.uuid4())", + data["BaseVoltage"]["PMD_BaseV_$(bv/1000.0)_kV"] = Dict{String,Any}( + "IdentifiedObject.name" => "PMD_BaseV_$(bv) V", + "IdentifiedObject.mRID" => "$(UUIDs.uuid4())", "Ravens.cimObjectType" => "BaseVoltage", "BaseVoltage.nominalVoltage" => bv ) @@ -269,8 +272,98 @@ function add_base_voltages!(data::Dict{String,<:Any}; overwrite::Bool=false)::No continue else cn = match(Regex("ConnectivityNode::'(.+)'"), item["ConductingEquipment.Terminals"][1]["Terminal.ConnectivityNode"]).captures[1] - _recursive_dict_set!(data, [path..., i, "ConductingEquipment.BaseVoltage"], "BaseVoltage::'RAVENS_BaseV_$(base_voltages[cn]/1000.0)_kV'") + _recursive_dict_set!(data, [path..., i, "ConductingEquipment.BaseVoltage"], "BaseVoltage::'PMD_BaseV_$(base_voltages[cn]/1000.0)_kV'") + end + end + end +end + + +function add_voltage_bounds!(data::Dict{String,<:Any}, vm_lb_pu::Real=0.95, vm_ub_pu::Real=1.05; apply_to_all_connectivity_nodes::Bool=false, overwrite::Bool=false, acceptable_duration::Real=5e9) + cond_equip_path = ["PowerSystemResource", "Equipment", "ConductingEquipment"] + + if overwrite || !haskey(data, "BaseVoltage") + data["BaseVoltage"] = Dict{String,Any}() + end + + add_voltage_limit_set_types!(data; overwrite=overwrite, acceptable_duration=acceptable_duration) + + for path in [["EnergyConnection", "EnergySource"], ["EnergyConnection", "EnergyConsumer"], ["RegulatingCondEq", "PowerElectronicsConnection"], ["RegulatingCondEq", "RotatingMachine"]] + path = [cond_equip_path..., path...] + for (i, item) in _recursive_dict_get(data, path, Dict()) + base_voltage_ref = get(item, "ConductingEquipment.BaseVoltage", missing) + if ismissing(base_voltage_ref) + @warn "Cannot add limits to $(path[end]).$(i): BaseVoltage is missing. Add BaseVoltage using functing `add_base_voltages`" + continue end + base_voltage = data["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + + for (n, terminal) in enumerate(item["ConductingEquipment.Terminals"]) + if !overwrite && haskey(item, "ACDCTerminal.OperationalLimitSet") + continue + else + limit_set_name = "PMD_BaseV_$(base_voltage*vm_lb_pu)_$(base_voltage*vm_ub_pu)" + if !haskey(data["BaseVoltage"], limit_set_name) + data["BaseVoltage"][limit_set_name] = _build_voltage_limit(base_voltage, vm_lb_pu, vm_ub_pu; acceptable_duration=acceptable_duration) + end + _recursive_dict_set!(data, [path..., i, "ACDCTerminal.OperationalLimitSet"], "OperationalLimitSet::'$(limit_set_name)'") + end + end + end + end +end + + +function add_voltage_limit_set_types!(data::Dict{String,Any}; overwrite::Bool=false, acceptable_duration::Real=5e9) + high = Dict{String,Any}( + "Ravens.cimObjectType" => "OperationalLimitType", + "IdentifiedObject.name" => "PMD_highType_$(acceptable_duration)s", + "IdentifiedObject.mRID" => "$(UUIDs.uuid4())", + "OperationalLimitType.direction" => "OperationalLimitDirectionKind.high", + "OperationalLimitType.acceptableDuration" => acceptable_duration + ) + + low = Dict{String,Any}( + "Ravens.cimObjectType" => "OperationalLimitType", + "IdentifiedObject.name" => "PMD_lowType_$(acceptable_duration)s", + "IdentifiedObject.mRID" => "$(UUIDs.uuid4())", + "OperationalLimitType.direction" => "OperationalLimitDirectionKind.low", + "OperationalLimitType.acceptableDuration" => acceptable_duration + ) + + if overwrite || !haskey(data, "OperationalLimitType") + data["OperationalLimitType"] = Dict{String,Any}() + end + + for item in [high, low] + if !(!overwrite && haskey(data["OperationalLimitType"], item["IdentifiedObject.name"])) + data["OperationalLimitType"][item["IdentifiedObject.name"]] = item end end end + + +function _build_voltage_limit(vbase::Real, vm_lb_pu::Real, vm_ub_pu::Real; acceptable_duration::Real=5e9)::Dict{String,Any} + Dict{String,Any}( + "Ravens.cimObjectType" => "OperationalLimitSet", + "IdentifiedObject.name" => "PMD_OpLimV-$(vbase*vm_lb_pu)_$(vbase*vm_ub_pu)", + "IdentifiedObject.mRID" => "$(UUIDs.uuid4())", + "OperationalLimitSet.OperationalLimitValue" => Dict{String,Any}[ + Dict{String,Any}( + "Ravens.cimObjectType" => "VoltageLimit", + "IdentifiedObject.mRID" => "$(UUIDs.uuid4())", + "VoltageLimit.normalValue" => vbase, + "VoltageLimit.value" => vbase * vm_ub_pu, + "OperationalLimit.OperationalLimitType" => "OperationalLimitType::'PMD_highType_$(acceptable_duration)s'" + ), + Dict{String,Any}( + "Ravens.cimObjectType" => "VoltageLimit", + "IdentifiedObject.mRID" => "$(UUIDs.uuid4())", + "VoltageLimit.normalValue" => vbase, + "VoltageLimit.value" => vbase * vm_lb_pu, + "OperationalLimit.OperationalLimitType" => "OperationalLimitType::'PMD_lowType_$(acceptable_duration)s'" + ) + ] + ) +end + From 1f743fcb6cab1b1e0106eacd3b1f9ed70169eb2c Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 10 Jul 2025 08:41:33 -0600 Subject: [PATCH 85/99] RM: old code for computing base voltages. --- src/data_model/transformations/ravens2math.jl | 52 +++++-------------- 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 57bc3d565..7957f1bb1 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -80,9 +80,6 @@ function _map_ravens2math( "power_scale_factor" => 1e3, "base_frequency" => get(_data_ravens, "BaseFrequency", 60.0), "vbases_default" => Dict{String,Real}(), - "vbases_network" => Dict{String,Real}(), - "vbases_buses" => Dict{String,Real}() - ) # Multinetwork @@ -642,9 +639,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data snom[wdg_endNumber] = wdgs[wdg_endNumber]["PowerTransformerEnd.ratedS"] zbase[wdg_endNumber] = (vnom[wdg_endNumber]^2)/snom[wdg_endNumber] - # Add vnom info to vbases - data_math["settings"]["vbases_network"][string(bus)] = deepcopy(vnom[wdg_endNumber]/voltage_scale_factor) - # Transformer impedance when values are missing for other windings. xfmr_star_impedance = get(wdgs[wdg_endNumber], "TransformerEnd.StarImpedance", Dict()) xfmr_star_impedance_r = get(xfmr_star_impedance, "TransformerStarImpedance.r", 0.0) @@ -1089,8 +1083,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data bus_data["vmax"] = fill(Inf, nphases) bus_data["grounded"] = zeros(Bool, nphases) end - # Add vnom info to bus - data_math["settings"]["vbases_network"][string(bus)] = deepcopy(vnom[i]/voltage_scale_factor) end # wdg i, tank 1 - assumes tank 1 always exists @@ -1179,10 +1171,6 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data end end - # Checks and calculates voltage bases for elements that do not have Voltage Bases. - # TODO: Revise if this is the best way to be calculate vbases for missing elements - # data_math["settings"]["vbases_buses"] = calc_math_voltage_bases(data_math, data_math["settings"]["vbases_network"])[1] # [1] bus_vbase, [2] edge_vbase - end @@ -1229,13 +1217,9 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r bus_conn = data_math["bus"][bus_info] # Set the nominal voltage - if haskey(ravens_obj, "ConductingEquipment.BaseVoltage") - base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) - base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor_sqrt3) - else - math_obj["vnom_kv"] = data_math["settings"]["vbases_buses"][bus_info] - end + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) + base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor_sqrt3) if haskey(data_ravens["ConnectivityNode"][connectivity_node], "ConnectivityNode.OperationalLimitSet") op_limit_id = _extract_name(data_ravens["ConnectivityNode"][connectivity_node]["ConnectivityNode.OperationalLimitSet"]) @@ -1602,16 +1586,13 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) - # Set the nominal voltage - bus_conn = data_math["bus"]["$(math_obj["gen_bus"])"] - if haskey(ravens_obj, "ConductingEquipment.BaseVoltage") - base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) - nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - base_voltage = nominal_voltage / sqrt(nconductors) - math_obj["vbase"] = base_voltage / voltage_scale_factor - else - math_obj["vbase"] = data_math["settings"]["vbases_buses"][string(math_obj["gen_bus"])] - end + # Set the nominal voltage + bus_conn = data_math["bus"]["$(math_obj["gen_bus"])"] + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) + nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + base_voltage = nominal_voltage / sqrt(nconductors) + math_obj["vbase"] = base_voltage / voltage_scale_factor + if control_mode == Int(ISOCHRONOUS) && status == 1 data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "RotatingMachine.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) @@ -1711,15 +1692,10 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data # Set the nominal voltage bus_conn = data_math["bus"]["$(math_obj["gen_bus"])"] - if haskey(ravens_obj, "ConductingEquipment.BaseVoltage") - base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) - nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - base_voltage = nominal_voltage / sqrt(nconductors) - math_obj["vbase"] = base_voltage / voltage_scale_factor - else - math_obj["vbase"] = data_math["settings"]["vbases_buses"][string(math_obj["gen_bus"])] - nominal_voltage = math_obj["vbase"] * voltage_scale_factor * sqrt(nconductors) - end + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) + nominal_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + base_voltage = nominal_voltage / sqrt(nconductors) + math_obj["vbase"] = base_voltage / voltage_scale_factor if control_mode == Int(ISOCHRONOUS) && status == 1 data_math["bus"]["$(math_obj["gen_bus"])"]["vm"] = ((get(ravens_obj, "PowerElectronicsConnection.ratedU", nominal_voltage))/nominal_voltage)* ones(nconductors) From 6a9573b3b923823e4e81d85311306b3d7a14d615 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 4 Sep 2025 10:44:18 -0600 Subject: [PATCH 86/99] FIX: find voltages function that was assigning incorrect voltage bases to elements in connected to three-phase transformers with single-phase tanks. --- src/data_model/utils_ravens.jl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 005d8c415..c27707d90 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -193,10 +193,19 @@ function find_voltages(data::Dict{String,<:Any})::Dict{String,Any} for (i, tr) in _recursive_dict_get(data, ["PowerSystemResource", "Equipment", "ConductingEquipment", "PowerTransformer"], Dict()) info_name = match(Regex("TransformerTankInfo::'(.*)'"), get(get(tr, "PowerTransformer.TransformerTank", [Dict()])[1], "PowerSystemResource.AssetDatasheet", "TransformerTankInfo::''")).captures[1] trinfos = _recursive_dict_get(data, ["AssetInfo", "PowerTransformerInfo", info_name, "PowerTransformerInfo.TransformerTankInfos", info_name, "TransformerTankInfo.TransformerEndInfos"], []) + + # Corrects voltage ratios for TransformerTanks with Single-phase Tanks datasheets + voltage_ratios = ones(length(tr["ConductingEquipment.Terminals"])) + for wdg_id in 1:1:length(tr["ConductingEquipment.Terminals"]) + conns = length(_phasecode_map[tr["ConductingEquipment.Terminals"][wdg_id]["Terminal.phases"]]) + voltage_ratios[wdg_id] = conns >= 3 ? sqrt(3) : 1.0 + end + rated_u = merge( - filter(x -> !ismissing(x.second), Dict(get(trinfo, "TransformerEndInfo.endNumber", n) => get(trinfo, "TransformerEndInfo.ratedU", missing) for (n, trinfo) in enumerate(trinfos))), + filter(x -> !ismissing(x.second), Dict(get(trinfo, "TransformerEndInfo.endNumber", n) => get(trinfo, "TransformerEndInfo.ratedU", missing) * voltage_ratios[n] for (n, trinfo) in enumerate(trinfos))), filter(x -> !ismissing(x.second), Dict(get(pte, "endNumber", n) => get(pte, "PowerTransformerEnd.ratedU", missing) for (n, pte) in enumerate(get(tr, "PowerTransformer.PowerTransformerEnd", [])))) ) + for (n, term) in enumerate(get(tr, "ConductingEquipment.Terminals", [])) voltages[match(Regex("ConnectivityNode::'(.+)'"), term["Terminal.ConnectivityNode"]).captures[1]] = get(rated_u, n, missing) end From 1c75a74d481511b47b0eb1f6ec69ddd3445def18 Mon Sep 17 00:00:00 2001 From: jjospina Date: Fri, 5 Sep 2025 10:04:57 -0600 Subject: [PATCH 87/99] REF: Calculation of impedance in EnergySource. --- src/data_model/transformations/ravens2math.jl | 11 +++++-- src/data_model/utils_ravens.jl | 29 +++++-------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 7957f1bb1..ce835dd98 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1500,6 +1500,13 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav math_obj["gen_bus"] = bus_obj["bus_i"] data_math["bus"]["$(bus_obj["index"])"] = bus_obj + # Impedance calculation + r = get(ravens_obj, "EnergySource.r", 0.0) + r0 = get(ravens_obj, "EnergySource.r0", 0.0) + x = get(ravens_obj, "EnergySource.x", 0.0) + x0 = get(ravens_obj, "EnergySource.x0", 0.0) + Z_ABC = _impedance_conversion_ravens_energy_source(data_ravens, ravens_obj, r+x*1im, r0+x0*1im) + branch_obj = Dict( "name" => "_virtual_branch.EnergySource.$name", "source_id" => "EnergySource.$name", @@ -1511,8 +1518,8 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav "angmax" => fill(10.0, nconductors), "c_rating_a" => fill(Inf, nconductors), "br_status" => math_obj["gen_status"], - "br_r" => _impedance_conversion_ravens_energy_source(data_ravens, ravens_obj, "EnergySource.r", "EnergySource.r0"), - "br_x" => _impedance_conversion_ravens_energy_source(data_ravens, ravens_obj, "EnergySource.x", "EnergySource.x0"), + "br_r" => real(Z_ABC), + "br_x" => imag(Z_ABC), "g_fr" => zeros(nconductors, nconductors), "g_to" => zeros(nconductors, nconductors), "b_fr" => zeros(nconductors, nconductors), diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index c27707d90..62199437d 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -78,27 +78,14 @@ function _impedance_conversion_ravens(data_eng::Dict{String,Any}, eng_obj::Dict{ end -"converts impendance in Ohm/m by multiplying by length" -function _impedance_conversion_ravens_energy_source(data_eng::Dict{String,Any}, eng_obj::Dict{String,Any}, key1::String, key2::String) - # Default energy sources considered 3 phases - nphases = 3 - _impedance_matrix = zeros(Float64, nphases, nphases) - - z = get(eng_obj, key1, 0.0) - z0 = get(eng_obj, key2, 0.0) - - for i in 1:nphases - for j in 1:i - if(i==j) - _impedance_matrix[i, j] = z + ((z0 - z)/3) - else - _impedance_matrix[i, j] = (z0 - z)/3 - _impedance_matrix[j, i] = (z0 - z)/3 - end - end - end - - return _impedance_matrix .* get(eng_obj, "Conductor.length", 1.0) +"converts impendance in Ohm/m in EnergySource" +function _impedance_conversion_ravens_energy_source(data_eng::Dict{String,Any}, eng_obj::Dict{String,Any}, z1::Complex, z0::Complex) + # TODO : Single-phase + a = 1*exp(120*im*π/180) + A = [1 1 1; 1 a a^2; 1 a^2 a] + Z_012 = [z0 0im 0im; 0im z1 0im; 0im 0im z1] + Z_ABC = A^-1 * Z_012 * A + return Z_ABC end From fcf37bc37f0ee26daebf5b5f841aff8efc2fda12 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 9 Sep 2025 16:18:47 -0600 Subject: [PATCH 88/99] FIX: vbase kv for loads. --- src/data_model/transformations/ravens2math.jl | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index ce835dd98..60ff16ed0 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1086,11 +1086,11 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data end # wdg i, tank 1 - assumes tank 1 always exists - r_s = [sum(r_s[i]) for i in 1:nrw] - x_sc = [sum(x_sc[i]) for i in 1:nrw] # sum the x_sc for all tanks per wdg - x_sc = [x_sc[1]] # get x_sc wrt to wdg 1 - g_sh = sum(g_sh) # wrt to wdg 1 - b_sh = sum(b_sh) # wrt to wdg 1 + r_s = [r_s[i][1] for i in 1:nrw] + x_sc = [x_sc[i][1] for i in 1:nrw] # sum the x_sc for all tanks per wdg + x_sc = [x_sc[1][1]] # get x_sc wrt to wdg 1 + g_sh = g_sh[1] # wrt to wdg 1 + b_sh = b_sh[1] # wrt to wdg 1 # convert x_sc from list of upper triangle elements to an explicit dict y_sh = g_sh + im*b_sh @@ -1127,7 +1127,11 @@ function _map_ravens2math_power_transformer!(data_math::Dict{String,<:Any}, data end # tm_nom depending on wdg configuration - tm_nom = configuration[wdg_id]==DELTA ? vnom[wdg_id]*sqrt(3)/voltage_scale_factor : vnom[wdg_id]/voltage_scale_factor + if ntanks >= 3 + tm_nom = configuration[wdg_id]==DELTA ? vnom[wdg_id]/voltage_scale_factor : vnom[wdg_id]/voltage_scale_factor*sqrt(3) + else + tm_nom = configuration[wdg_id]==DELTA ? vnom[wdg_id]/voltage_scale_factor : vnom[wdg_id]/voltage_scale_factor + end # Transformer Object transformer_2wa_obj = Dict{String,Any}( @@ -1216,11 +1220,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r bus_info = string(math_obj["load_bus"]) bus_conn = data_math["bus"][bus_info] - # Set the nominal voltage - base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) - base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] - math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor_sqrt3) - + # OperationalLimitSets if haskey(data_ravens["ConnectivityNode"][connectivity_node], "ConnectivityNode.OperationalLimitSet") op_limit_id = _extract_name(data_ravens["ConnectivityNode"][connectivity_node]["ConnectivityNode.OperationalLimitSet"]) op_limits = data_ravens["OperationalLimitSet"][op_limit_id]["OperationalLimitSet.OperationalLimitValue"] @@ -1236,9 +1236,9 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end if lim_type == "OperationalLimitDirectionKind.high" - op_limit_max = lim["VoltageLimit.value"] / voltage_scale_factor_sqrt3 + op_limit_max = lim["VoltageLimit.value"] elseif lim_type == "OperationalLimitDirectionKind.low" - op_limit_min = lim["VoltageLimit.value"] / voltage_scale_factor_sqrt3 + op_limit_min = lim["VoltageLimit.value"] end end @@ -1267,6 +1267,20 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r math_obj["connections"] = bus_conn["terminals"] end + # Set the nominal voltage + base_voltage_ref = _extract_name(ravens_obj["ConductingEquipment.BaseVoltage"]) + base_voltage = data_ravens["BaseVoltage"][base_voltage_ref]["BaseVoltage.nominalVoltage"] + + if nphases >= 3 + math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor_sqrt3) + bus_conn["vmax"] = bus_conn["vmax"]./voltage_scale_factor_sqrt3 + bus_conn["vmin"] = bus_conn["vmin"]./voltage_scale_factor_sqrt3 + else + math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor) + bus_conn["vmax"] = bus_conn["vmax"]./voltage_scale_factor + bus_conn["vmin"] = bus_conn["vmin"]./voltage_scale_factor + end + # Set p and q (w/ multinetwork support) if nw==0 math_obj["pd"] = fill(get(ravens_obj, "EnergyConsumer.p", 0.0) / (power_scale_factor*nphases), nphases) From 6d8ee03c9e85a83a789ab2d268110ccf21cfbd9b Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 9 Sep 2025 16:49:30 -0600 Subject: [PATCH 89/99] FIX: voltage limits loads. --- src/data_model/transformations/ravens2math.jl | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 60ff16ed0..1bd335bc5 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1236,9 +1236,9 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end if lim_type == "OperationalLimitDirectionKind.high" - op_limit_max = lim["VoltageLimit.value"] + op_limit_max = lim["VoltageLimit.value"]/voltage_scale_factor_sqrt3 elseif lim_type == "OperationalLimitDirectionKind.low" - op_limit_min = lim["VoltageLimit.value"] + op_limit_min = lim["VoltageLimit.value"]/voltage_scale_factor_sqrt3 end end @@ -1273,12 +1273,8 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r if nphases >= 3 math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor_sqrt3) - bus_conn["vmax"] = bus_conn["vmax"]./voltage_scale_factor_sqrt3 - bus_conn["vmin"] = bus_conn["vmin"]./voltage_scale_factor_sqrt3 else math_obj["vnom_kv"] = (base_voltage / voltage_scale_factor) - bus_conn["vmax"] = bus_conn["vmax"]./voltage_scale_factor - bus_conn["vmin"] = bus_conn["vmin"]./voltage_scale_factor end # Set p and q (w/ multinetwork support) From 7d7423dcde13c7572f8ba3792f096ee80ee90aa5 Mon Sep 17 00:00:00 2001 From: Juan Ospina Date: Wed, 24 Sep 2025 16:00:06 -0600 Subject: [PATCH 90/99] Add ravens output (#6) * WIP: math2ravens solution converter. Added Voltages, Statuses, and PowerFlows basic structures. * WIP: Add support for adding status to transformers coming from MATH model. * WIP: add operational results switch states and return values for transformation. * WIP: Add mn support for voltages. * ADD: multinetwork support for PF/OPF solutions. * ADD: support for ONM solutions states, status. * ADD: support for storage power flows and correct timestep values to hours based on time elapsed. * FIX: check for existence of state and status keys. * REF: sort the nws in mn solutions, making sure the timesteps are ordered. --- src/PowerModelsDistribution.jl | 1 + src/data_model/transformations/math2ravens.jl | 559 ++++++++++++++++++ 2 files changed, 560 insertions(+) create mode 100644 src/data_model/transformations/math2ravens.jl diff --git a/src/PowerModelsDistribution.jl b/src/PowerModelsDistribution.jl index eef595b50..97612bb3e 100644 --- a/src/PowerModelsDistribution.jl +++ b/src/PowerModelsDistribution.jl @@ -70,6 +70,7 @@ module PowerModelsDistribution include("data_model/transformations/dss2eng.jl") include("data_model/transformations/eng2math.jl") include("data_model/transformations/math2eng.jl") + include("data_model/transformations/math2ravens.jl") include("data_model/transformations/utils.jl") include("data_model/transformations/reduce.jl") include("data_model/transformations/ravens2math.jl") diff --git a/src/data_model/transformations/math2ravens.jl b/src/data_model/transformations/math2ravens.jl new file mode 100644 index 000000000..c09d0b09f --- /dev/null +++ b/src/data_model/transformations/math2ravens.jl @@ -0,0 +1,559 @@ +function transform_solution_ravens( + solution_math::Dict{String,<:Any}, + data_math::Dict{String,<:Any}; + map::Union{Vector{<:Dict{String,<:Any}},Missing}=missing, + make_si::Bool=true, + convert_rad2deg::Bool=true, + map_math2eng_extensions::Dict{String,<:Function}=Dict{String,Function}(), + make_si_extensions::Vector{<:Function}=Function[], + dimensionalize_math_extensions::Dict{String,<:Dict{String,<:Vector{<:String}}}=Dict{String,Dict{String,Vector{String}}}() +)::Dict{String,Any} + + @assert ismath(data_math) "cannot be converted. Not a MATH model." + + # convert solution to si? + solution_math = solution_make_si( + solution_math, + data_math; + mult_vbase=make_si, + mult_sbase=make_si, + convert_rad2deg=convert_rad2deg, + make_si_extensions=make_si_extensions, + dimensionalize_math_extensions=dimensionalize_math_extensions + ) + + # multinetwork/multiperiod support + mn_flag = false + if ismultinetwork(data_math) + # Assumes there is at least nw=1 + nws_math_data = data_math["nw"]["1"] + solution = solution_math["nw"]["1"] + mn_flag = true + + # sort nw keys (ensures vectors are organized in RAVENS) + keys_array = collect(keys(solution_math["nw"])) + sorted_nws = sort(keys_array, by=x -> parse(Int, x)) + + else + nws_math_data = data_math + solution = solution_math + end + + # Get time_elapsed to compute time steps -- default is 1.0 hour. + time_elapsed = get(data_math, "time_elapsed", 1.0) + + # Create OptimalPowerFlow AnalysisResult Dictionary + # TODO: read original JSON file, and add result to that JSON file (check if AnalysisResult exists before overwriting it) + solution_ravens = Dict() + solution_ravens["AnalysisResult"] = Dict() + solution_ravens["AnalysisResult"]["OptimalPowerFlow"] = Dict() + solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["Ravens.cimObjectType"] = "OperationsResult" + solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["IdentifiedObject.name"] = "OptimalPowerFlow" + solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["IdentifiedObject.mRID"] = "#_$(uppercase(string(UUIDs.uuid4())))" + + # Create a mapping from integers to strings + phase_mapping = Dict(1 => "SinglePhaseKind.A", 2 => "SinglePhaseKind.B", 3 => "SinglePhaseKind.C") + + # Voltages + solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Voltages"] = [] + + # PowerFlows + solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.PowerFlows"] = [] + + # Statuses + solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Statuses"] = [] + + # Switches States + solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Switches"] = [] + + # PowerFlow solutions for Transformers elements + seen_xfrmrs = Set{String}() # Set to save xfrmr names + + # Buses/ConnectivityNodes + for (node_number, node_data) in solution["bus"] + + # Extract the phases for the node + node_terminals = nws_math_data["bus"][node_number]["terminals"] + phase_kinds = [phase_mapping[x] for x in node_terminals] + + for (i, result_phase) in enumerate(phase_kinds) + + conn_node = split(nws_math_data["bus"][node_number]["source_id"], '.')[2] + + # Multinetwork support + if mn_flag == true + + # Curve data + mn_data = Dict() + mn_data["AnalysisResultData.Curve"] = Dict() + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] + + for nw in sorted_nws + mn_info = Dict( + "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], + "ArCurveData.DataValues" => Dict( + "AvVoltage.v" => solution_math["nw"][nw]["bus"][node_number]["vm"][i]*solution_math["nw"][nw]["settings"]["voltage_scale_factor"], + "Ravens.cimObjectType" => "AvVoltage", + ), + ) + + # Conditionally add the angle (some do not have it) + if haskey(solution_math["nw"][nw]["bus"][node_number], "va") + mn_info["ArCurveData.DataValues"]["AvVoltage.angle"] = solution_math["nw"][nw]["bus"][node_number]["va"][i] + end + + push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) + end + + voltage_info = Dict( + "AnalysisResultData.phase" => result_phase, + "ArVoltage.ConnectivityNode" => "ConnectivityNode::'$(conn_node)'", + "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] + ) + + else + voltage_info = Dict( + "AnalysisResultData.phase" => result_phase, + "ArVoltage.ConnectivityNode" => "ConnectivityNode::'$(conn_node)'", + "AnalysisResultData.DataValues" => Dict( + "AvVoltage.v" => node_data["vm"][i]*solution_math["settings"]["voltage_scale_factor"], + "AvVoltage.angle" => node_data["va"][i], + "Ravens.cimObjectType" => "AvVoltage", + ), + ) + end + + # Push info to final dictionary + push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Voltages"], voltage_info) + + end + + end + + # Transformers + for (xfrmr_number, xfrmr_data) in get(solution, "transformer", Dict{Any,Dict{String,Any}}()) + + # Extract data + source_id_vect = split(nws_math_data["transformer"][xfrmr_number]["source_id"], '.') + cond_eq_type = source_id_vect[2] + cond_eq_name = source_id_vect[3] + end_num = parse(Int, source_id_vect[4]) + + # Extract the phases for the branch + terminals = nws_math_data["transformer"][xfrmr_number]["f_connections"] + phase_kinds = [phase_mapping[x] for x in terminals] + + for (i, result_phase) in enumerate(phase_kinds) + + # Multinetwork support + if mn_flag == true + + # Curve data + mn_data = Dict() + mn_data["AnalysisResultData.Curve"] = Dict() + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] + + for nw in sorted_nws + mn_info = Dict( + "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], + "ArCurveData.DataValues" => Dict( + "AvPowerFlow.p" => solution_math["nw"][nw]["transformer"][xfrmr_number]["pf"][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "AvPowerFlow.q" => solution_math["nw"][nw]["transformer"][xfrmr_number]["qf"][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "AvPowerFlow.endNumber" => end_num, + "Ravens.cimObjectType" => "ArPowerFlow", + ), + ) + push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) + end + + pf_info = Dict( + "AnalysisResultData.phase" => result_phase, + "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] + ) + + else + + pf_info = Dict( + "AnalysisResultData.phase" => result_phase, + "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.DataValues" => Dict( + "AvPowerFlow.p" => xfrmr_data["pf"][i]*solution_math["settings"]["power_scale_factor"], + "AvPowerFlow.q" => xfrmr_data["qf"][i]*solution_math["settings"]["power_scale_factor"], + "AvPowerFlow.endNumber" => end_num, + "Ravens.cimObjectType" => "ArPowerFlow", + ), + ) + + + end + + push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.PowerFlows"], pf_info) + + end + + # Status for Xfrmrs + if !(cond_eq_name in seen_xfrmrs) + + xfrmr_status = nws_math_data["transformer"][xfrmr_number]["status"] == 1 ? true : false + + # Multinetwork support + if mn_flag == true + + # Curve data + mn_data = Dict() + mn_data["AnalysisResultData.Curve"] = Dict() + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] + + for nw in sorted_nws + mn_info = Dict( + "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], + "ArCurveData.DataValues" => Dict( + "AvStatus.inService" => xfrmr_status + ), + ) + push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) + end + + status_info = Dict( + "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] + ) + + else + + status_info = Dict( + "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.DataValues" => Dict( + "AvStatus.inService" => xfrmr_status, + ) + ) + + end + + push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Statuses"], status_info) + + end + + # Store the xfrmr name + push!(seen_xfrmrs, "$(cond_eq_name)") + + end + + # Edge elements (branches, switches) + edge_elements = ["branch", "switch"] + for edge_elmnt in edge_elements + + for (edge_number, edge_data) in get(solution, edge_elmnt, Dict{Any,Dict{String,Any}}()) + + # Filter virtual elements that exist in the MATH model + if !occursin("virtual", nws_math_data[edge_elmnt][edge_number]["name"]) + + cond_eq_type = split(nws_math_data[edge_elmnt][edge_number]["source_id"], '.')[1] + cond_eq_name = split(nws_math_data[edge_elmnt][edge_number]["source_id"], '.')[2] + + # Add Switch state (only switches) + if edge_elmnt == "switch" + + # initial state from math network data + sw_state = nws_math_data[edge_elmnt][edge_number]["state"] == 1 ? false : true + + if mn_flag == true + + # Curve data + mn_data = Dict() + mn_data["AnalysisResultData.Curve"] = Dict() + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] + + for nw in sorted_nws + if haskey(solution_math["nw"][nw][edge_elmnt][edge_number], "state") + sw_state = Int(solution_math["nw"][nw][edge_elmnt][edge_number]["state"]) == 0 ? true : false + end + mn_info = Dict( + "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], + "ArCurveData.DataValues" => Dict( + "AvSwitch.open" => sw_state, + ), + ) + push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) + end + + state_info = Dict( + "ArSwitch.Switch" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] + ) + + else + state_info = Dict( + "ArSwitch.Switch" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.DataValues" => Dict( + "AvSwitch.open" => sw_state, + ) + ) + + end + + push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Switches"], state_info) + + end + + + num_ends = 2 + # # OPTIONAL opt out of edge elements to write from and to flows + # if edge_elmnt != "transformer" + # num_ends = 1 + # end + + for end_num in 1:num_ends # loop through ends + if end_num == 1 + connection_flow = "f_connections" + p_flow_direction = "pf" + q_flow_direction = "qf" + else end_num == 2 + connection_flow = "t_connections" + p_flow_direction = "pt" + q_flow_direction = "qt" + end + + # Extract the phases for the branch + terminals = nws_math_data[edge_elmnt][edge_number][connection_flow] + phase_kinds = [phase_mapping[x] for x in terminals] + + for (i, result_phase) in enumerate(phase_kinds) + + # Multinetwork support + if mn_flag == true + + # Curve data + mn_data = Dict() + mn_data["AnalysisResultData.Curve"] = Dict() + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] + + for nw in sorted_nws + mn_info = Dict( + "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], + "ArCurveData.DataValues" => Dict( + "AvPowerFlow.p" => solution_math["nw"][nw][edge_elmnt][edge_number][p_flow_direction][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "AvPowerFlow.q" => solution_math["nw"][nw][edge_elmnt][edge_number][q_flow_direction][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "AvPowerFlow.endNumber" => end_num, + "Ravens.cimObjectType" => "ArPowerFlow", + ), + ) + push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) + end + + pf_info = Dict( + "AnalysisResultData.phase" => result_phase, + "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] + ) + + else + pf_info = Dict( + "AnalysisResultData.phase" => result_phase, + "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.DataValues" => Dict( + "AvPowerFlow.p" => edge_data[p_flow_direction][i]*solution_math["settings"]["power_scale_factor"], + "AvPowerFlow.q" => edge_data[q_flow_direction][i]*solution_math["settings"]["power_scale_factor"], + "AvPowerFlow.endNumber" => end_num, + "Ravens.cimObjectType" => "ArPowerFlow", + ), + ) + + end + + push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.PowerFlows"], pf_info) + + end + end + + # Statuses + object_prefix = "" + if edge_elmnt == "branch" + object_prefix = "br_" + end + + elemtn_status = nws_math_data[edge_elmnt][edge_number]["$(object_prefix)status"] == 1 ? true : false + + # Multinetwork support + if mn_flag == true + + # Curve data + mn_data = Dict() + mn_data["AnalysisResultData.Curve"] = Dict() + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] + + for nw in sorted_nws + mn_info = Dict( + "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], + "ArCurveData.DataValues" => Dict( + "AvStatus.inService" => elemtn_status + ), + ) + push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) + end + + status_info = Dict( + "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] + ) + + else + + status_info = Dict( + "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.DataValues" => Dict( + "AvStatus.inService" => elemtn_status, + ) + ) + + end + + push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Statuses"], status_info) + + end + + end + end + + # Nodal elements (loads, gens) + node_elements = ["load", "gen", "storage"] + for node_elmnt in node_elements + + for (node_number, node_data) in get(solution, node_elmnt, Dict{Any,Dict{String,Any}}()) + + # Filter virtual elements that exist in the MATH model + if !occursin("virtual", nws_math_data[node_elmnt][node_number]["name"]) + + cond_eq_type = split(nws_math_data[node_elmnt][node_number]["source_id"], '.')[1] + cond_eq_name = split(nws_math_data[node_elmnt][node_number]["source_id"], '.')[2] + + if node_elmnt == "load" + p_key = "pd" + q_key = "qd" + elseif node_elmnt == "gen" + p_key = "pg" + q_key = "qg" + elseif node_elmnt == "storage" + p_key = "ps" + q_key = "qs" + else + p_key = "p" + q_key = "q" + end + + # Extract the phases for the node element + terminals = nws_math_data[node_elmnt][node_number]["connections"] + phase_kinds = [phase_mapping[x] for x in terminals] + + for (i, result_phase) in enumerate(phase_kinds) + + # Multinetwork support + if mn_flag == true + + # Curve data + mn_data = Dict() + mn_data["AnalysisResultData.Curve"] = Dict() + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] + + for nw in sorted_nws + mn_info = Dict( + "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], + "ArCurveData.DataValues" => Dict( + "AvPowerFlow.p" => solution_math["nw"][nw][node_elmnt][node_number][p_key][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "AvPowerFlow.q" => solution_math["nw"][nw][node_elmnt][node_number][q_key][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "Ravens.cimObjectType" => "ArPowerFlow", + ), + ) + push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) + end + + pf_info = Dict( + "AnalysisResultData.phase" => result_phase, + "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] + ) + + + else + + pf_info = Dict( + "AnalysisResultData.phase" => result_phase, + "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.DataValues" => Dict( + "AvPowerFlow.p" => node_data[p_key][i]*solution_math["settings"]["power_scale_factor"], + "AvPowerFlow.q" => node_data[q_key][i]*solution_math["settings"]["power_scale_factor"], + "Ravens.cimObjectType" => "ArPowerFlow", + ), + ) + + end + + push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.PowerFlows"], pf_info) + + end + + + # Statuses + object_prefix = "" + if node_elmnt == "gen" + object_prefix = "gen_" + end + + # original status from math data + elemtn_status = nws_math_data[node_elmnt][node_number]["$(object_prefix)status"] == 1 ? true : false + + # Multinetwork support + if mn_flag == true + + # Curve data + mn_data = Dict() + mn_data["AnalysisResultData.Curve"] = Dict() + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" + mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] + + for nw in sorted_nws + if haskey(solution_math["nw"][nw][node_elmnt][node_number], "status") + elemtn_status = Int(solution_math["nw"][nw][node_elmnt][node_number]["status"]) == 1 ? true : false + end + mn_info = Dict( + "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], + "ArCurveData.DataValues" => Dict( + "AvStatus.inService" => elemtn_status + ), + ) + push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) + end + + status_info = Dict( + "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] + ) + + else + + status_info = Dict( + "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + "AnalysisResultData.DataValues" => Dict( + "AvStatus.inService" => elemtn_status, + ) + ) + + end + + push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Statuses"], status_info) + + end + end + end + + return solution_ravens + +end From 7c950e3ff83828003fc70a9876315f1761d8f7c5 Mon Sep 17 00:00:00 2001 From: jjospina Date: Fri, 26 Sep 2025 12:47:42 -0600 Subject: [PATCH 91/99] REF: trasnform solution from math to ravens. Fix issue with vg in PV units. --- src/data_model/transformations/math2ravens.jl | 704 +++++++----------- src/data_model/transformations/ravens2math.jl | 7 +- 2 files changed, 264 insertions(+), 447 deletions(-) diff --git a/src/data_model/transformations/math2ravens.jl b/src/data_model/transformations/math2ravens.jl index c09d0b09f..89e8354fa 100644 --- a/src/data_model/transformations/math2ravens.jl +++ b/src/data_model/transformations/math2ravens.jl @@ -1,17 +1,71 @@ + +function _make_curve_data(nws, data_math, path_func) + curve_data = [Dict( + "ArCurveData.xvalue" => parse(Float64, nw) * data_math["nw"][nw]["time_elapsed"], + "ArCurveData.DataValues" => path_func(nw) + ) for nw in nws] + + return Dict("AnalysisResultCurve.xUnit" => "UnitSymbol.h", "AnalysisResultCurve.CurveDatas" => curve_data) +end + +function _get_phases(terminals, phase_mapping) + return [phase_mapping[x] for x in terminals] +end + +function _push_result!(container::Dict, key::String, data::Dict) + push!(container["AnalysisResult"]["OptimalPowerFlow"][key], data) +end + +function _build_voltage_entry(phase, conn_node, data) + entry = Dict( + "AnalysisResultData.phase" => phase, + "ArVoltage.ConnectivityNode" => "ConnectivityNode::'$(conn_node)'", + ) + merged_entry = merge(entry, data) + return merged_entry +end + +function _build_powerflow_entry(phase, eq_type, eq_name, data) + entry = Dict( + "AnalysisResultData.phase" => phase, + "ArPowerFlow.ConductingEquipment" => "$(eq_type)::'$(eq_name)'", + ) + merged_entry = merge(entry, data) + return merged_entry +end + +function _build_status_entry(eq_type, eq_name, data) + entry = Dict( + "ArStatus.ConductingEquipment" => "$(eq_type)::'$(eq_name)'", + ) + merged_entry = merge(entry, data) + return merged_entry +end + +function _build_switch_entry(eq_type, eq_name, data) + entry = Dict( + "ArSwitch.Switch" => "$(eq_type)::'$(eq_name)'", + ) + merged_entry = merge(entry, data) + return merged_entry +end + + + function transform_solution_ravens( solution_math::Dict{String,<:Any}, data_math::Dict{String,<:Any}; map::Union{Vector{<:Dict{String,<:Any}},Missing}=missing, make_si::Bool=true, convert_rad2deg::Bool=true, - map_math2eng_extensions::Dict{String,<:Function}=Dict{String,Function}(), + map_math2eng_extensions::Dict{String,<:Function}=Dict{String,Function}(), make_si_extensions::Vector{<:Function}=Function[], dimensionalize_math_extensions::Dict{String,<:Dict{String,<:Vector{<:String}}}=Dict{String,Dict{String,Vector{String}}}() )::Dict{String,Any} @assert ismath(data_math) "cannot be converted. Not a MATH model." - # convert solution to si? + # convert solution to si solution_math = solution_make_si( solution_math, data_math; @@ -22,425 +76,236 @@ function transform_solution_ravens( dimensionalize_math_extensions=dimensionalize_math_extensions ) - # multinetwork/multiperiod support - mn_flag = false - if ismultinetwork(data_math) - # Assumes there is at least nw=1 - nws_math_data = data_math["nw"]["1"] - solution = solution_math["nw"]["1"] - mn_flag = true - - # sort nw keys (ensures vectors are organized in RAVENS) - keys_array = collect(keys(solution_math["nw"])) - sorted_nws = sort(keys_array, by=x -> parse(Int, x)) - - else - nws_math_data = data_math - solution = solution_math - end - - # Get time_elapsed to compute time steps -- default is 1.0 hour. + mn_flag = ismultinetwork(data_math) + nws = mn_flag ? sort(collect(keys(solution_math["nw"])), by = x -> parse(Int, x)) : [] + nw_data = mn_flag ? data_math["nw"]["1"] : data_math + sol = mn_flag ? solution_math["nw"]["1"] : solution_math time_elapsed = get(data_math, "time_elapsed", 1.0) - # Create OptimalPowerFlow AnalysisResult Dictionary - # TODO: read original JSON file, and add result to that JSON file (check if AnalysisResult exists before overwriting it) - solution_ravens = Dict() - solution_ravens["AnalysisResult"] = Dict() - solution_ravens["AnalysisResult"]["OptimalPowerFlow"] = Dict() - solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["Ravens.cimObjectType"] = "OperationsResult" - solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["IdentifiedObject.name"] = "OptimalPowerFlow" - solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["IdentifiedObject.mRID"] = "#_$(uppercase(string(UUIDs.uuid4())))" - - # Create a mapping from integers to strings - phase_mapping = Dict(1 => "SinglePhaseKind.A", 2 => "SinglePhaseKind.B", 3 => "SinglePhaseKind.C") - - # Voltages - solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Voltages"] = [] - - # PowerFlows - solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.PowerFlows"] = [] - - # Statuses - solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Statuses"] = [] - - # Switches States - solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Switches"] = [] - # PowerFlow solutions for Transformers elements seen_xfrmrs = Set{String}() # Set to save xfrmr names - # Buses/ConnectivityNodes - for (node_number, node_data) in solution["bus"] - - # Extract the phases for the node - node_terminals = nws_math_data["bus"][node_number]["terminals"] - phase_kinds = [phase_mapping[x] for x in node_terminals] - - for (i, result_phase) in enumerate(phase_kinds) - - conn_node = split(nws_math_data["bus"][node_number]["source_id"], '.')[2] - - # Multinetwork support - if mn_flag == true + # Phase mapping + phase_mapping = Dict(1 => "SinglePhaseKind.A", 2 => "SinglePhaseKind.B", 3 => "SinglePhaseKind.C") - # Curve data - mn_data = Dict() - mn_data["AnalysisResultData.Curve"] = Dict() - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] + solution_ravens = Dict( + "AnalysisResult" => Dict( + "OptimalPowerFlow" => Dict( + "Ravens.cimObjectType" => "OperationsResult", + "IdentifiedObject.name" => "OptimalPowerFlow", + "IdentifiedObject.mRID" => "#_$(uppercase(string(UUIDs.uuid4())))", + "OperationsResult.Voltages" => [], + "OperationsResult.PowerFlows" => [], + "OperationsResult.Statuses" => [], + "OperationsResult.Switches" => [] + ) + ) + ) - for nw in sorted_nws - mn_info = Dict( - "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], - "ArCurveData.DataValues" => Dict( - "AvVoltage.v" => solution_math["nw"][nw]["bus"][node_number]["vm"][i]*solution_math["nw"][nw]["settings"]["voltage_scale_factor"], - "Ravens.cimObjectType" => "AvVoltage", - ), + # --- Voltages --- + for (bus_id, bus_data) in sol["bus"] + terminals = nw_data["bus"][bus_id]["terminals"] + phases = _get_phases(terminals, phase_mapping) + conn_node = split(nw_data["bus"][bus_id]["source_id"], '.')[2] + + for (i, phase) in enumerate(phases) + if mn_flag + data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math, nw -> + begin + nw_bus = solution_math["nw"][nw]["bus"][bus_id] + v_info = Dict( + "AvVoltage.v" => nw_bus["vm"][i] * solution_math["nw"][nw]["settings"]["voltage_scale_factor"], + "Ravens.cimObjectType" => "AvVoltage" + ) + # Conditionally add the angle (some do not have it) + if haskey(nw_bus, "va") + v_info["AvVoltage.angle"] = nw_bus["va"][i] + end + return v_info + end ) - - # Conditionally add the angle (some do not have it) - if haskey(solution_math["nw"][nw]["bus"][node_number], "va") - mn_info["ArCurveData.DataValues"]["AvVoltage.angle"] = solution_math["nw"][nw]["bus"][node_number]["va"][i] - end - - push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) - end - - voltage_info = Dict( - "AnalysisResultData.phase" => result_phase, - "ArVoltage.ConnectivityNode" => "ConnectivityNode::'$(conn_node)'", - "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] ) - else - voltage_info = Dict( - "AnalysisResultData.phase" => result_phase, - "ArVoltage.ConnectivityNode" => "ConnectivityNode::'$(conn_node)'", - "AnalysisResultData.DataValues" => Dict( - "AvVoltage.v" => node_data["vm"][i]*solution_math["settings"]["voltage_scale_factor"], - "AvVoltage.angle" => node_data["va"][i], - "Ravens.cimObjectType" => "AvVoltage", - ), + data = Dict("AnalysisResultData.DataValues" => Dict( + "AvVoltage.v" => bus_data["vm"][i] * solution_math["settings"]["voltage_scale_factor"], + "AvVoltage.angle" => bus_data["va"][i], + "Ravens.cimObjectType" => "AvVoltage" + ) ) end - - # Push info to final dictionary - push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Voltages"], voltage_info) - + _push_result!(solution_ravens, "OperationsResult.Voltages", _build_voltage_entry(phase, conn_node, data)) end - end - # Transformers - for (xfrmr_number, xfrmr_data) in get(solution, "transformer", Dict{Any,Dict{String,Any}}()) - # Extract data - source_id_vect = split(nws_math_data["transformer"][xfrmr_number]["source_id"], '.') + # --- Transformers --- + for (tr_id, tr_data) in get(sol, "transformer", Dict{Any,Dict{String,Any}}()) + # Get xfrmr data + terminals = nw_data["transformer"][tr_id]["f_connections"] + phases = _get_phases(terminals, phase_mapping) + source_id_vect = split(nw_data["transformer"][tr_id]["source_id"], '.') cond_eq_type = source_id_vect[2] cond_eq_name = source_id_vect[3] - end_num = parse(Int, source_id_vect[4]) - - # Extract the phases for the branch - terminals = nws_math_data["transformer"][xfrmr_number]["f_connections"] - phase_kinds = [phase_mapping[x] for x in terminals] - - for (i, result_phase) in enumerate(phase_kinds) - - # Multinetwork support - if mn_flag == true - - # Curve data - mn_data = Dict() - mn_data["AnalysisResultData.Curve"] = Dict() - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] - - for nw in sorted_nws - mn_info = Dict( - "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], - "ArCurveData.DataValues" => Dict( - "AvPowerFlow.p" => solution_math["nw"][nw]["transformer"][xfrmr_number]["pf"][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], - "AvPowerFlow.q" => solution_math["nw"][nw]["transformer"][xfrmr_number]["qf"][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], - "AvPowerFlow.endNumber" => end_num, - "Ravens.cimObjectType" => "ArPowerFlow", - ), + end_n = parse(Int, source_id_vect[4]) + + # PowerFlow + for (i, phase) in enumerate(phases) + if mn_flag + data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math, nw -> + begin + nw_tr = solution_math["nw"][nw]["transformer"][tr_id] + Dict( + "AvPowerFlow.p" => nw_tr["pf"][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "AvPowerFlow.q" => nw_tr["qf"][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "AvPowerFlow.endNumber" => end_n, + "Ravens.cimObjectType" => "AvPowerFlow" + ) + end ) - push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) - end - - pf_info = Dict( - "AnalysisResultData.phase" => result_phase, - "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] ) - else - - pf_info = Dict( - "AnalysisResultData.phase" => result_phase, - "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.DataValues" => Dict( - "AvPowerFlow.p" => xfrmr_data["pf"][i]*solution_math["settings"]["power_scale_factor"], - "AvPowerFlow.q" => xfrmr_data["qf"][i]*solution_math["settings"]["power_scale_factor"], - "AvPowerFlow.endNumber" => end_num, - "Ravens.cimObjectType" => "ArPowerFlow", - ), + data = Dict("AnalysisResultData.DataValues" => Dict( + "AvPowerFlow.p" => tr_data["pf"][i]*solution_math["settings"]["power_scale_factor"], + "AvPowerFlow.q" => tr_data["qf"][i]*solution_math["settings"]["power_scale_factor"], + "AvPowerFlow.endNumber" => end_n, + "Ravens.cimObjectType" => "AvPowerFlow" + ) ) - - end - - push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.PowerFlows"], pf_info) - + _push_result!(solution_ravens, "OperationsResult.PowerFlows", _build_powerflow_entry(phase, cond_eq_type, cond_eq_name, data)) end - # Status for Xfrmrs + # Status if !(cond_eq_name in seen_xfrmrs) - - xfrmr_status = nws_math_data["transformer"][xfrmr_number]["status"] == 1 ? true : false - - # Multinetwork support - if mn_flag == true - - # Curve data - mn_data = Dict() - mn_data["AnalysisResultData.Curve"] = Dict() - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] - - for nw in sorted_nws - mn_info = Dict( - "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], - "ArCurveData.DataValues" => Dict( - "AvStatus.inService" => xfrmr_status - ), + # Original status from data_math + tr_status = nw_data["transformer"][tr_id]["status"] == 1 ? true : false + if mn_flag + data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math,nw -> + begin + if haskey(solution_math["nw"][nw]["transformer"][tr_id], "status") + tr_status = Int(solution_math["nw"][nw]["transformer"][tr_id]["status"]) == 1 ? true : false + end + Dict("AvStatus.inService" => tr_status) + end ) - push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) - end - - status_info = Dict( - "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] ) - else - - status_info = Dict( - "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.DataValues" => Dict( - "AvStatus.inService" => xfrmr_status, - ) - ) - + data = Dict("AnalysisResultData.DataValues" => Dict("AvStatus.inService" => tr_status)) end - - push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Statuses"], status_info) - + _push_result!(solution_ravens, "OperationsResult.Statuses", _build_status_entry(cond_eq_type, cond_eq_name, data)) end - # Store the xfrmr name push!(seen_xfrmrs, "$(cond_eq_name)") - end - # Edge elements (branches, switches) - edge_elements = ["branch", "switch"] - for edge_elmnt in edge_elements - - for (edge_number, edge_data) in get(solution, edge_elmnt, Dict{Any,Dict{String,Any}}()) - + # --- Edge elements (branches, switches, etc.) --- + edge_elements = ["branch", "switch"] + for ed in edge_elements + for (ed_id, ed_data) in get(sol, ed, Dict{Any,Dict{String,Any}}()) # Filter virtual elements that exist in the MATH model - if !occursin("virtual", nws_math_data[edge_elmnt][edge_number]["name"]) - - cond_eq_type = split(nws_math_data[edge_elmnt][edge_number]["source_id"], '.')[1] - cond_eq_name = split(nws_math_data[edge_elmnt][edge_number]["source_id"], '.')[2] - - # Add Switch state (only switches) - if edge_elmnt == "switch" - - # initial state from math network data - sw_state = nws_math_data[edge_elmnt][edge_number]["state"] == 1 ? false : true - - if mn_flag == true - - # Curve data - mn_data = Dict() - mn_data["AnalysisResultData.Curve"] = Dict() - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] - - for nw in sorted_nws - if haskey(solution_math["nw"][nw][edge_elmnt][edge_number], "state") - sw_state = Int(solution_math["nw"][nw][edge_elmnt][edge_number]["state"]) == 0 ? true : false - end - mn_info = Dict( - "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], - "ArCurveData.DataValues" => Dict( - "AvSwitch.open" => sw_state, - ), + if !occursin("virtual", nw_data[ed][ed_id]["name"]) + cond_eq_type = split(nw_data[ed][ed_id]["source_id"], '.')[1] + cond_eq_name = split(nw_data[ed][ed_id]["source_id"], '.')[2] + # ---- EXCLUSIVE state for Switches ---- + if ed == "switch" + # initial state from math network data + sw_state = nw_data[ed][ed_id]["state"] == 1 ? false : true + if mn_flag + data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math, nw -> + begin + nw_ed = solution_math["nw"][nw][ed][ed_id] + if haskey(nw_ed, "state") + sw_state = Int(nw_ed["state"]) == 0 ? true : false + end + Dict("AvSwitch.open" => sw_state) + end ) - push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) - end - - state_info = Dict( - "ArSwitch.Switch" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] ) - else - state_info = Dict( - "ArSwitch.Switch" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.DataValues" => Dict( - "AvSwitch.open" => sw_state, - ) - ) - - end - - push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Switches"], state_info) - - end - - - num_ends = 2 - # # OPTIONAL opt out of edge elements to write from and to flows - # if edge_elmnt != "transformer" - # num_ends = 1 - # end - - for end_num in 1:num_ends # loop through ends - if end_num == 1 - connection_flow = "f_connections" - p_flow_direction = "pf" - q_flow_direction = "qf" - else end_num == 2 - connection_flow = "t_connections" - p_flow_direction = "pt" - q_flow_direction = "qt" + data = Dict("AnalysisResultData.DataValues" => Dict("AvSwitch.open" => sw_state)) end - - # Extract the phases for the branch - terminals = nws_math_data[edge_elmnt][edge_number][connection_flow] - phase_kinds = [phase_mapping[x] for x in terminals] - - for (i, result_phase) in enumerate(phase_kinds) - - # Multinetwork support - if mn_flag == true - - # Curve data - mn_data = Dict() - mn_data["AnalysisResultData.Curve"] = Dict() - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] - - for nw in sorted_nws - mn_info = Dict( - "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], - "ArCurveData.DataValues" => Dict( - "AvPowerFlow.p" => solution_math["nw"][nw][edge_elmnt][edge_number][p_flow_direction][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], - "AvPowerFlow.q" => solution_math["nw"][nw][edge_elmnt][edge_number][q_flow_direction][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], - "AvPowerFlow.endNumber" => end_num, - "Ravens.cimObjectType" => "ArPowerFlow", - ), + _push_result!(solution_ravens, "OperationsResult.Switches", _build_switch_entry(cond_eq_type, cond_eq_name, data)) + end + + # --- PowerFlow --- + num_ends = 1 # TODO: (Optional) Change to 2 if you would like to get both 'to' and 'from' flows for edge elements + for end_n in num_ends + # information related to direction flow, terminals, and phases + conn_flow, p_flow, q_flow = end_n == 1 ? ("f_connections", "pf", "qf") : ("t_connections", "pt", "qt") + terminals = nw_data[ed][ed_id][conn_flow] + phases = _get_phases(terminals, phase_mapping) + for (i, phase) in enumerate(phases) + if mn_flag + data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math, nw -> + begin + nw_ed = solution_math["nw"][nw][ed][ed_id] + Dict( + "AvPowerFlow.p" => nw_ed[p_flow][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "AvPowerFlow.q" => nw_ed[q_flow][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "AvPowerFlow.endNumber" => end_n, + "Ravens.cimObjectType" => "AvPowerFlow" + ) + end ) - push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) - end - - pf_info = Dict( - "AnalysisResultData.phase" => result_phase, - "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] ) - else - pf_info = Dict( - "AnalysisResultData.phase" => result_phase, - "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", + data = Dict( "AnalysisResultData.DataValues" => Dict( - "AvPowerFlow.p" => edge_data[p_flow_direction][i]*solution_math["settings"]["power_scale_factor"], - "AvPowerFlow.q" => edge_data[q_flow_direction][i]*solution_math["settings"]["power_scale_factor"], - "AvPowerFlow.endNumber" => end_num, - "Ravens.cimObjectType" => "ArPowerFlow", - ), + "AvPowerFlow.p" => ed_data[p_flow][i]*solution_math["settings"]["power_scale_factor"], + "AvPowerFlow.q" => ed_data[q_flow][i]*solution_math["settings"]["power_scale_factor"], + "AvPowerFlow.endNumber" => end_n, + "Ravens.cimObjectType" => "AvPowerFlow" + ) ) - end - - push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.PowerFlows"], pf_info) - - end + _push_result!(solution_ravens, "OperationsResult.PowerFlows", _build_powerflow_entry(phase, cond_eq_type, cond_eq_name, data)) + end + end + + # --- Statuses ---- + obj_prfx = "" + if ed == "branch" + obj_prfx = "br_" end - # Statuses - object_prefix = "" - if edge_elmnt == "branch" - object_prefix = "br_" - end - - elemtn_status = nws_math_data[edge_elmnt][edge_number]["$(object_prefix)status"] == 1 ? true : false - - # Multinetwork support - if mn_flag == true - - # Curve data - mn_data = Dict() - mn_data["AnalysisResultData.Curve"] = Dict() - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] - - for nw in sorted_nws - mn_info = Dict( - "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], - "ArCurveData.DataValues" => Dict( - "AvStatus.inService" => elemtn_status - ), + ed_status = nw_data[ed][ed_id]["$(obj_prfx)status"] == 1 ? true : false + if mn_flag + data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math, nw -> + begin + if haskey(solution_math["nw"][nw][ed][ed_id], "status") + ed_status = Int(solution_math["nw"][nw][ed][ed_id]["status"]) == 1 ? true : false + end + Dict("AvStatus.inService" => ed_status) + end ) - push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) - end - - status_info = Dict( - "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] ) - else - - status_info = Dict( - "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.DataValues" => Dict( - "AvStatus.inService" => elemtn_status, - ) - ) - + data = Dict("AnalysisResultData.DataValues" => Dict("AvStatus.inService" => ed_status)) end - - push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Statuses"], status_info) + _push_result!(solution_ravens, "OperationsResult.Statuses", _build_status_entry(cond_eq_type, cond_eq_name, data)) end - end end - # Nodal elements (loads, gens) + # --- Node elements (gens, loads, storage) --- node_elements = ["load", "gen", "storage"] - for node_elmnt in node_elements - - for (node_number, node_data) in get(solution, node_elmnt, Dict{Any,Dict{String,Any}}()) - + for nd in node_elements + for (nd_id, nd_data) in get(sol, nd, Dict{Any,Dict{String,Any}}()) # Filter virtual elements that exist in the MATH model - if !occursin("virtual", nws_math_data[node_elmnt][node_number]["name"]) + if !occursin("virtual", nw_data[nd][nd_id]["name"]) + cond_eq_type = split(nw_data[nd][nd_id]["source_id"], '.')[1] + cond_eq_name = split(nw_data[nd][nd_id]["source_id"], '.')[2] + terminals = nw_data[nd][nd_id]["connections"] + phases = _get_phases(terminals, phase_mapping) - cond_eq_type = split(nws_math_data[node_elmnt][node_number]["source_id"], '.')[1] - cond_eq_name = split(nws_math_data[node_elmnt][node_number]["source_id"], '.')[2] - - if node_elmnt == "load" + if nd == "load" p_key = "pd" q_key = "qd" - elseif node_elmnt == "gen" + elseif nd == "gen" p_key = "pg" q_key = "qg" - elseif node_elmnt == "storage" + elseif nd == "storage" p_key = "ps" q_key = "qs" else @@ -448,108 +313,52 @@ function transform_solution_ravens( q_key = "q" end - # Extract the phases for the node element - terminals = nws_math_data[node_elmnt][node_number]["connections"] - phase_kinds = [phase_mapping[x] for x in terminals] - - for (i, result_phase) in enumerate(phase_kinds) - - # Multinetwork support - if mn_flag == true - - # Curve data - mn_data = Dict() - mn_data["AnalysisResultData.Curve"] = Dict() - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] - - for nw in sorted_nws - mn_info = Dict( - "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], - "ArCurveData.DataValues" => Dict( - "AvPowerFlow.p" => solution_math["nw"][nw][node_elmnt][node_number][p_key][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], - "AvPowerFlow.q" => solution_math["nw"][nw][node_elmnt][node_number][q_key][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], - "Ravens.cimObjectType" => "ArPowerFlow", - ), + # PowerFlow + for (i, phase) in enumerate(phases) + if mn_flag + data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math, nw -> + begin + nw_nd = solution_math["nw"][nw][nd][nd_id] + Dict( + "AvPowerFlow.p" => nw_nd[p_key][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "AvPowerFlow.q" => nw_nd[q_key][i]*solution_math["nw"][nw]["settings"]["power_scale_factor"], + "Ravens.cimObjectType" => "AvPowerFlow" + ) + end ) - push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) - end - - pf_info = Dict( - "AnalysisResultData.phase" => result_phase, - "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] ) - - else - - pf_info = Dict( - "AnalysisResultData.phase" => result_phase, - "ArPowerFlow.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.DataValues" => Dict( - "AvPowerFlow.p" => node_data[p_key][i]*solution_math["settings"]["power_scale_factor"], - "AvPowerFlow.q" => node_data[q_key][i]*solution_math["settings"]["power_scale_factor"], - "Ravens.cimObjectType" => "ArPowerFlow", - ), + data = Dict("AnalysisResultData.DataValues" => Dict( + "AvPowerFlow.p" => nd_data[p_key][i]*solution_math["settings"]["power_scale_factor"], + "AvPowerFlow.q" => nd_data[q_key][i]*solution_math["settings"]["power_scale_factor"], + "Ravens.cimObjectType" => "AvPowerFlow" + ) ) - end - - push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.PowerFlows"], pf_info) - + _push_result!(solution_ravens, "OperationsResult.PowerFlows", _build_powerflow_entry(phase, cond_eq_type, cond_eq_name, data)) end - - # Statuses - object_prefix = "" - if node_elmnt == "gen" - object_prefix = "gen_" + # --- Statuses ---- + obj_prfx = "" + if nd == "gen" + obj_prfx = "gen_" end - # original status from math data - elemtn_status = nws_math_data[node_elmnt][node_number]["$(object_prefix)status"] == 1 ? true : false - - # Multinetwork support - if mn_flag == true - - # Curve data - mn_data = Dict() - mn_data["AnalysisResultData.Curve"] = Dict() - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.xUnit"] = "UnitSymbol.h" - mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"] = [] - - for nw in sorted_nws - if haskey(solution_math["nw"][nw][node_elmnt][node_number], "status") - elemtn_status = Int(solution_math["nw"][nw][node_elmnt][node_number]["status"]) == 1 ? true : false - end - mn_info = Dict( - "ArCurveData.xvalue" => parse(Float64, nw)*data_math["nw"][nw]["time_elapsed"], - "ArCurveData.DataValues" => Dict( - "AvStatus.inService" => elemtn_status - ), + nd_status = nw_data[nd][nd_id]["$(obj_prfx)status"] == 1 ? true : false + if mn_flag + data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math, nw -> + begin + if haskey(solution_math["nw"][nw][nd][nd_id], "status") + nd_status = Int(solution_math["nw"][nw][nd][nd_id]["status"]) == 1 ? true : false + end + Dict("AvStatus.inService" => nd_status) + end ) - push!(mn_data["AnalysisResultData.Curve"]["AnalysisResultCurve.CurveDatas"], mn_info) - end - - status_info = Dict( - "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.Curve" => mn_data["AnalysisResultData.Curve"] ) - else - - status_info = Dict( - "ArStatus.ConductingEquipment" => "$(cond_eq_type)::'$(cond_eq_name)'", - "AnalysisResultData.DataValues" => Dict( - "AvStatus.inService" => elemtn_status, - ) - ) - + data = Dict("AnalysisResultData.DataValues" => Dict("AvStatus.inService" => nd_status)) end - - push!(solution_ravens["AnalysisResult"]["OptimalPowerFlow"]["OperationsResult.Statuses"], status_info) - + _push_result!(solution_ravens, "OperationsResult.Statuses", _build_status_entry(cond_eq_type, cond_eq_name, data)) end end end @@ -557,3 +366,6 @@ function transform_solution_ravens( return solution_ravens end + + + diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 1bd335bc5..ddff63fdc 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1723,9 +1723,14 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data end # Set vg + if nconductors > 1 + m = sqrt(3) + else + m = 1 + end for (fr_k, to_k) in [("PowerElectronicsConnection.ratedU", "vg")] if haskey(ravens_obj, fr_k) - math_obj[to_k] = (ravens_obj[fr_k]/nominal_voltage)*ones(nconductors)/voltage_scale_factor + math_obj[to_k] = (nominal_voltage/m)*ones(nconductors)/voltage_scale_factor end end From 0d5b87dedebe99ddb07762ae9c94bebbe628d198 Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 29 Sep 2025 15:21:52 -0600 Subject: [PATCH 92/99] ADD: fix function for numerical errors in states coming from solvers and add new utils function to extract type from name in RAVENS. --- src/data_model/transformations/math2ravens.jl | 29 ++++++++++++++++++- src/data_model/utils_ravens.jl | 7 +++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/data_model/transformations/math2ravens.jl b/src/data_model/transformations/math2ravens.jl index 89e8354fa..0f83d2f72 100644 --- a/src/data_model/transformations/math2ravens.jl +++ b/src/data_model/transformations/math2ravens.jl @@ -51,6 +51,27 @@ function _build_switch_entry(eq_type, eq_name, data) end +# -------- FIX States solution from Gurobi ---- Some "state" values for switches are -1.0287133995719573e-10 +function _zero_tiny(x; tol=1e-9) + return abs(x) < tol ? 0.0 : x +end + +function _fix_noninteger_states!(solution_math; mn_flag::Bool=false) + if mn_flag + for (nw_id, nw_data) in solution_math["nw"] + for (sw_id, sw_sol) in nw_data["switch"] + sw_sol["state"] = _zero_tiny(sw_sol["state"]) + end + end + else + for (sw_id, sw_sol) in solution_math["switch"] + sw_sol["state"] = _zero_tiny(sw_sol["state"]) + end + end +end + +################################# + function transform_solution_ravens( solution_math::Dict{String,<:Any}, @@ -60,7 +81,8 @@ function transform_solution_ravens( convert_rad2deg::Bool=true, map_math2eng_extensions::Dict{String,<:Function}=Dict{String,Function}(), make_si_extensions::Vector{<:Function}=Function[], - dimensionalize_math_extensions::Dict{String,<:Dict{String,<:Vector{<:String}}}=Dict{String,Dict{String,Vector{String}}}() + dimensionalize_math_extensions::Dict{String,<:Dict{String,<:Vector{<:String}}}=Dict{String,Dict{String,Vector{String}}}(), + fix_switch_states::Bool=false )::Dict{String,Any} @assert ismath(data_math) "cannot be converted. Not a MATH model." @@ -82,6 +104,11 @@ function transform_solution_ravens( sol = mn_flag ? solution_math["nw"]["1"] : solution_math time_elapsed = get(data_math, "time_elapsed", 1.0) + # Fix Switch states - "state" values for switches are -1.0287133995719573e-10 coming from some solvers + if fix_switch_states + _fix_noninteger_states!(solution_math; mn_flag=mn_flag) + end + # PowerFlow solutions for Transformers elements seen_xfrmrs = Set{String}() # Set to save xfrmr names diff --git a/src/data_model/utils_ravens.jl b/src/data_model/utils_ravens.jl index 62199437d..d6a416174 100644 --- a/src/data_model/utils_ravens.jl +++ b/src/data_model/utils_ravens.jl @@ -113,6 +113,13 @@ function _extract_name(element) return name end +"extracts the type from a ravens reference string" +function _extract_type(element) + + name = replace(split(element, "::")[1], "'" => "") + return name +end + "calculates the shunt admittance matrix based on terminals and b or g" function _calc_shunt_admittance_matrix(terminals, b) From 0a1f48a8cb350d8c71cb98fb05d91fd96d06f5d7 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 30 Sep 2025 16:20:22 -0600 Subject: [PATCH 93/99] ADD: function to round floats to integer in switch states, e.g., 0.999 -> 1 --- src/data_model/transformations/math2ravens.jl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/data_model/transformations/math2ravens.jl b/src/data_model/transformations/math2ravens.jl index 0f83d2f72..33224b470 100644 --- a/src/data_model/transformations/math2ravens.jl +++ b/src/data_model/transformations/math2ravens.jl @@ -56,16 +56,27 @@ function _zero_tiny(x; tol=1e-9) return abs(x) < tol ? 0.0 : x end +function _round_almost_integer(x; tol=1e-9) + # Get the nearest integer to x. + r = round(Int, x) + + # Check if the absolute difference between x and the nearest integer is within the tolerance. + # If so, return the integer. Otherwise, return the original floating-point number. + return abs(x - r) < tol ? r : x +end + function _fix_noninteger_states!(solution_math; mn_flag::Bool=false) if mn_flag for (nw_id, nw_data) in solution_math["nw"] for (sw_id, sw_sol) in nw_data["switch"] sw_sol["state"] = _zero_tiny(sw_sol["state"]) + sw_sol["state"] = _round_almost_integer(sw_sol["state"]) end end else for (sw_id, sw_sol) in solution_math["switch"] sw_sol["state"] = _zero_tiny(sw_sol["state"]) + sw_sol["state"] = _round_almost_integer(sw_sol["state"]) end end end From 62c4ecf35113021e28a4db50100a36141418c23d Mon Sep 17 00:00:00 2001 From: jjospina Date: Wed, 1 Oct 2025 10:19:11 -0600 Subject: [PATCH 94/99] FIX: increase tol for integers conversion in switch states. --- src/data_model/transformations/math2ravens.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data_model/transformations/math2ravens.jl b/src/data_model/transformations/math2ravens.jl index 33224b470..414183374 100644 --- a/src/data_model/transformations/math2ravens.jl +++ b/src/data_model/transformations/math2ravens.jl @@ -52,11 +52,11 @@ end # -------- FIX States solution from Gurobi ---- Some "state" values for switches are -1.0287133995719573e-10 -function _zero_tiny(x; tol=1e-9) +function _zero_tiny(x; tol=1e-6) return abs(x) < tol ? 0.0 : x end -function _round_almost_integer(x; tol=1e-9) +function _round_almost_integer(x; tol=1e-6) # Get the nearest integer to x. r = round(Int, x) From f6fe6d09be361f03099965a4f8e1a9f157ea1bac Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 6 Oct 2025 16:43:30 -0600 Subject: [PATCH 95/99] FIX: modify bus type of MATH model based on element status. Correctly assign status in transform solution to ravens based on bus statuses. --- src/data_model/transformations/math2ravens.jl | 20 +++++++ src/data_model/transformations/ravens2math.jl | 58 +++++++++++++++++-- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/data_model/transformations/math2ravens.jl b/src/data_model/transformations/math2ravens.jl index 414183374..5ff228b23 100644 --- a/src/data_model/transformations/math2ravens.jl +++ b/src/data_model/transformations/math2ravens.jl @@ -222,6 +222,15 @@ function transform_solution_ravens( begin if haskey(solution_math["nw"][nw]["transformer"][tr_id], "status") tr_status = Int(solution_math["nw"][nw]["transformer"][tr_id]["status"]) == 1 ? true : false + else + # deduce the element status based on status of t_bus + t_bus_id = nw_data["transformer"][tr_id]["t_bus"] # index for t_bus of edge element + t_bus_status = Int(solution_math["nw"][nw]["bus"]["$(t_bus_id)"]["status"]) + if (t_bus_status == 0) + tr_status = false + else + tr_status = true + end end Dict("AvStatus.inService" => tr_status) end @@ -307,16 +316,27 @@ function transform_solution_ravens( end ed_status = nw_data[ed][ed_id]["$(obj_prfx)status"] == 1 ? true : false + if mn_flag data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math, nw -> begin if haskey(solution_math["nw"][nw][ed][ed_id], "status") ed_status = Int(solution_math["nw"][nw][ed][ed_id]["status"]) == 1 ? true : false + else + # deduce the element status based on status of t_bus + t_bus_id = nw_data[ed][ed_id]["t_bus"] # index for t_bus of edge element + t_bus_status = Int(solution_math["nw"][nw]["bus"]["$(t_bus_id)"]["status"]) + if (t_bus_status == 0) + ed_status = false + else + ed_status = true + end end Dict("AvStatus.inService" => ed_status) end ) ) + else data = Dict("AnalysisResultData.DataValues" => Dict("AvStatus.inService" => ed_status)) end diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index ddff63fdc..4537e2a5c 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -529,6 +529,11 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: end math_obj["br_status"] = get(ravens_obj, "Equipment.inService", true) == true ? 1 : 0 + bus_data = data_math["bus"][string(math_obj["t_bus"])] + if(math_obj["br_status"] == 0) + bus_data["bus_type"] = 4 + end + data_math["branch"]["$(math_obj["index"])"] = math_obj push!(data_math["map"], Dict{String,Any}( @@ -1386,7 +1391,11 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end # Set bus type to PQ bus - bus_conn["bus_type"] = 1 + if(math_obj["status"] == 0) + bus_conn["bus_type"] = 4 + else + bus_conn["bus_type"] = 1 + end # Map the object push!(data_math["map"], Dict{String,Any}( @@ -1415,7 +1424,6 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav gen_bus = data_math["bus_lookup"][connectivity_node] math_obj["gen_bus"] = gen_bus bus_conn = data_math["bus"][string(gen_bus)] - bus_conn["bus_type"] = 3 # Set bus type to PV bus # Handle phase-specific or three-phase connection connections = Vector{Int64}() @@ -1452,6 +1460,12 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav math_obj["gen_status"] = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true math_obj["gen_status"] = math_obj["gen_status"] == true ? 1 : 0 + if(math_obj["gen_status"] == 0) + bus_conn["bus_type"] = 4 + else + bus_conn["bus_type"] = 3 + end + math_obj["configuration"] = get(ravens_obj, "EnergySource.connectionKind", WYE) # Set the nominal voltage @@ -1489,7 +1503,12 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav # Check for impedance and adjust bus type if necessary map_to = "gen.$(math_obj["index"])" if !all(isapprox.(rs, 0)) && !all(isapprox.(xs, 0)) - bus_conn["bus_type"] = 1 # Virtual bus becomes the new slack bus + + if(math_obj["gen_status"] == 0) + bus_conn["bus_type"] = 4 + else + bus_conn["bus_type"] = 1 # Virtual bus becomes the new slack bus + end bus_obj = Dict( "bus_i" => length(data_math["bus"]) + 1, @@ -1600,7 +1619,12 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ end # Set bus type - bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] + if(status == 0) + bus_type = 4 + else + bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] + end + data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) # Set the nominal voltage @@ -1704,7 +1728,12 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) # Set bus type - bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] + if(status == 0) + bus_type = 4 + else + bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] + end + data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) # Set the nominal voltage @@ -1870,7 +1899,12 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data math_obj["qs"] = (-get(ravens_obj, "PowerElectronicsConnection.q", 0.0))./(power_scale_factor) # Set bus type - bus_type = data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] + if(status == 0) + bus_type = 4 + else + bus_type = data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] + end + data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) if control_mode == Int(ISOCHRONOUS) && math_obj["status"] == 1 @@ -1947,6 +1981,10 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di # Status status = get(ravens_obj, "Equipment.inService", true) math_obj["status"] = status == true ? 1 : 0 + bus_data = data_math["bus"][string(math_obj["t_bus"])] + if(status == 0) + bus_data["bus_type"] = 4 + end # State sw_state = CLOSED @@ -2022,6 +2060,14 @@ function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data status = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true math_obj["status"] = status == true ? 1 : 0 + bus_info = string(math_obj["shunt_bus"]) + bus_conn = data_math["bus"][bus_info] + if(math_obj["status"] == 0) + bus_conn["bus_type"] = 4 + else + bus_conn["bus_type"] = 1 + end + # Connections/phases obtained from Terminals connections = _phasecode_map[get(ravens_obj["ConductingEquipment.Terminals"][1], "Terminal.phases", "PhaseCode.ABC")] From 9cc29614225a16ca6b3f1891ccd2c9b8ed1fdd8c Mon Sep 17 00:00:00 2001 From: jjospina Date: Mon, 6 Oct 2025 23:33:02 -0600 Subject: [PATCH 96/99] REF: default status of buses to bus type = 4 assuming they are disabled and as the model is parsed the buses type are updated based on the statuses of the elements connected to the respective buses. --- src/data_model/transformations/math2ravens.jl | 10 +++- src/data_model/transformations/ravens2math.jl | 59 +++++++++---------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/data_model/transformations/math2ravens.jl b/src/data_model/transformations/math2ravens.jl index 5ff228b23..f578575e2 100644 --- a/src/data_model/transformations/math2ravens.jl +++ b/src/data_model/transformations/math2ravens.jl @@ -223,10 +223,12 @@ function transform_solution_ravens( if haskey(solution_math["nw"][nw]["transformer"][tr_id], "status") tr_status = Int(solution_math["nw"][nw]["transformer"][tr_id]["status"]) == 1 ? true : false else - # deduce the element status based on status of t_bus + # deduce the element status based on status of f_bus - t_bus + f_bus_id = nw_data["transformer"][tr_id]["f_bus"] # index for f_bus of edge element t_bus_id = nw_data["transformer"][tr_id]["t_bus"] # index for t_bus of edge element + f_bus_status = Int(solution_math["nw"][nw]["bus"]["$(f_bus_id)"]["status"]) t_bus_status = Int(solution_math["nw"][nw]["bus"]["$(t_bus_id)"]["status"]) - if (t_bus_status == 0) + if (f_bus_status == 0 || t_bus_status == 0) tr_status = false else tr_status = true @@ -324,9 +326,11 @@ function transform_solution_ravens( ed_status = Int(solution_math["nw"][nw][ed][ed_id]["status"]) == 1 ? true : false else # deduce the element status based on status of t_bus + f_bus_id = nw_data[ed][ed_id]["f_bus"] # index for f_bus of edge element t_bus_id = nw_data[ed][ed_id]["t_bus"] # index for t_bus of edge element + f_bus_status = Int(solution_math["nw"][nw]["bus"]["$(f_bus_id)"]["status"]) t_bus_status = Int(solution_math["nw"][nw]["bus"]["$(t_bus_id)"]["status"]) - if (t_bus_status == 0) + if (f_bus_status == 0 || t_bus_status == 0) ed_status = false else ed_status = true diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index 4537e2a5c..c1420bb44 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -244,7 +244,7 @@ function _map_ravens2math_connectivity_node!(data_math::Dict{String,<:Any}, data # Set basic bus properties math_obj["bus_i"] = index math_obj["source_id"] = "ConnectivityNode.$name" - math_obj["bus_type"] = 1 # Default bus_type, will be modified as needed + math_obj["bus_type"] = 4 # Default bus_type, - DISABLED math_obj["vm_pair_lb"] = Tuple{Any, Any, Real}[] math_obj["vm_pair_ub"] = Tuple{Any, Any, Real}[] @@ -529,9 +529,11 @@ function _map_ravens2math_conductor!(data_math::Dict{String,<:Any}, data_ravens: end math_obj["br_status"] = get(ravens_obj, "Equipment.inService", true) == true ? 1 : 0 - bus_data = data_math["bus"][string(math_obj["t_bus"])] - if(math_obj["br_status"] == 0) - bus_data["bus_type"] = 4 + f_bus_data = data_math["bus"][string(math_obj["f_bus"])] + t_bus_data = data_math["bus"][string(math_obj["t_bus"])] + if(math_obj["br_status"] == 1) + f_bus_data["bus_type"] = 1 + t_bus_data["bus_type"] = 1 end data_math["branch"]["$(math_obj["index"])"] = math_obj @@ -1391,9 +1393,7 @@ function _map_ravens2math_energy_consumer!(data_math::Dict{String,<:Any}, data_r end # Set bus type to PQ bus - if(math_obj["status"] == 0) - bus_conn["bus_type"] = 4 - else + if(math_obj["status"] == 1) bus_conn["bus_type"] = 1 end @@ -1460,9 +1460,7 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav math_obj["gen_status"] = haskey(ravens_obj, "Equipment.inService") ? ravens_obj["Equipment.inService"] : true math_obj["gen_status"] = math_obj["gen_status"] == true ? 1 : 0 - if(math_obj["gen_status"] == 0) - bus_conn["bus_type"] = 4 - else + if(math_obj["gen_status"] == 1) bus_conn["bus_type"] = 3 end @@ -1504,10 +1502,10 @@ function _map_ravens2math_energy_source!(data_math::Dict{String,<:Any}, data_rav map_to = "gen.$(math_obj["index"])" if !all(isapprox.(rs, 0)) && !all(isapprox.(xs, 0)) - if(math_obj["gen_status"] == 0) - bus_conn["bus_type"] = 4 + if(math_obj["gen_status"] == 1) + bus_conn["bus_type"] = 1 else - bus_conn["bus_type"] = 1 # Virtual bus becomes the new slack bus + bus_conn["bus_type"] = 4 # Virtual bus becomes the new slack bus end bus_obj = Dict( @@ -1619,10 +1617,9 @@ function _map_ravens2math_rotating_machine!(data_math::Dict{String,<:Any}, data_ end # Set bus type - if(status == 0) - bus_type = 4 - else - bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] + bus_type = 4 + if(status == 1) + bus_type = 1 end data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) @@ -1728,10 +1725,9 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data math_obj["control_mode"] = control_mode = Int(get(ravens_obj, "control_mode", FREQUENCYDROOP)) # Set bus type - if(status == 0) - bus_type = 4 - else - bus_type = data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] + bus_type = 4 + if(status == 1) + bus_type = 1 end data_math["bus"]["$(math_obj["gen_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) @@ -1899,10 +1895,9 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data math_obj["qs"] = (-get(ravens_obj, "PowerElectronicsConnection.q", 0.0))./(power_scale_factor) # Set bus type - if(status == 0) - bus_type = 4 - else - bus_type = data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] + bus_type = 4 + if(status == 1) + bus_type = 1 end data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) @@ -1981,9 +1976,12 @@ function _map_ravens2math_switch!(data_math::Dict{String,<:Any}, data_ravens::Di # Status status = get(ravens_obj, "Equipment.inService", true) math_obj["status"] = status == true ? 1 : 0 - bus_data = data_math["bus"][string(math_obj["t_bus"])] - if(status == 0) - bus_data["bus_type"] = 4 + + f_bus_data = data_math["bus"][string(math_obj["f_bus"])] + t_bus_data = data_math["bus"][string(math_obj["t_bus"])] + if(math_obj["status"] == 1) + f_bus_data["bus_type"] = 1 + t_bus_data["bus_type"] = 1 end # State @@ -2062,9 +2060,8 @@ function _map_ravens2math_shunt_compensator!(data_math::Dict{String,<:Any}, data bus_info = string(math_obj["shunt_bus"]) bus_conn = data_math["bus"][bus_info] - if(math_obj["status"] == 0) - bus_conn["bus_type"] = 4 - else + + if(math_obj["status"] == 1) bus_conn["bus_type"] = 1 end From 5ac12f3912b5b1792d70215898ff98096398cbc1 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 9 Oct 2025 08:55:51 -0600 Subject: [PATCH 97/99] FIX: reduce tolerance for rounding Gurobi solutions. --- src/data_model/transformations/math2ravens.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data_model/transformations/math2ravens.jl b/src/data_model/transformations/math2ravens.jl index f578575e2..b4734910b 100644 --- a/src/data_model/transformations/math2ravens.jl +++ b/src/data_model/transformations/math2ravens.jl @@ -52,11 +52,11 @@ end # -------- FIX States solution from Gurobi ---- Some "state" values for switches are -1.0287133995719573e-10 -function _zero_tiny(x; tol=1e-6) +function _zero_tiny(x; tol=1e-4) return abs(x) < tol ? 0.0 : x end -function _round_almost_integer(x; tol=1e-6) +function _round_almost_integer(x; tol=1e-4) # Get the nearest integer to x. r = round(Int, x) From e26956a594e71e9ce76889f2db0952d44eb2ed08 Mon Sep 17 00:00:00 2001 From: jjospina Date: Thu, 9 Oct 2025 14:48:32 -0600 Subject: [PATCH 98/99] ADD: capability to add GFM bus type of bus connected to battery with GFM information. --- src/data_model/transformations/ravens2math.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/data_model/transformations/ravens2math.jl b/src/data_model/transformations/ravens2math.jl index c1420bb44..97270e4ff 100644 --- a/src/data_model/transformations/ravens2math.jl +++ b/src/data_model/transformations/ravens2math.jl @@ -1898,6 +1898,12 @@ function _map_ravens2math_power_electronics!(data_math::Dict{String,<:Any}, data bus_type = 4 if(status == 1) bus_type = 1 + if haskey(ravens_obj, "PowerElectronicsConnection.PowerElectronicsOperatingMode") + mode = ravens_obj["PowerElectronicsConnection.PowerElectronicsOperatingMode"]["PowerElectronicsOperatingMode.mode"] + if mode == "OperatingModeKind.gridForming" + bus_type = 2 + end + end end data_math["bus"]["$(math_obj["storage_bus"])"]["bus_type"] = _compute_bus_type(bus_type, status, control_mode) From 6c204d99074879f058136e10012f184cb64f1545 Mon Sep 17 00:00:00 2001 From: jjospina Date: Tue, 14 Oct 2025 12:38:13 -0600 Subject: [PATCH 99/99] FIX: filter virtual buses in OPF solutions RAVENS. --- src/data_model/transformations/math2ravens.jl | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/data_model/transformations/math2ravens.jl b/src/data_model/transformations/math2ravens.jl index b4734910b..a1e5c5fb5 100644 --- a/src/data_model/transformations/math2ravens.jl +++ b/src/data_model/transformations/math2ravens.jl @@ -146,32 +146,35 @@ function transform_solution_ravens( phases = _get_phases(terminals, phase_mapping) conn_node = split(nw_data["bus"][bus_id]["source_id"], '.')[2] - for (i, phase) in enumerate(phases) - if mn_flag - data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math, nw -> - begin - nw_bus = solution_math["nw"][nw]["bus"][bus_id] - v_info = Dict( - "AvVoltage.v" => nw_bus["vm"][i] * solution_math["nw"][nw]["settings"]["voltage_scale_factor"], - "Ravens.cimObjectType" => "AvVoltage" - ) - # Conditionally add the angle (some do not have it) - if haskey(nw_bus, "va") - v_info["AvVoltage.angle"] = nw_bus["va"][i] + # Filter virtual buses that exist in the MATH model + if !occursin("virtual", nw_data["bus"][bus_id]["name"]) + for (i, phase) in enumerate(phases) + if mn_flag + data = Dict("AnalysisResultData.Curve" => _make_curve_data(nws, data_math, nw -> + begin + nw_bus = solution_math["nw"][nw]["bus"][bus_id] + v_info = Dict( + "AvVoltage.v" => nw_bus["vm"][i] * solution_math["nw"][nw]["settings"]["voltage_scale_factor"], + "Ravens.cimObjectType" => "AvVoltage" + ) + # Conditionally add the angle (some do not have it) + if haskey(nw_bus, "va") + v_info["AvVoltage.angle"] = nw_bus["va"][i] + end + return v_info end - return v_info - end + ) ) - ) - else - data = Dict("AnalysisResultData.DataValues" => Dict( - "AvVoltage.v" => bus_data["vm"][i] * solution_math["settings"]["voltage_scale_factor"], - "AvVoltage.angle" => bus_data["va"][i], - "Ravens.cimObjectType" => "AvVoltage" + else + data = Dict("AnalysisResultData.DataValues" => Dict( + "AvVoltage.v" => bus_data["vm"][i] * solution_math["settings"]["voltage_scale_factor"], + "AvVoltage.angle" => bus_data["va"][i], + "Ravens.cimObjectType" => "AvVoltage" + ) ) - ) + end + _push_result!(solution_ravens, "OperationsResult.Voltages", _build_voltage_entry(phase, conn_node, data)) end - _push_result!(solution_ravens, "OperationsResult.Voltages", _build_voltage_entry(phase, conn_node, data)) end end