Source code for monee.io.matpower

import math

import scipy.io

# Imported so the @model decorator registers them in the model component
# registry that native_dict_to_network resolves the string model_types against.
# These are exactly the concrete model classes this importer constructs (by name).
from monee.model.branch import GenericPowerBranch  # noqa: F401
from monee.model.child import (  # noqa: F401
    ExtPowerGrid,
    PowerGenerator,
    PowerLoad,
)
from monee.model.grid import PowerGrid  # noqa: F401
from monee.model.node import Bus  # noqa: F401

from .native import native_dict_to_network


[docs] def as_controllable(start_value): return {"value": start_value, "max": None, "min": None}
[docs] def number_of_lines_with_from_to(from_node, to_node, branch_list): number = 0 for branch in branch_list: branch_id = branch["id"] if branch_id[0] == from_node and branch_id[1] == to_node: number += 1 return number
[docs] def read_matpower_data(mat_data): mpc = mat_data["mpc"] base_mva = mpc["baseMVA"][0][0][0] bus_mat = mpc["bus"][0][0] branch_mat = mpc["branch"][0][0] gen_mat = mpc["gen"][0][0] grid_dict_list = { "power": { "model_type": "PowerGrid", "values": {"name": "power", "sn_mva": base_mva[0]}, } } node_dict_list = [] branch_dict_list = [] child_dict_list = [] fill_node_dict(bus_mat, node_dict_list, child_dict_list) fill_child_dict(gen_mat, node_dict_list, child_dict_list) fill_branch_dict(branch_mat, branch_dict_list) return native_dict_to_network( { "grids": grid_dict_list, "nodes": node_dict_list, "childs": child_dict_list, "branches": branch_dict_list, } )
[docs] def fill_branch_dict(branch_mat, branch_dict_list): for i in range(len(branch_mat)): branch_dict = {} branch_row = branch_mat[i] branch_dict["values"] = {} branch_dict["grid_id"] = "power" branch_dict["id"] = ( int(branch_row[0]), int(branch_row[1]), number_of_lines_with_from_to( branch_row[0], branch_row[1], branch_dict_list ), ) branch_dict["from_node"] = int(branch_row[0]) branch_dict["to_node"] = int(branch_row[1]) branch_dict["values"]["br_r_pu"] = branch_row[2] branch_dict["values"]["br_x_pu"] = branch_row[3] branch_dict["values"]["g_fr_pu"] = 0 branch_dict["values"]["b_fr_pu"] = branch_row[4] / 2 branch_dict["values"]["g_to_pu"] = 0 branch_dict["values"]["b_to_pu"] = branch_row[4] / 2 branch_dict["values"]["tap"] = 1 if branch_row[8] == 0 else branch_row[8] branch_dict["values"]["shift"] = math.radians(branch_row[9]) branch_dict["values"]["max_i_ka"] = 999 # essentially unbound branch_dict["values"]["on_off"] = 1 branch_dict["model_type"] = "GenericPowerBranch" branch_dict_list.append(branch_dict)
[docs] def fill_child_dict(gen_mat, node_dict_list, child_dict_list): for i in range(len(gen_mat)): child_dict = {} gen_row = gen_mat[i] child_dict["values"] = {} child_dict["id"] = len(child_dict_list) if gen_row[1] != gen_row[8] and gen_row[1] == 0: child_dict["model_type"] = "ExtPowerGrid" child_dict["values"]["p_mw"] = as_controllable(gen_row[1]) child_dict["values"]["q_mvar"] = as_controllable(gen_row[2]) child_dict["values"]["vm_pu"] = gen_row[5] child_dict["values"]["va_degree"] = 0 else: child_dict["model_type"] = "PowerGenerator" child_dict["values"]["p_mw"] = -gen_row[1] child_dict["values"]["q_mvar"] = -gen_row[2] for node_dict in node_dict_list: if node_dict["id"] == gen_row[0]: node_dict["child_ids"].append(child_dict["id"]) child_dict_list.append(child_dict)
[docs] def fill_node_dict(bus_mat, node_dict_list, child_dict_list): for i in range(len(bus_mat)): node_dict = {} bus_row = bus_mat[i] node_dict["id"] = int(bus_row[0]) node_dict["grid_id"] = "power" node_dict["values"] = {} node_dict["values"]["vm_pu"] = as_controllable(bus_row[7]) # Seed the angle decision variable (va_radians); va_degree stays the # model's derived Intermediate (= 180/π·va_radians). Setting va_degree # here would overwrite that Intermediate with a free, unconstrained Var. node_dict["values"]["va_radians"] = { "value": bus_row[8] * math.pi / 180, "min": -math.pi, "max": math.pi, } node_dict["values"]["base_kv"] = bus_row[9] node_dict["model_type"] = "Bus" node_dict["child_ids"] = [] node_dict_list.append(node_dict) if bus_row[2] != 0 or bus_row[3] != 0: node_dict["child_ids"].append(len(child_dict_list)) model_type = "PowerLoad" if bus_row[2] >= 0 else "PowerGenerator" # bus_row[2] is the (signed) bus load. A PowerLoad stores p_mw as-is # (positive = consumption). For the negative-load case a PowerGenerator # built from magnitude abs(bus_row[2]) would store -abs(bus_row[2]), # which equals the already-negative bus_row[2] - so storing the raw # value is correct for both model types here. child_dict_list.append( { "id": len(child_dict_list), "model_type": model_type, "values": {"p_mw": bus_row[2], "q_mvar": bus_row[3]}, } )
[docs] def read_matpower_case(file): return read_matpower_data(scipy.io.loadmat(file))