Network Data Format

PowerModels Network Data Format

The Network Data Dictionary

Internally PowerModels utilizes a dictionary to store network data. The dictionary uses strings as key values so it can be serialized to JSON for algorithmic data exchange.

The data dictionary organization and key names are designed to be consistent with the Matpower file format and should be familiar to power system researchers, with the exception that loads and shunts are now split into separate components (see example below).

The network data dictionary structure is roughly as follows:

{
"name":<string>,
"version":"2",
"baseMVA":<float>,
"bus":{
    "1":{
        "index":<int>,
        "bus_type":<int>,
        "va":<float>,
        "vm":<float>,
        ...
    },
    "2":{...},
    ...
},
"load":{
    "1":{
        "index":<int>,
        "load_bus":<int>,
        "pd":<float>,
        "qd":<float>,
        ...
    },
    "2":{...},
    ...
},
"shunt":{
    "1":{
        "index":<int>,
        "shunt_bus":<int>,
        "gs":<float>,
        "bs":<float>,
        ...
    },
    "2":{...},
    ...
},
"gen":{
    "1":{
        "index":<int>,
        "gen_bus":<int>,
        "pg":<float>,
        "qg":<float>,
        ...
    },
    "2":{...},
    ...
},
"branch":{
    "1":{
        "index":<int>,
        "f_bus":<int>,
        "t_bus":<int>,
        "br_r":<float>,
        ...
    },
    "2":{...},
    ...
}
}

The following commands can be used to explore the network data dictionary generated by a given Matpower data file,

network_data = PowerModels.parse_file("nesta_case3_lmbd.m")
display(network_data) # raw dictionary
PowerModels.print_summary(network_data) # quick table-like summary

The print_summary function generates a table-like text summary of the network data, which is helpful in quickly assessing the values in a data or solution dictionary.

For a detailed list of all possible parameters refer to the specification document provided with Matpower. The exception to this is that "load" and "shunt", containing "pd", "qd" and "gs", "bs", respectively, have been added as additional fields. These values are contained in "bus" in the original specification.

Noteworthy Differences from Matpower Data Files

The PowerModels network data dictionary differs from the Matpower format in the following ways,

Working with the Network Data Dictionary

Data exchange via JSON files is ideal for building algorithms, however it is hard to for humans to read and process. To that end PowerModels provides various helper functions for manipulating the network data dictionary.

The first of these helper functions are make_per_unit and make_mixed_units, which convert the units of the data inside a network data dictionary. The mixed units format follows the unit conventions from Matpower and other common power network formats where some of the values are in per unit and others are the true values. These functions can be used as follows,

network_data = PowerModels.parse_file("nesta_case3_lmbd.m")
PowerModels.print_summary(network_data) # default per-unit form
PowerModels.make_mixed_units(network_data)
PowerModels.print_summary(network_data) # mixed units form

Another useful helper function is update_data, which takes two network data dictionaries and updates the values in the first dictionary with the values from the second dictionary. This is particularly helpful when applying sparse updates to network data. A good example is using the solution of one computation to update the data in preparation for a second computation, like so,

data = PowerModels.parse_file("nesta_case3_lmbd.m")
opf_result = run_ac_opf(data, IpoptSolver())
PowerModels.print_summary(opf_result["solution"])

PowerModels.update_data(data, opf_result["solution"])
pf_result = run_ac_pf(data, IpoptSolver())
PowerModels.print_summary(pf_result["solution"])

A variety of helper functions are available for processing the topology of the network. For example, connected_components will compute the collections of buses that are connected by branches (i.e. the network's islands). By default PowerModels will attempt to solve all of the network components simultaneously. The select_largest_component function can be used to only consider the largest component in the network. Finally the propagate_topology_status can be used to explicitly deactivate components that are implicitly inactive due to the status of other components (e.g. deactivating branches based on the status of their connecting buses), like so,

data = PowerModels.parse_file("nesta_case3_lmbd.m")
PowerModels.propagate_topology_status(data)
opf_result = run_ac_opf(data, IpoptSolver())

The test/data/case7_tplgy.m case provides an example of the kind of component status deductions that can be made. The propagate_topology_status function can be helpful in diagnosing network models that converge to an infeasible solution.

For details on all of the network data helper functions see, src/core/data.jl.

Working with Matpower Data Files

PowerModels has extensive support for parsing Matpower network files in the .m format.

In addition to parsing the standard Matpower parameters, PowerModels also supports extending the standard Matpower format in a number of ways as illustrated by the following examples. In these examples JSON document fragments are used to indicate the structure of the PowerModel dictionary.

Note that for DC lines, the flow results are returned using the same convention as for the AC lines, i.e. positive values for p_from/q_fromand p_to/q_to indicating power flow from the 'to' node or 'from' node into the line. This means that w.r.t matpower the sign is identical for p_from, but opposite for q_from/p_to/q_to.

Single Values

Single values are added to the root of the dictionary as follows,

mpc.const_float = 4.56

becomes

{
"const_float": 4.56
}

Nonstandard Matrices

Nonstandard matrices can be added as follows,

mpc.areas = [
    1   1;
    2   3;
];

becomes

{
"areas":{
    "1":{
        "index":1,
        "col_1":1,
        "col_2":1
    },
    "2":{
        "index":1,
        "col_1":2,
        "col_2":3
    }
}
}

Column Names

Column names can be given to nonstandard matrices using the following special comment,

%column_names%  area    refbus
mpc.areas_named = [
    4   5;
    5   6;
];

becomes

{
"areas":{
    "1":{
        "index":1,
        "area":4,
        "refbus":5
    },
    "2":{
        "index":2,
        "area":5,
        "refbus":6
    }
}
}

Standard Matrix Extensions

Finally, if a nonstandard matrix's name extends a current Matpower matrix name with an underscore, then its values will be merged with the original Matpower component data. Note that this feature requires that the nonstandard matrix has column names and has the same number of rows as the original matrix (similar to the gencost matrix in the Matpower format). For example,

%column_names%  rate_i  rate_p
mpc.branch_limit = [
    50.2    45;
    36  60.1;
    12  30;
];

becomes

{
"branch":{
    "1":{
        "index":1,
        ...(all pre existing fields)...
        "rate_i":50.2,
        "rate_p":45
    },
    "2":{
        "index":2,
        ...(all pre existing fields)...
        "rate_i":36,
        "rate_p":60.1
    },
    "3":{
        "index":3,
        ...(all pre existing fields)...
        "rate_i":12,
        "rate_p":30
    }
}
}