示例#1
0
def test_demo_5_node(root_path=ROOT_PATH):
    np.core.arrayprint.set_printoptions(precision=4)

    grid = MultiCircuit()

    # Add buses
    bus1 = Bus('Bus 1', vnom=20)
    grid.add_bus(bus1)
    gen1 = Generator('Slack Generator', voltage_module=1.0)
    grid.add_generator(bus1, gen1)

    bus2 = Bus('Bus 2', vnom=20)
    grid.add_bus(bus2)
    grid.add_load(bus2, Load('load 2', P=40, Q=20))

    bus3 = Bus('Bus 3', vnom=20)
    grid.add_bus(bus3)
    grid.add_load(bus3, Load('load 3', P=25, Q=15))

    bus4 = Bus('Bus 4', vnom=20)
    grid.add_bus(bus4)
    grid.add_load(bus4, Load('load 4', P=40, Q=20))

    bus5 = Bus('Bus 5', vnom=20)
    grid.add_bus(bus5)
    grid.add_load(bus5, Load('load 5', P=50, Q=20))

    # add branches (Lines in this case)
    grid.add_line(Line(bus1, bus2, 'line 1-2', r=0.05, x=0.11, b=0.02))
    grid.add_line(Line(bus1, bus3, 'line 1-3', r=0.05, x=0.11, b=0.02))
    grid.add_line(Line(bus1, bus5, 'line 1-5', r=0.03, x=0.08, b=0.02))
    grid.add_line(Line(bus2, bus3, 'line 2-3', r=0.04, x=0.09, b=0.02))
    grid.add_line(Line(bus2, bus5, 'line 2-5', r=0.04, x=0.09, b=0.02))
    grid.add_line(Line(bus3, bus4, 'line 3-4', r=0.06, x=0.13, b=0.03))
    grid.add_line(Line(bus4, bus5, 'line 4-5', r=0.04, x=0.09, b=0.02))
    # grid.plot_graph()
    print('\n\n', grid.name)

    FileSave(grid, 'demo_5_node.json').save()

    options = PowerFlowOptions(SolverType.NR, verbose=False)

    power_flow = PowerFlowDriver(grid, options)
    power_flow.run()

    print_power_flow_results(power_flow=power_flow)
    v = np.array([1., 0.9553, 0.9548, 0.9334, 0.9534])
    all_ok = np.isclose(np.abs(power_flow.results.voltage), v, atol=1e-3)
    return all_ok
示例#2
0
def test_demo_5_node(root_path):
    np.core.arrayprint.set_printoptions(precision=4)

    grid = MultiCircuit()

    # Add buses
    bus1 = Bus('Bus 1', vnom=20)
    # bus1.is_slack = True
    grid.add_bus(bus1)
    gen1 = Generator('Slack Generator', voltage_module=1.0)
    grid.add_generator(bus1, gen1)

    bus2 = Bus('Bus 2', vnom=20)
    grid.add_bus(bus2)
    grid.add_load(bus2, Load('load 2', P=40, Q=20))

    bus3 = Bus('Bus 3', vnom=20)
    grid.add_bus(bus3)
    grid.add_load(bus3, Load('load 3', P=25, Q=15))

    bus4 = Bus('Bus 4', vnom=20)
    grid.add_bus(bus4)
    grid.add_load(bus4, Load('load 4', P=40, Q=20))

    bus5 = Bus('Bus 5', vnom=20)
    grid.add_bus(bus5)
    grid.add_load(bus5, Load('load 5', P=50, Q=20))

    # add branches (Lines in this case)
    grid.add_branch(Branch(bus1, bus2, 'line 1-2', r=0.05, x=0.11, b=0.02))
    grid.add_branch(Branch(bus1, bus3, 'line 1-3', r=0.05, x=0.11, b=0.02))
    grid.add_branch(Branch(bus1, bus5, 'line 1-5', r=0.03, x=0.08, b=0.02))
    grid.add_branch(Branch(bus2, bus3, 'line 2-3', r=0.04, x=0.09, b=0.02))
    grid.add_branch(Branch(bus2, bus5, 'line 2-5', r=0.04, x=0.09, b=0.02))
    grid.add_branch(Branch(bus3, bus4, 'line 3-4', r=0.06, x=0.13, b=0.03))
    grid.add_branch(Branch(bus4, bus5, 'line 4-5', r=0.04, x=0.09, b=0.02))
    # grid.plot_graph()
    print('\n\n', grid.name)

    options = PowerFlowOptions(SolverType.NR, verbose=False)

    power_flow = PowerFlowDriver(grid, options)
    power_flow.run()

    print_power_flow_results(power_flow=power_flow)
示例#3
0
    def parse_bus_bars(self, cim: CIMCircuit, circuit: MultiCircuit):
        """

        :param cim:
        :param circuit:
        :return:
        """

        busbar_dict = dict()

        if 'BusbarSection' in cim.elements_by_type.keys():
            for elm in cim.elements_by_type['BusbarSection']:

                obj = gcdev.Bus(name=str(elm.name), idtag=elm.uuid)

                circuit.add_bus(obj)

                busbar_dict[elm] = obj
        else:
            self.logger.add_error(
                "No BusbarSections: There is no chance to reduce the grid")

        return busbar_dict
def test_xfo_static_tap_3():
    """
    Basic test with the main transformer's  HV tap (X_C3) set at -2.5%
    (0.975 pu), which raises the LV by the same amount (+2.5%).
    """
    test_name = "test_xfo_static_tap_3"
    grid = MultiCircuit(name=test_name)
    grid.Sbase = Sbase
    grid.time_profile = None
    grid.logger = Logger()

    # Create buses
    POI = Bus(
        name="POI",
        vnom=100,  # kV
        is_slack=True)
    grid.add_bus(POI)

    B_C3 = Bus(name="B_C3", vnom=10)  # kV
    grid.add_bus(B_C3)

    B_MV_M32 = Bus(name="B_MV_M32", vnom=10)  # kV
    grid.add_bus(B_MV_M32)

    B_LV_M32 = Bus(name="B_LV_M32", vnom=0.6)  # kV
    grid.add_bus(B_LV_M32)

    # Create voltage controlled generators (or slack, a.k.a. swing)
    UT = Generator(name="Utility")
    UT.bus = POI
    grid.add_generator(POI, UT)

    # Create static generators (with fixed power factor)
    M32 = StaticGenerator(name="M32", P=4.2, Q=0.0)  # MVA (complex)
    M32.bus = B_LV_M32
    grid.add_static_generator(B_LV_M32, M32)

    # Create transformer types
    s = 5  # MVA
    z = 8  # %
    xr = 40
    SS = TransformerType(
        name="SS",
        hv_nominal_voltage=100,  # kV
        lv_nominal_voltage=10,  # kV
        nominal_power=s,
        copper_losses=complex_impedance(z, xr).real * s * 1000 / Sbase,
        iron_losses=6.25,  # kW
        no_load_current=0.5,  # %
        short_circuit_voltage=z)
    grid.add_transformer_type(SS)

    s = 5  # MVA
    z = 6  # %
    xr = 20
    PM = TransformerType(
        name="PM",
        hv_nominal_voltage=10,  # kV
        lv_nominal_voltage=0.6,  # kV
        nominal_power=s,
        copper_losses=complex_impedance(z, xr).real * s * 1000 / Sbase,
        iron_losses=6.25,  # kW
        no_load_current=0.5,  # %
        short_circuit_voltage=z)
    grid.add_transformer_type(PM)

    # Create branches
    X_C3 = Branch(bus_from=POI,
                  bus_to=B_C3,
                  name="X_C3",
                  branch_type=BranchType.Transformer,
                  template=SS,
                  tap=0.975)
    # update to a more precise tap changer
    X_C3.apply_tap_changer(
        TapChanger(taps_up=20, taps_down=20, max_reg=1.1, min_reg=0.9))
    grid.add_branch(X_C3)

    C_M32 = Branch(bus_from=B_C3,
                   bus_to=B_MV_M32,
                   name="C_M32",
                   r=0.784,
                   x=0.174)
    grid.add_branch(C_M32)

    X_M32 = Branch(bus_from=B_MV_M32,
                   bus_to=B_LV_M32,
                   name="X_M32",
                   branch_type=BranchType.Transformer,
                   template=PM)
    grid.add_branch(X_M32)

    # Apply templates (device types)
    grid.apply_all_branch_types()

    print("Buses:")
    for i, b in enumerate(grid.buses):
        print(f" - bus[{i}]: {b}")
    print()

    options = PowerFlowOptions(SolverType.NR,
                               verbose=True,
                               initialize_with_existing_solution=True,
                               multi_core=True,
                               control_q=ReactivePowerControlMode.Direct,
                               tolerance=1e-6,
                               max_iter=15)

    power_flow = PowerFlowDriver(grid, options)
    power_flow.run()

    print()
    print(f"Test: {test_name}")
    print()

    print("Generators:")
    for g in grid.get_generators():
        print(f" - Generator {g}: q_min={g.Qmin} MVAR, q_max={g.Qmax} MVAR")
    print()

    print("Branches:")
    for b in grid.branches:
        print(f" - {b}:")
        print(f"   R = {round(b.R, 4)} pu")
        print(f"   X = {round(b.X, 4)} pu")
        print(f"   X/R = {round(b.X/b.R, 1)}")
        print(f"   G = {round(b.G, 4)} pu")
        print(f"   B = {round(b.B, 4)} pu")
    print()

    print("Transformer types:")
    for t in grid.transformer_types:
        print(f" - {t}: Copper losses={int(t.Pcu)}kW, "
              f"Iron losses={int(t.Pfe)}kW, SC voltage={t.Vsc}%")
    print()

    print("Losses:")
    for i in range(len(grid.branches)):
        print(
            f" - {grid.branches[i]}: losses={1000*round(power_flow.results.losses[i], 3)} kVA"
        )
    print()

    equal = False
    for i, branch in enumerate(grid.branches):
        if branch.name == "X_C3":
            equal = power_flow.results.tap_module[i] == branch.tap_module

    if not equal:
        grid.export_pf(f"{test_name}_results.xlsx", power_flow.results)
        grid.save_excel(f"{test_name}_grid.xlsx")

    assert equal
示例#5
0
def parse_json_data(data) -> MultiCircuit:
    """
    Parse JSON structure into GridCal MultiCircuit
    :param data: JSON structure (list of dictionaries)
    :return: GridCal MultiCircuit
    """

    circuit = MultiCircuit()

    bus_id = dict()

    for element in data:

        if element["phases"] == 'ps':

            if element["type"] == "circuit":

                circuit = MultiCircuit()
                circuit.name = element["name"]
                circuit.Sbase = element["Sbase"]
                circuit.comments = element['comments']

            elif element["type"] == "bus":

                # create the bus and add some properties
                elm = Bus(name=element["name"],
                          vnom=element["Vnom"],
                          vmin=0.9,
                          vmax=1.1,
                          xpos=element['x'],
                          ypos=element['y'],
                          height=element['h'],
                          width=element['w'],
                          active=True)

                if element["is_slack"]:
                    elm.type = BusMode.Slack
                if element["vmax"] > 0:
                    elm.Vmax = element["vmax"]
                if element["vmin"] > 0:
                    elm.Vmin = element["vmin"]

                elm.Zf = complex(element['rf'], element['xf'])

                circuit.add_bus(elm)

                # add the bus to the dictionary
                bus_id[element["id"]] = elm

            elif element["type"] == "load":

                # get the matching bus object pointer
                bus = bus_id[element["bus"]]

                # create a load in the bus
                elm = Load(name=element['name'],
                           G=element["G"],
                           B=element["B"],
                           Ir=element["Ir"],
                           Ii=element["Ii"],
                           P=element["P"],
                           Q=element["Q"],
                           active=element['active'])
                bus.loads.append(elm)

            elif element["type"] == "controlled_gen":

                # get the matching bus object pointer
                bus = bus_id[element["bus"]]

                # create a load in the bus
                elm = Generator(name=element['name'],
                                active_power=element["P"],
                                voltage_module=element["vset"],
                                Qmin=element['qmin'],
                                Qmax=element['qmax'],
                                Snom=element['Snom'],
                                power_prof=None,
                                vset_prof=None,
                                active=element['active'],
                                p_min=0.0,
                                p_max=element['Snom'],
                                op_cost=1.0)
                bus.controlled_generators.append(elm)

            elif element["type"] == "static_gen":

                # get the matching bus object pointer
                bus = bus_id[element["bus"]]

                # create a load in the bus
                elm = StaticGenerator(name=element['name'],
                                      P=element['P'], Q=element['Q'],
                                      active=element['active'])
                bus.static_generators.append(elm)

            elif element["type"] == "battery":

                # get the matching bus object pointer
                bus = bus_id[element["bus"]]

                # create a load in the bus
                elm = Battery(name=element['name'],
                              active_power=element["P"],
                              voltage_module=element["vset"],
                              Qmin=element['qmin'],
                              Qmax=element['qmax'],
                              Snom=element['Snom'],
                              Enom=element['Enom'],
                              power_prof=None,
                              vset_prof=None,
                              active=element['active'])
                bus.batteries.append(elm)

            elif element["type"] == "shunt":

                # get the matching bus object pointer
                bus = bus_id[element["bus"]]

                # create a load in the bus
                elm = Shunt(name=element['name'],
                            G=element["g"], B=element["b"],
                            active=element['active'])
                bus.shunts.append(elm)

            elif element["type"] == "branch":

                # get the matching bus object pointer
                bus1 = bus_id[element["from"]]
                bus2 = bus_id[element["to"]]

                # create a load in the  bus
                elm = Branch(bus_from=bus1,
                             bus_to=bus2,
                             name=element["name"],
                             r=element["r"],
                             x=element["x"],
                             g=element["g"],
                             b=element["b"],
                             rate=element["rate"],
                             tap=element["tap_module"],
                             shift_angle=element["tap_angle"],
                             active=element["active"],
                             mttf=0,
                             mttr=0,
                             branch_type=element["branch_type"])
                circuit.add_branch(elm)

        else:
            warn('ID: ' + element["id"] + ' error: GridCal only takes positive sequence elements.')

    return circuit
示例#6
0
def parse_json_data_v2(data: dict, logger: Logger):
    """
    New Json parser
    :param data:
    :param logger:
    :return:
    """
    devices = data['devices']
    profiles = data['profiles']

    if DeviceType.CircuitDevice.value in devices.keys():

        dta = devices[DeviceType.CircuitDevice.value]
        circuit = MultiCircuit(name=str(dta['name']),
                               Sbase=float(dta['sbase']),
                               fbase=float(dta['fbase']),
                               idtag=str(dta['id']))

        jcircuit = devices["Circuit"]
        circuit.Sbase = jcircuit["sbase"]

        # Countries
        country_dict = dict()
        if 'Country' in devices.keys():
            elms = devices["Country"]
            for jentry in elms:
                elm = Country(idtag=str(jentry['id']),
                              code=str(jentry['code']),
                              name=str(jentry['name']))
                circuit.countries.append(elm)
                country_dict[elm.idtag] = elm
        else:
            elm = Country(idtag=None, code='Default', name='Default')
            circuit.countries.append(elm)

        # Areas
        areas_dict = dict()
        if 'Area' in devices.keys():
            elms = devices["Area"]
            for jentry in elms:
                elm = Area(idtag=str(jentry['id']),
                           code=str(jentry['code']),
                           name=str(jentry['name']))
                circuit.areas.append(elm)
                areas_dict[elm.idtag] = elm
        else:
            elm = Area(idtag=None, code='Default', name='Default')
            circuit.areas.append(elm)

        # Zones
        zones_dict = dict()
        if 'Zone' in devices.keys():
            elms = devices["Zone"]
            for jentry in elms:
                elm = Zone(idtag=str(jentry['id']),
                           code=str(jentry['code']),
                           name=str(jentry['name']))
                circuit.zones.append(elm)
                zones_dict[elm.idtag] = elm
        else:
            elm = Zone(idtag=None, code='Default', name='Default')
            circuit.zones.append(elm)

        # Substations
        substations_dict = dict()
        if 'Substation' in devices.keys():
            elms = devices["Substation"]
            for jentry in elms:
                elm = Substation(idtag=str(jentry['id']),
                                 code=str(jentry['code']),
                                 name=str(jentry['name']))
                circuit.substations.append(elm)
                substations_dict[elm.idtag] = elm
        else:
            elm = Substation(idtag=None, code='Default', name='Default')
            circuit.substations.append(elm)

        # buses
        bus_dict = dict()
        if 'Bus' in devices.keys():
            buses = devices["Bus"]
            for jentry in buses:

                area_id = str(jentry['area']) if 'area' in jentry.keys() else ''
                zone_id = str(jentry['zone']) if 'zone' in jentry.keys() else ''
                substation_id = str(jentry['substation']) if 'substation' in jentry.keys() else ''
                country_id = str(jentry['country']) if 'country' in jentry.keys() else ''

                if area_id in areas_dict.keys():
                    area = areas_dict[area_id]
                else:
                    area = circuit.areas[0]

                if zone_id in zones_dict.keys():
                    zone = zones_dict[zone_id]
                else:
                    zone = circuit.zones[0]

                if substation_id in substations_dict.keys():
                    substation = substations_dict[substation_id]
                else:
                    substation = circuit.substations[0]

                if country_id in country_dict.keys():
                    country = country_dict[country_id]
                else:
                    country = circuit.countries[0]

                bus = Bus(name=str(jentry['name']),
                          idtag=str(jentry['id']),
                          vnom=float(jentry['vnom']),
                          vmin=float(jentry['vmin']),
                          vmax=float(jentry['vmax']),
                          r_fault=float(jentry['rf']),
                          x_fault=float(jentry['xf']),
                          xpos=float(jentry['x']),
                          ypos=float(jentry['y']),
                          height=float(jentry['h']),
                          width=float(jentry['w']),
                          active=bool(jentry['active']),
                          is_slack=bool(jentry['is_slack']),
                          area=area,
                          zone=zone,
                          substation=substation,
                          country=country,
                          longitude=float(jentry['lon']),
                          latitude=float(jentry['lat']))

                bus_dict[jentry['id']] = bus
                circuit.add_bus(bus)

        if 'Generator' in devices.keys():
            generators = devices["Generator"]
            for jentry in generators:
                gen = Generator(name=str(jentry['name']),
                                idtag=str(jentry['id']),
                                active_power=float(jentry['p']),
                                power_factor=float(jentry['pf']),
                                voltage_module=float(jentry['vset']),
                                is_controlled=bool(jentry['is_controlled']),
                                Qmin=float(jentry['qmin']),
                                Qmax=float(jentry['qmax']),
                                Snom=float(jentry['snom']),
                                active=bool(jentry['active']),
                                p_min=float(jentry['pmin']),
                                p_max=float(jentry['pmax']),
                                op_cost=float(jentry['cost']),
                                )
                gen.bus = bus_dict[jentry['bus']]
                circuit.add_generator(gen.bus, gen)

        if 'Battery' in devices.keys():
            batteries = devices["Battery"]
            for jentry in batteries:
                gen = Battery(name=str(jentry['name']),
                              idtag=str(jentry['id']),
                              active_power=float(jentry['p']),
                              power_factor=float(jentry['pf']),
                              voltage_module=float(jentry['vset']),
                              is_controlled=bool(jentry['is_controlled']),
                              Qmin=float(jentry['qmin']),
                              Qmax=float(jentry['qmax']),
                              Snom=float(jentry['snom']),
                              active=bool(jentry['active']),
                              p_min=float(jentry['pmin']),
                              p_max=float(jentry['pmax']),
                              op_cost=float(jentry['cost']),
                              )
                gen.bus = bus_dict[jentry['bus']]
                circuit.add_battery(gen.bus, gen)

        if 'Load' in devices.keys():
            loads = devices["Load"]
            for jentry in loads:
                elm = Load(name=str(jentry['name']),
                           idtag=str(jentry['id']),
                           P=float(jentry['p']),
                           Q=float(jentry['q']),
                           active=bool(jentry['active']))
                elm.bus = bus_dict[jentry['bus']]
                circuit.add_load(elm.bus, elm)

        if "Shunt" in devices.keys():
            shunts = devices["Shunt"]
            for jentry in shunts:
                elm = Shunt(name=str(jentry['name']),
                            idtag=str(jentry['id']),
                            G=float(jentry['g']),
                            B=float(jentry['b']),
                            active=bool(jentry['active']))
                elm.bus = bus_dict[jentry['bus']]
                circuit.add_shunt(elm.bus, elm)

        if "Line" in devices.keys():
            lines = devices["Line"]
            for entry in lines:
                elm = Line(bus_from=bus_dict[entry['bus_from']],
                           bus_to=bus_dict[entry['bus_to']],
                           name=str(entry['name']),
                           idtag=str(entry['id']),
                           r=float(entry['r']),
                           x=float(entry['x']),
                           b=float(entry['b']),
                           rate=float(entry['rate']),
                           active=entry['active'],
                           length=float(entry['length']),
                           )
                circuit.add_line(elm)

        if "Transformer" in devices.keys() or "Transformer2w" in devices.keys():

            if "Transformer" in devices.keys():
                transformers = devices["Transformer"]
            elif "Transformer2w" in devices.keys():
                transformers = devices["Transformer2w"]
            else:
                raise Exception('Transformer key not found')

            for entry in transformers:
                elm = Transformer2W(bus_from=bus_dict[entry['bus_from']],
                                    bus_to=bus_dict[entry['bus_to']],
                                    name=str(entry['name']),
                                    idtag=str(entry['id']),
                                    r=float(entry['r']),
                                    x=float(entry['x']),
                                    g=float(entry['g']),
                                    b=float(entry['b']),
                                    rate=float(entry['rate']),
                                    active=bool(entry['active']),
                                    tap=float(entry['tap_module']),
                                    shift_angle=float(entry['tap_angle']),
                                    )
                circuit.add_transformer2w(elm)

        if "VSC" in devices.keys():
            vsc = devices["VSC"]

            # TODO: call correct_buses_connection()

        if "HVDC Line" in devices.keys():
            hvdc = devices["HVDC Line"]

        return circuit

    else:
        logger.add('The Json structure does not have a Circuit inside the devices!')
        return MultiCircuit()
示例#7
0
def test_tolerance_lf_higher():
    test_name = "test_tolerance_lf_higher"
    grid = MultiCircuit(name=test_name)
    grid.Sbase = Sbase
    grid.time_profile = None
    grid.logger = list()

    # Create buses
    Bus0 = Bus(name="Bus0", vnom=25, is_slack=True)
    bus_1 = Bus(name="bus_1", vnom=25)

    grid.add_bus(Bus0)
    grid.add_bus(bus_1)

    # Create load
    grid.add_load(bus_1, Load(name="Load0", P=1.0, Q=0.4))

    # Create slack bus
    grid.add_generator(Bus0, Generator(name="Utility"))

    # Create cable (r and x should be in pu)
    grid.add_branch(
        Branch(bus_from=Bus0,
               bus_to=bus_1,
               name="Cable1",
               r=0.01,
               x=0.05,
               tolerance=10))

    # Run non-linear power flow
    options = PowerFlowOptions(
        verbose=True,
        branch_impedance_tolerance_mode=BranchImpedanceMode.Upper)

    power_flow = PowerFlow(grid, options)
    power_flow.run()

    # Check solution
    approx_losses = round(1000 * power_flow.results.losses[0], 3)
    solution = complex(0.128, 0.58)  # Expected solution from GridCal
    # Tested on ETAP 16.1.0 and pandapower

    print(
        "\n=================================================================")
    print(f"Test: {test_name}")
    print(
        "=================================================================\n")
    print(f"Results:  {approx_losses}")
    print(f"Solution: {solution}")
    print()

    print("Buses:")
    for i, b in enumerate(grid.buses):
        print(f" - bus[{i}]: {b}")
    print()

    print("Branches:")
    for b in grid.branches:
        print(f" - {b}:")
        print(f"   R = {round(b.R, 4)} pu")
        print(f"   X = {round(b.X, 4)} pu")
        print(f"   X/R = {round(b.X/b.R, 2)}")
    print()

    print("Voltages:")
    for i in range(len(grid.buses)):
        print(
            f" - {grid.buses[i]}: voltage={round(power_flow.results.voltage[i], 3)} pu"
        )
    print()

    print("Losses:")
    for i in range(len(grid.branches)):
        print(
            f" - {grid.branches[i]}: losses={round(power_flow.results.losses[i], 3)} MVA"
        )
    print()

    print("Loadings (power):")
    for i in range(len(grid.branches)):
        print(
            f" - {grid.branches[i]}: loading={round(power_flow.results.Sbranch[i], 3)} MVA"
        )
    print()

    print("Loadings (current):")
    for i in range(len(grid.branches)):
        print(
            f" - {grid.branches[i]}: loading={round(power_flow.results.Ibranch[i], 3)} pu"
        )
    print()

    assert approx_losses == solution
示例#8
0
def test_basic():
    """
    Basic GridCal test, also useful for a basic tutorial. In this case the
    magnetizing branch of the transformers is neglected by inputting 1e-20
    excitation current and iron core losses.
    The results are identical to ETAP's, which always uses this assumption in
    balanced load flow calculations.
    """
    test_name = "test_basic"
    grid = MultiCircuit(name=test_name)
    S_base = 100  # MVA
    grid.Sbase = S_base
    grid.time_profile = None
    grid.logger = list()

    # Create buses
    POI = Bus(
        name="POI",
        vnom=100,  #kV
        is_slack=True)
    grid.add_bus(POI)

    B_C3 = Bus(name="B_C3", vnom=10)  #kV
    grid.add_bus(B_C3)

    B_MV_M32 = Bus(name="B_MV_M32", vnom=10)  #kV
    grid.add_bus(B_MV_M32)

    B_LV_M32 = Bus(name="B_LV_M32", vnom=0.6)  #kV
    grid.add_bus(B_LV_M32)

    # Create voltage controlled generators (or slack, a.k.a. swing)
    UT = Generator(name="Utility")
    UT.bus = POI
    grid.add_generator(POI, UT)

    # Create static generators (with fixed power factor)
    M32 = StaticGenerator(
        name="M32",
        P=4.2,  # MW
        Q=0.0j)  # MVAR
    M32.bus = B_LV_M32
    grid.add_static_generator(B_LV_M32, M32)

    # Create transformer types
    s = 5  # MVA
    z = 8  # %
    xr = 40
    SS = TransformerType(
        name="SS",
        hv_nominal_voltage=100,  # kV
        lv_nominal_voltage=10,  # kV
        nominal_power=s,
        copper_losses=complex_impedance(z, xr).real * s * 1000 / S_base,
        iron_losses=1e-20,
        no_load_current=1e-20,
        short_circuit_voltage=z)
    grid.add_transformer_type(SS)

    s = 5  # MVA
    z = 6  # %
    xr = 20
    PM = TransformerType(
        name="PM",
        hv_nominal_voltage=10,  # kV
        lv_nominal_voltage=0.6,  # kV
        nominal_power=s,
        copper_losses=complex_impedance(z, xr).real * s * 1000 / S_base,
        iron_losses=1e-20,
        no_load_current=1e-20,
        short_circuit_voltage=z)
    grid.add_transformer_type(PM)

    # Create branches
    X_C3 = Branch(bus_from=POI,
                  bus_to=B_C3,
                  name="X_C3",
                  branch_type=BranchType.Transformer,
                  template=SS)
    grid.add_branch(X_C3)

    C_M32 = Branch(bus_from=B_C3,
                   bus_to=B_MV_M32,
                   name="C_M32",
                   r=0.784,
                   x=0.174)
    grid.add_branch(C_M32)

    X_M32 = Branch(bus_from=B_MV_M32,
                   bus_to=B_LV_M32,
                   name="X_M32",
                   branch_type=BranchType.Transformer,
                   template=PM)
    grid.add_branch(X_M32)

    # Apply templates (device types)
    grid.apply_all_branch_types()

    print("Buses:")
    for i, b in enumerate(grid.buses):
        print(f" - bus[{i}]: {b}")
    print()

    options = PowerFlowOptions(SolverType.LM,
                               verbose=True,
                               initialize_with_existing_solution=True,
                               multi_core=True,
                               control_q=ReactivePowerControlMode.Direct,
                               tolerance=1e-6,
                               max_iter=99)

    power_flow = PowerFlow(grid, options)
    power_flow.run()

    approx_volt = [round(100 * abs(v), 1) for v in power_flow.results.voltage]
    solution = [
        100.0, 99.6, 102.7, 102.9
    ]  # Expected solution from GridCal and ETAP 16.1.0, for reference

    print()
    print(f"Test: {test_name}")
    print(f"Results:  {approx_volt}")
    print(f"Solution: {solution}")
    print()

    print("Generators:")
    for g in grid.get_generators():
        print(f" - Generator {g}: q_min={g.Qmin}pu, q_max={g.Qmax}pu")
    print()

    print("Branches:")
    for b in grid.branches:
        print(f" - {b}:")
        print(f"   R = {round(b.R, 4)} pu")
        print(f"   X = {round(b.X, 4)} pu")
        print(f"   X/R = {round(b.X/b.R, 1)}")
        print(f"   G = {round(b.G, 4)} pu")
        print(f"   B = {round(b.B, 4)} pu")
    print()

    print("Transformer types:")
    for t in grid.transformer_types:
        print(
            f" - {t}: Copper losses={int(t.Pcu)}kW, Iron losses={int(t.Pfe)}kW, SC voltage={t.Vsc}%"
        )
    print()

    print("Losses:")
    for i in range(len(grid.branches)):
        print(
            f" - {grid.branches[i]}: losses={1000*round(power_flow.results.losses[i], 3)} kVA"
        )
    print()

    equal = True
    for i in range(len(approx_volt)):
        if approx_volt[i] != solution[i]:
            equal = False

    assert equal
示例#9
0
def parse_buses_data(circuit: MultiCircuit, data, area_idx_dict,
                     logger: Logger):
    """
    Parse Matpower / FUBM Matpower bus data into GridCal
    :param circuit: MultiCircuit instance
    :param data: data dictionary
    :param area_idx_dict: area index -> object dictionary
    :return: bus index -> object dictionary
    """

    # Buses
    table = data['bus']

    n = table.shape[0]

    # load profiles
    if 'Lprof' in data.keys():
        Pprof = data['Lprof']
        Qprof = data['LprofQ']
        are_load_prfiles = True
        print('There are load profiles')
    else:
        are_load_prfiles = False

    if 'bus_names' in data.keys():
        names = data['bus_names']
    else:
        names = [
            'bus ' + str(int(table[i, matpower_buses.BUS_I])) for i in range(n)
        ]

    # Buses
    bus_idx_dict = dict()
    for i in range(n):
        # Create bus
        area_idx = int(table[i, matpower_buses.BUS_AREA])
        bus_idx = int(table[i, matpower_buses.BUS_I])
        is_slack = False

        if area_idx in area_idx_dict.keys():
            area, ref_idx = area_idx_dict[area_idx]
            if ref_idx == bus_idx:
                is_slack = True
        else:
            area = circuit.default_area

        code = str(bus_idx)

        bus = Bus(name=names[i],
                  code=code,
                  vnom=table[i, matpower_buses.BASE_KV],
                  vmax=table[i, matpower_buses.VMAX],
                  vmin=table[i, matpower_buses.VMIN],
                  area=area,
                  is_slack=is_slack)

        # store the given bus index in relation to its real index in the table for later
        bus_idx_dict[table[i, matpower_buses.BUS_I]] = i

        # determine if the bus is set as slack manually
        tpe = table[i, matpower_buses.BUS_TYPE]
        if tpe == matpower_buses.REF:
            bus.is_slack = True
        else:
            bus.is_slack = False

        # Add the load
        if table[i, matpower_buses.PD] != 0 or table[i,
                                                     matpower_buses.QD] != 0:
            load = Load(P=table[i, matpower_buses.PD],
                        Q=table[i, matpower_buses.QD])
            load.bus = bus
            bus.loads.append(load)

        # Add the shunt
        if table[i, matpower_buses.GS] != 0 or table[i,
                                                     matpower_buses.BS] != 0:
            shunt = Shunt(G=table[i, matpower_buses.GS],
                          B=table[i, matpower_buses.BS])
            shunt.bus = bus
            bus.shunts.append(shunt)

        # Add the bus to the circuit buses
        circuit.add_bus(bus)

    return bus_idx_dict
def main():
    ####################################################################################################################
    # Define the circuit
    #
    # A circuit contains all the grid information regardless of the islands formed or the amount of devices
    ####################################################################################################################

    # create a circuit

    grid = MultiCircuit(name='lynn 5 bus')

    # let's create a master profile

    st = datetime.datetime(2020, 1, 1)
    dates = [st + datetime.timedelta(hours=i) for i in range(24)]
    time_array = pd.to_datetime(dates)
    x = np.linspace(-np.pi, np.pi, len(time_array))
    y = np.abs(np.sin(x))
    df_0 = pd.DataFrame(data=y, index=time_array)  # complex values

    # set the grid master time profile
    grid.time_profile = df_0.index

    ####################################################################################################################
    # Define the buses
    ####################################################################################################################
    # I will define this bus with all the properties so you see
    bus1 = Bus(name='Bus1',
               vnom=10,   # Nominal voltage in kV
               vmin=0.9,  # Bus minimum voltage in per unit
               vmax=1.1,  # Bus maximum voltage in per unit
               xpos=0,    # Bus x position in pixels
               ypos=0,    # Bus y position in pixels
               height=0,  # Bus height in pixels
               width=0,   # Bus width in pixels
               active=True,   # Is the bus active?
               is_slack=False,  # Is this bus a slack bus?
               area='Defualt',  # Area (for grouping purposes only)
               zone='Default',  # Zone (for grouping purposes only)
               substation='Default'  # Substation (for grouping purposes only)
               )

    # the rest of the buses are defined with the default parameters
    bus2 = Bus(name='Bus2')
    bus3 = Bus(name='Bus3')
    bus4 = Bus(name='Bus4')
    bus5 = Bus(name='Bus5')

    # add the bus objects to the circuit
    grid.add_bus(bus1)
    grid.add_bus(bus2)
    grid.add_bus(bus3)
    grid.add_bus(bus4)
    grid.add_bus(bus5)

    ####################################################################################################################
    # Add the loads
    ####################################################################################################################

    # In GridCal, the loads, generators ect are stored within each bus object:

    # we'll define the first load completely
    l2 = Load(name='Load',
              G=0, B=0,  # admittance of the ZIP model in MVA at the nominal voltage
              Ir=0, Ii=0,  # Current of the ZIP model in MVA at the nominal voltage
              P=40, Q=20,  # Power of the ZIP model in MVA
              active=True,  # Is active?
              mttf=0.0,  # Mean time to failure
              mttr=0.0  # Mean time to recovery
              )
    grid.add_load(bus2, l2)

    # Define the others with the default parameters
    grid.add_load(bus3, Load(P=25, Q=15))
    grid.add_load(bus4, Load(P=40, Q=20))
    grid.add_load(bus5, Load(P=50, Q=20))

    ####################################################################################################################
    # Add the generators
    ####################################################################################################################

    g1 = Generator(name='gen',
                   active_power=0.0,  # Active power in MW, since this generator is used to set the slack , is 0
                   voltage_module=1.0,  # Voltage set point to control
                   Qmin=-9999,  # minimum reactive power in MVAr
                   Qmax=9999,  # Maximum reactive power in MVAr
                   Snom=9999,  # Nominal power in MVA
                   power_prof=None,  # power profile
                   vset_prof=None,  # voltage set point profile
                   active=True  # Is active?
                   )
    grid.add_generator(bus1, g1)

    ####################################################################################################################
    # Add the lines
    ####################################################################################################################

    br1 = Branch(bus_from=bus1,
                 bus_to=bus2,
                 name='Line 1-2',
                 r=0.05,  # resistance of the pi model in per unit
                 x=0.11,  # reactance of the pi model in per unit
                 g=1e-20,  # conductance of the pi model in per unit
                 b=0.02,  # susceptance of the pi model in per unit
                 rate=50,  # Rate in MVA
                 tap=1.0,  # Tap value (value close to 1)
                 shift_angle=0,  # Tap angle in radians
                 active=True,  # is the branch active?
                 mttf=0,  # Mean time to failure
                 mttr=0,  # Mean time to recovery
                 branch_type=BranchType.Line,  # Branch type tag
                 length=1,  # Length in km (to be used with templates)
                 template=BranchTemplate()  # Branch template (The default one is void)
                 )
    grid.add_branch(br1)

    grid.add_branch(Branch(bus1, bus3, name='Line 1-3', r=0.05, x=0.11, b=0.02, rate=50))
    grid.add_branch(Branch(bus1, bus5, name='Line 1-5', r=0.03, x=0.08, b=0.02, rate=80))
    grid.add_branch(Branch(bus2, bus3, name='Line 2-3', r=0.04, x=0.09, b=0.02, rate=3))
    grid.add_branch(Branch(bus2, bus5, name='Line 2-5', r=0.04, x=0.09, b=0.02, rate=10))
    grid.add_branch(Branch(bus3, bus4, name='Line 3-4', r=0.06, x=0.13, b=0.03, rate=30))
    grid.add_branch(Branch(bus4, bus5, name='Line 4-5', r=0.04, x=0.09, b=0.02, rate=30))

    FileSave(grid, 'lynn5node.gridcal').save()

    ####################################################################################################################
    # Overwrite the default profiles with the custom ones
    ####################################################################################################################

    for load in grid.get_loads():
        load.P_prof = load.P * df_0.values[:, 0]
        load.Q_prof = load.Q * df_0.values[:, 0]

    for gen in grid.get_static_generators():
        gen.P_prof = gen.Q * df_0.values[:, 0]
        gen.Q_prof = gen.Q * df_0.values[:, 0]

    for gen in grid.get_generators():
        gen.P_prof = gen.P * df_0.values[:, 0]

    ####################################################################################################################
    # Run a power flow simulation
    ####################################################################################################################

    # We need to specify power flow options
    pf_options = PowerFlowOptions(solver_type=SolverType.NR,  # Base method to use
                                  verbose=False,  # Verbose option where available
                                  tolerance=1e-6,  # power error in p.u.
                                  max_iter=25,  # maximum iteration number
                                  control_q=True  # if to control the reactive power
                                  )

    # Declare and execute the power flow simulation
    pf = PowerFlowDriver(grid, pf_options)
    pf.run()

    writer = pd.ExcelWriter('Results.xlsx')
    # now, let's compose a nice DataFrame with the voltage results
    headers = ['Vm (p.u.)', 'Va (Deg)', 'Vre', 'Vim']
    Vm = np.abs(pf.results.voltage)
    Va = np.angle(pf.results.voltage, deg=True)
    Vre = pf.results.voltage.real
    Vim = pf.results.voltage.imag
    data = np.c_[Vm, Va, Vre, Vim]
    v_df = pd.DataFrame(data=data, columns=headers, index=grid.bus_names)
    # print('\n', v_df)
    v_df.to_excel(writer, sheet_name='V')

    # Let's do the same for the branch results
    headers = ['Loading (%)', 'Current(p.u.)', 'Power (MVA)']
    loading = np.abs(pf.results.loading) * 100
    current = np.abs(pf.results.If)
    power = np.abs(pf.results.Sf)
    data = np.c_[loading, current, power]
    br_df = pd.DataFrame(data=data, columns=headers, index=grid.branch_names)
    br_df.to_excel(writer, sheet_name='Br')

    # Finally the execution metrics
    print('\nError:', pf.results.error)
    print('Elapsed time (s):', pf.results.elapsed, '\n')

    # print(tabulate(v_df, tablefmt="pipe", headers=v_df.columns.values))
    # print()
    # print(tabulate(br_df, tablefmt="pipe", headers=br_df.columns.values))



    ####################################################################################################################
    # Run a time series power flow simulation
    ####################################################################################################################

    ts = TimeSeries(grid=grid,
                    options=pf_options,
                    opf_time_series_results=None,
                    start_=0,
                    end_=None)

    ts.run()

    print()
    print('-' * 200)
    print('Time series')
    print('-' * 200)
    print('Voltage time series')
    df_voltage = pd.DataFrame(data=np.abs(ts.results.voltage), columns=grid.bus_names, index=grid.time_profile)
    df_voltage.to_excel(writer, sheet_name='Vts')
    writer.close()
示例#11
0
def interpret_excel_v3(circuit: MultiCircuit, data):
    """
    Interpret the file version 3
    In this file version there are no complex numbers saved
    :param circuit:
    :param data: Dictionary with the excel file sheet labels and the corresponding DataFrame
    :return: Nothing, just applies the loaded data to this MultiCircuit instance
    """

    # print('Interpreting V2 data...')

    # clear all the data
    circuit.clear()

    circuit.name = data['name']

    # set the base magnitudes
    circuit.Sbase = data['baseMVA']

    # dictionary of branch types [name] -> type object
    branch_types = dict()

    # Set comments
    circuit.comments = data['Comments'] if 'Comments' in data.keys() else ''

    circuit.logger = Logger()

    # common function
    def set_object_attributes(obj_, attr_list, values):
        for a, attr in enumerate(attr_list):

            # Hack to change the enabled by active...
            if attr == 'is_enabled':
                attr = 'active'

            if attr == 'type_obj':
                attr = 'template'

            if attr == 'wire_name':
                attr = 'name'

            if hasattr(obj_, attr):
                conv = obj_.editable_headers[
                    attr].tpe  # get the type converter
                if conv is None:
                    setattr(obj_, attr, values[a])
                elif conv is BranchType:
                    cbr = BranchTypeConverter(None)
                    setattr(obj_, attr, cbr(values[a]))
                else:
                    setattr(obj_, attr, conv(values[a]))
            else:
                warn(str(obj_) + ' has no ' + attr + ' property.')

    # time profile #################################################################################################
    if 'time' in data.keys():
        time_df = data['time']
        circuit.time_profile = pd.to_datetime(time_df.values[:, 0])
    else:
        circuit.time_profile = None

    # Add the buses ################################################################################################
    bus_dict = dict()
    if 'bus' in data.keys():
        df = data['bus']
        hdr = df.columns.values
        vals = df.values
        for i in range(len(df)):
            obj = Bus()
            set_object_attributes(obj, hdr, vals[i, :])
            bus_dict[obj.name] = obj
            circuit.add_bus(obj)
    else:
        circuit.logger.append('No buses in the file!')

    # add the loads ################################################################################################
    if 'load' in data.keys():
        df = data['load']
        bus_from = df['bus'].values
        hdr = df.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus'))
        vals = df[hdr].values

        profles_attr = {
            'load_P_prof': 'P_prof',
            'load_Q_prof': 'Q_prof',
            'load_Ir_prof': 'Ir_prof',
            'load_Ii_prof': 'Ii_prof',
            'load_G_prof': 'G_prof',
            'load_B_prof': 'B_prof',
            'load_active_prof': 'active_prof',
            'load_Cost_prof': 'Cost_prof'
        }

        for i in range(df.shape[0]):
            obj = Load()
            set_object_attributes(obj, hdr, vals[i, :])

            # parse profiles:
            for sheet_name, load_attr in profles_attr.items():
                if sheet_name in data.keys():
                    val = data[sheet_name].values[:, i]
                    idx = data[sheet_name].index
                    # setattr(obj, load_attr, pd.DataFrame(data=val, index=idx))
                    setattr(obj, load_attr, val)

                    if circuit.time_profile is None or len(
                            circuit.time_profile) < len(idx):
                        circuit.time_profile = idx

            try:
                bus = bus_dict[str(bus_from[i])]
            except KeyError as ex:
                raise Exception(
                    str(i) + ': Load bus is not in the buses list.\n' +
                    str(ex))

            if obj.name == 'Load':
                obj.name += str(len(bus.loads) + 1) + '@' + bus.name

            obj.bus = bus
            bus.loads.append(obj)
            obj.ensure_profiles_exist(circuit.time_profile)
    else:
        circuit.logger.append('No loads in the file!')

    # add the controlled generators ################################################################################
    if 'generator' in data.keys():
        df = data['generator']
        bus_from = df['bus'].values
        hdr = df.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus'))
        vals = df[hdr].values
        for i in range(df.shape[0]):
            obj = Generator()
            set_object_attributes(obj, hdr, vals[i, :])

            if 'generator_P_prof' in data.keys():
                val = data['generator_P_prof'].values[:, i]
                idx = data['generator_P_prof'].index
                obj.create_profile(magnitude='P', index=idx, arr=val)
                # also create the Pf array because there might not be values in the file
                obj.create_profile(magnitude='Pf', index=idx, arr=None)

                if circuit.time_profile is None or len(
                        circuit.time_profile) < len(idx):
                    circuit.time_profile = idx

            if 'generator_Pf_prof' in data.keys():
                val = data['generator_Pf_prof'].values[:, i]
                idx = data['generator_Pf_prof'].index
                obj.create_profile(magnitude='Pf', index=idx, arr=val)

            if 'generator_Vset_prof' in data.keys():
                val = data['generator_Vset_prof'].values[:, i]
                idx = data['generator_Vset_prof'].index
                obj.create_profile(magnitude='Vset', index=idx, arr=val)

            if 'generator_active_prof' in data.keys():
                val = data['generator_active_prof'].values[:, i]
                idx = data['generator_active_prof'].index
                obj.create_profile(magnitude='active', index=idx, arr=val)

            if 'generator_Cost_prof' in data.keys():
                val = data['generator_Cost_prof'].values[:, i]
                idx = data['generator_Cost_prof'].index
                obj.create_profile(magnitude='Cost', index=idx, arr=val)

            try:
                bus = bus_dict[str(bus_from[i])]
            except KeyError as ex:
                raise Exception(
                    str(i) +
                    ': Controlled generator bus is not in the buses list.\n' +
                    str(ex))

            if obj.name == 'gen':
                obj.name += str(len(bus.controlled_generators) +
                                1) + '@' + bus.name

            obj.bus = bus
            bus.controlled_generators.append(obj)
            obj.ensure_profiles_exist(circuit.time_profile)
    else:
        circuit.logger.append('No controlled generator in the file!')

    # add the batteries ############################################################################################
    if 'battery' in data.keys():
        df = data['battery']
        bus_from = df['bus'].values
        hdr = df.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus'))
        vals = df[hdr].values
        for i in range(df.shape[0]):
            obj = Battery()
            set_object_attributes(obj, hdr, vals[i, :])

            if 'battery_P_prof' in data.keys():
                val = data['battery_P_prof'].values[:, i]
                idx = data['battery_P_prof'].index
                obj.create_profile(magnitude='P', index=idx, arr=val)
                # also create the Pf array because there might not be values in the file
                obj.create_profile(magnitude='Pf', index=idx, arr=None)

            if 'battery_Vset_prof' in data.keys():
                val = data['battery_Vset_prof'].values[:, i]
                idx = data['battery_Vset_prof'].index
                obj.create_profile(magnitude='Vset', index=idx, arr=val)

            if 'battery_active_prof' in data.keys():
                val = data['battery_active_prof'].values[:, i]
                idx = data['battery_active_prof'].index
                obj.create_profile(magnitude='active', index=idx, arr=val)

            if 'battery_Cost_prof' in data.keys():
                val = data['battery_Cost_prof'].values[:, i]
                idx = data['battery_Cost_prof'].index
                obj.create_profile(magnitude='Cost', index=idx, arr=val)

            try:
                bus = bus_dict[str(bus_from[i])]
            except KeyError as ex:
                raise Exception(
                    str(i) + ': Battery bus is not in the buses list.\n' +
                    str(ex))

            if obj.name == 'batt':
                obj.name += str(len(bus.batteries) + 1) + '@' + bus.name

            obj.bus = bus
            bus.batteries.append(obj)
            obj.ensure_profiles_exist(circuit.time_profile)
    else:
        circuit.logger.append('No battery in the file!')

    # add the static generators ####################################################################################
    if 'static_generator' in data.keys():
        df = data['static_generator']
        bus_from = df['bus'].values
        hdr = df.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus'))
        vals = df[hdr].values
        for i in range(df.shape[0]):
            obj = StaticGenerator()
            set_object_attributes(obj, hdr, vals[i, :])

            if 'static_generator_Sprof' in data.keys():
                val = data['static_generator_Sprof'].values[:, i]
                idx = data['static_generator_Sprof'].index
                obj.create_profile(magnitude='P', index=idx, arr=val.real)
                obj.create_profile(magnitude='Q', index=idx, arr=val.imag)

            if 'static_generator_P_prof' in data.keys():
                val = data['static_generator_P_prof'].values[:, i]
                idx = data['static_generator_P_prof'].index
                obj.create_profile(magnitude='P', index=idx, arr=val)

            if 'static_generator_Q_prof' in data.keys():
                val = data['static_generator_Q_prof'].values[:, i]
                idx = data['static_generator_Q_prof'].index
                obj.create_profile(magnitude='Q', index=idx, arr=val)

            if 'static_generator_active_prof' in data.keys():
                val = data['static_generator_active_prof'].values[:, i]
                idx = data['static_generator_active_prof'].index
                obj.create_profile(magnitude='active', index=idx, arr=val)

            if 'static_generator_Cost_prof' in data.keys():
                val = data['static_generator_Cost_prof'].values[:, i]
                idx = data['static_generator_Cost_prof'].index
                obj.create_profile(magnitude='Cost', index=idx, arr=val)

            try:
                bus = bus_dict[str(bus_from[i])]
            except KeyError as ex:
                raise Exception(
                    str(i) +
                    ': Static generator bus is not in the buses list.\n' +
                    str(ex))

            if obj.name == 'StaticGen':
                obj.name += str(len(bus.static_generators) +
                                1) + '@' + bus.name

            obj.bus = bus
            bus.static_generators.append(obj)
            obj.ensure_profiles_exist(circuit.time_profile)
    else:
        circuit.logger.append('No static generator in the file!')

    # add the shunts ###############################################################################################
    if 'shunt' in data.keys():
        df = data['shunt']
        bus_from = df['bus'].values
        hdr = df.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus'))
        vals = df[hdr].values
        for i in range(df.shape[0]):
            obj = Shunt()
            set_object_attributes(obj, hdr, vals[i, :])

            if 'shunt_Y_profiles' in data.keys():
                val = data['shunt_Y_profiles'].values[:, i]
                idx = data['shunt_Y_profiles'].index
                obj.create_profile(magnitude='G', index=idx, arr=val.real)
                obj.create_profile(magnitude='B', index=idx, arr=val.imag)

            if 'shunt_G_prof' in data.keys():
                val = data['shunt_G_prof'].values[:, i]
                idx = data['shunt_G_prof'].index
                obj.create_profile(magnitude='G', index=idx, arr=val)

            if 'shunt_B_prof' in data.keys():
                val = data['shunt_B_prof'].values[:, i]
                idx = data['shunt_B_prof'].index
                obj.create_profile(magnitude='B', index=idx, arr=val)

            if 'shunt_active_prof' in data.keys():
                val = data['shunt_active_prof'].values[:, i]
                idx = data['shunt_active_prof'].index
                obj.create_profile(magnitude='active', index=idx, arr=val)

            if 'shunt_Cost_prof' in data.keys():
                val = data['shunt_Cost_prof'].values[:, i]
                idx = data['shunt_Cost_prof'].index
                obj.create_profile(magnitude='Cost', index=idx, arr=val)

            try:
                bus = bus_dict[str(bus_from[i])]
            except KeyError as ex:
                raise Exception(
                    str(i) + ': Shunt bus is not in the buses list.\n' +
                    str(ex))

            if obj.name == 'shunt':
                obj.name += str(len(bus.shunts) + 1) + '@' + bus.name

            obj.bus = bus
            bus.shunts.append(obj)
            obj.ensure_profiles_exist(circuit.time_profile)
    else:
        circuit.logger.append('No shunt in the file!')

    # Add the wires ################################################################################################
    if 'wires' in data.keys():
        df = data['wires']
        hdr = df.columns.values
        vals = df.values
        for i in range(len(df)):
            obj = Wire()
            set_object_attributes(obj, hdr, vals[i, :])
            circuit.add_wire(obj)
    else:
        circuit.logger.append('No wires in the file!')

    # Add the overhead_line_types ##################################################################################
    if 'overhead_line_types' in data.keys():
        df = data['overhead_line_types']
        if data['overhead_line_types'].values.shape[0] > 0:
            for tower_name in df['tower_name'].unique():
                obj = Tower()
                dft = df[df['tower_name'] == tower_name]
                vals = dft.values

                wire_prop = df.columns.values[len(obj.editable_headers):]

                # set the tower values
                set_object_attributes(obj, obj.editable_headers.keys(),
                                      vals[0, :])

                # add the wires
                if len(wire_prop) == 7:
                    for i in range(vals.shape[0]):

                        # ['wire_name' 'xpos' 'ypos' 'phase' 'r' 'x' 'gmr']
                        name = dft['wire_name'].values[i]
                        gmr = dft['gmr'].values[i]
                        r = dft['r'].values[i]
                        x = dft['x'].values[i]
                        xpos = dft['xpos'].values[i]
                        ypos = dft['ypos'].values[i]
                        phase = dft['phase'].values[i]

                        wire = Wire(name=name, gmr=gmr, r=r, x=x)
                        w = WireInTower(wire=wire,
                                        xpos=xpos,
                                        ypos=ypos,
                                        phase=phase)
                        obj.wires_in_tower.append(w)

                circuit.add_overhead_line(obj)
                branch_types[str(obj)] = obj
        else:
            pass
    else:
        circuit.logger.append('No overhead_line_types in the file!')

    # Add the wires ################################################################################################
    if 'underground_cable_types' in data.keys():
        df = data['underground_cable_types']
        hdr = df.columns.values
        vals = df.values
        # for i in range(len(lst)):
        #     obj = UndergroundLineType()
        #     set_object_attributes(obj, hdr, vals[i, :])
        #     circuit.underground_cable_types.append(obj)
        #     branch_types[str(obj)] = obj
    else:
        circuit.logger.append('No underground_cable_types in the file!')

    # Add the sequence line types ##################################################################################
    if 'sequence_line_types' in data.keys():
        df = data['sequence_line_types']
        hdr = df.columns.values
        vals = df.values
        for i in range(len(df)):
            obj = SequenceLineType()
            set_object_attributes(obj, hdr, vals[i, :])
            circuit.add_sequence_line(obj)
            branch_types[str(obj)] = obj
    else:
        circuit.logger.append('No sequence_line_types in the file!')

    # Add the transformer types ####################################################################################
    if 'transformer_types' in data.keys():
        df = data['transformer_types']
        hdr = df.columns.values
        vals = df.values
        for i in range(len(df)):
            obj = TransformerType()
            set_object_attributes(obj, hdr, vals[i, :])
            circuit.add_transformer_type(obj)
            branch_types[str(obj)] = obj
    else:
        circuit.logger.append('No transformer_types in the file!')

    # Add the branches #############################################################################################
    if 'branch' in data.keys():
        df = data['branch']

        # fix the old 'is_transformer' property
        if 'is_transformer' in df.columns.values:
            df['is_transformer'] = df['is_transformer'].map({
                True: 'transformer',
                False: 'line'
            })
            df.rename(columns={'is_transformer': 'branch_type'}, inplace=True)

        bus_from = df['bus_from'].values
        bus_to = df['bus_to'].values
        hdr = df.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus_from'))
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus_to'))
        vals = df[hdr].values
        for i in range(df.shape[0]):
            try:
                obj = Branch(bus_from=bus_dict[str(bus_from[i])],
                             bus_to=bus_dict[str(bus_to[i])])
            except KeyError as ex:
                raise Exception(
                    str(i) + ': Branch bus is not in the buses list.\n' +
                    str(ex))

            set_object_attributes(obj, hdr, vals[i, :])

            # set the branch
            circuit.add_branch(obj)
            obj.ensure_profiles_exist(circuit.time_profile)

            if 'branch_active_prof' in data.keys():
                val = data['branch_active_prof'].values[:, i]
                idx = data['branch_active_prof'].index
                obj.create_profile(magnitude='active', index=idx, arr=val)

            if 'branch_Cost_prof' in data.keys():
                val = data['branch_Cost_prof'].values[:, i]
                idx = data['branch_Cost_prof'].index
                obj.create_profile(magnitude='Cost', index=idx, arr=val)

            if 'branch_temp_oper_prof' in data.keys():
                val = data['branch_temp_oper_prof'].values[:, i]
                idx = data['branch_temp_oper_prof'].index
                obj.create_profile(magnitude='temp_oper', index=idx, arr=val)

            # correct the branch template object
            template_name = str(obj.template)
            if template_name in branch_types.keys():
                obj.template = branch_types[template_name]
                print(template_name, 'updtaed!')

    else:
        circuit.logger.append('No branches in the file!')

    # Other actions ################################################################################################
    circuit.logger += circuit.apply_all_branch_types()
def test_xfo_static_tap_1():
    """
    Basic test with the main transformer's  HV tap (X_C3) set at +5% (1.05 pu),
    which lowers the LV by the same amount (-5%).
    """
    test_name = "test_xfo_static_tap_1"
    grid = MultiCircuit(name=test_name)
    grid.Sbase = Sbase
    grid.time_profile = None
    grid.logger = Logger()

    # Create buses
    POI = Bus(
        name="POI",
        vnom=100,  #kV
        is_slack=True)
    grid.add_bus(POI)

    B_C3 = Bus(name="B_C3", vnom=10)  #kV
    grid.add_bus(B_C3)

    B_MV_M32 = Bus(name="B_MV_M32", vnom=10)  #kV
    grid.add_bus(B_MV_M32)

    B_LV_M32 = Bus(name="B_LV_M32", vnom=0.6)  #kV
    grid.add_bus(B_LV_M32)

    # Create voltage controlled generators (or slack, a.k.a. swing)
    UT = Generator(name="Utility")
    UT.bus = POI
    grid.add_generator(POI, UT)

    # Create static generators (with fixed power factor)
    M32 = StaticGenerator(name="M32", P=4.2, Q=0.0)  # MVA (complex)
    M32.bus = B_LV_M32
    grid.add_static_generator(B_LV_M32, M32)

    # Create transformer types
    s = 5  # MVA
    z = 8  # %
    xr = 40
    SS = TransformerType(
        name="SS",
        hv_nominal_voltage=100,  # kV
        lv_nominal_voltage=10,  # kV
        nominal_power=s,
        copper_losses=complex_impedance(z, xr).real * s * 1000 / Sbase,
        iron_losses=6.25,  # kW
        no_load_current=0.5,  # %
        short_circuit_voltage=z)
    grid.add_transformer_type(SS)

    s = 5  # MVA
    z = 6  # %
    xr = 20
    PM = TransformerType(
        name="PM",
        hv_nominal_voltage=10,  # kV
        lv_nominal_voltage=0.6,  # kV
        nominal_power=s,
        copper_losses=complex_impedance(z, xr).real * s * 1000 / Sbase,
        iron_losses=6.25,  # kW
        no_load_current=0.5,  # %
        short_circuit_voltage=z)
    grid.add_transformer_type(PM)

    # Create branches
    X_C3 = Branch(bus_from=POI,
                  bus_to=B_C3,
                  name="X_C3",
                  branch_type=BranchType.Transformer,
                  template=SS,
                  tap=1.05)
    grid.add_branch(X_C3)

    C_M32 = Branch(bus_from=B_C3,
                   bus_to=B_MV_M32,
                   name="C_M32",
                   r=0.784,
                   x=0.174)
    grid.add_branch(C_M32)

    X_M32 = Branch(bus_from=B_MV_M32,
                   bus_to=B_LV_M32,
                   name="X_M32",
                   branch_type=BranchType.Transformer,
                   template=PM)
    grid.add_branch(X_M32)

    # Apply templates (device types)
    grid.apply_all_branch_types()

    print("Buses:")
    for i, b in enumerate(grid.buses):
        print(f" - bus[{i}]: {b}")
    print()

    options = PowerFlowOptions(SolverType.NR,
                               verbose=True,
                               initialize_with_existing_solution=True,
                               multi_core=True,
                               control_q=ReactivePowerControlMode.Direct,
                               tolerance=1e-6,
                               max_iter=99)

    power_flow = PowerFlowDriver(grid, options)
    power_flow.run()

    approx_volt = [round(100 * abs(v), 1) for v in power_flow.results.voltage]
    solution = [100.0, 94.7, 98.0, 98.1]  # Expected solution from GridCal

    print()
    print(f"Test: {test_name}")
    print(f"Results:  {approx_volt}")
    print(f"Solution: {solution}")
    print()

    print("Generators:")
    for g in grid.get_generators():
        print(f" - Generator {g}: q_min={g.Qmin} MVAR, q_max={g.Qmax} MVAR")
    print()

    print("Branches:")
    for b in grid.branches:
        print(f" - {b}:")
        print(f"   R = {round(b.R, 4)} pu")
        print(f"   X = {round(b.X, 4)} pu")
        print(f"   X/R = {round(b.X/b.R, 1)}")
        print(f"   G = {round(b.G, 4)} pu")
        print(f"   B = {round(b.B, 4)} pu")
    print()

    print("Transformer types:")
    for t in grid.transformer_types:
        print(
            f" - {t}: Copper losses={int(t.Pcu)}kW, Iron losses={int(t.Pfe)}kW, SC voltage={t.Vsc}%"
        )
    print()

    print("Losses:")
    for i in range(len(grid.branches)):
        print(
            f" - {grid.branches[i]}: losses={1000*round(power_flow.results.losses[i], 3)} kVA"
        )
    print()

    equal = True
    for i in range(len(approx_volt)):
        if approx_volt[i] != solution[i]:
            equal = False

    assert equal
def test_pv_3():
    """
    Voltage controlled generator test, also useful for a basic tutorial. In this
    case the generator M32 regulates the voltage at a setpoint of 1.025 pu, and
    the slack bus (POI) regulates it at 1.0 pu.

    The transformers' magnetizing branch losses are considered, as well as the
    main power transformer's voltage regulator (X_C3) which regulates bus
    B_MV_M32 at 1.005 pu.

    In addition, the iterative PV control method is used instead of the usual
    (faster) method.
    """
    test_name = "test_pv_3"
    grid = MultiCircuit(name=test_name)
    Sbase = 100  # MVA
    grid.Sbase = Sbase
    grid.time_profile = None
    grid.logger = Logger()

    # Create buses
    POI = Bus(
        name="POI",
        vnom=100,  # kV
        is_slack=True)
    grid.add_bus(POI)

    B_MV_M32 = Bus(name="B_MV_M32", vnom=10)  # kV
    grid.add_bus(B_MV_M32)

    B_LV_M32 = Bus(name="B_LV_M32", vnom=0.6)  # kV
    grid.add_bus(B_LV_M32)

    # Create voltage controlled generators (or slack, a.k.a. swing)
    UT = Generator(name="Utility")
    UT.bus = POI
    grid.add_generator(POI, UT)

    M32 = Generator(name="M32",
                    active_power=4.2,
                    voltage_module=1.025,
                    Qmin=-2.5,
                    Qmax=2.5)
    M32.bus = B_LV_M32
    grid.add_generator(B_LV_M32, M32)

    # Create transformer types
    s = 100  # MVA
    z = 8  # %
    xr = 40
    SS = TransformerType(
        name="SS",
        hv_nominal_voltage=100,  # kV
        lv_nominal_voltage=10,  # kV
        nominal_power=s,
        copper_losses=complex_impedance(z, xr).real * s * 1000 / Sbase,
        iron_losses=125,  # kW
        no_load_current=0.5,  # %
        short_circuit_voltage=z)
    grid.add_transformer_type(SS)

    s = 5  # MVA
    z = 6  # %
    xr = 20
    PM = TransformerType(
        name="PM",
        hv_nominal_voltage=10,  # kV
        lv_nominal_voltage=0.6,  # kV
        nominal_power=s,
        copper_losses=complex_impedance(z, xr).real * s * 1000 / Sbase,
        iron_losses=6.25,  # kW
        no_load_current=0.5,  # %
        short_circuit_voltage=z)
    grid.add_transformer_type(PM)

    # Create branches
    X_C3 = Branch(bus_from=POI,
                  bus_to=B_MV_M32,
                  name="X_C3",
                  branch_type=BranchType.Transformer,
                  template=SS,
                  bus_to_regulated=True,
                  vset=1.005)
    X_C3.tap_changer = TapChanger(taps_up=16,
                                  taps_down=16,
                                  max_reg=1.1,
                                  min_reg=0.9)
    X_C3.tap_changer.set_tap(X_C3.tap_module)
    grid.add_branch(X_C3)

    X_M32 = Branch(bus_from=B_MV_M32,
                   bus_to=B_LV_M32,
                   name="X_M32",
                   branch_type=BranchType.Transformer,
                   template=PM)
    grid.add_branch(X_M32)

    # Apply templates (device types)
    grid.apply_all_branch_types()

    print("Buses:")
    for i, b in enumerate(grid.buses):
        print(f" - bus[{i}]: {b}")
    print()

    options = PowerFlowOptions(SolverType.LM,
                               verbose=True,
                               initialize_with_existing_solution=True,
                               multi_core=True,
                               control_q=ReactivePowerControlMode.Iterative,
                               control_taps=TapsControlMode.Direct,
                               tolerance=1e-6,
                               max_iter=99)

    power_flow = PowerFlowDriver(grid, options)
    power_flow.run()

    approx_volt = [round(100 * abs(v), 1) for v in power_flow.results.voltage]
    solution = [100.0, 100.7, 102.5]  # Expected solution from GridCal

    print()
    print(f"Test: {test_name}")
    print(f"Results:  {approx_volt}")
    print(f"Solution: {solution}")
    print()

    print("Generators:")
    for g in grid.get_generators():
        print(f" - Generator {g}: q_min={g.Qmin} MVAR, q_max={g.Qmax} MVAR")
    print()

    print("Branches:")
    for b in grid.branches:
        print(f" - {b}:")
        print(f"   R = {round(b.R, 4)} pu")
        print(f"   X = {round(b.X, 4)} pu")
        print(f"   X/R = {round(b.X / b.R, 1)}")
        print(f"   G = {round(b.G, 4)} pu")
        print(f"   B = {round(b.B, 4)} pu")
    print()

    print("Transformer types:")
    for t in grid.transformer_types:
        print(
            f" - {t}: Copper losses={int(t.Pcu)}kW, Iron losses={int(t.Pfe)}kW, SC voltage={t.Vsc}%"
        )
    print()

    print("Losses:")
    for i in range(len(grid.branches)):
        print(
            f" - {grid.branches[i]}: losses={1000 * round(power_flow.results.losses[i], 3)} kVA"
        )
    print()

    equal = True
    for i in range(len(approx_volt)):
        if approx_volt[i] != solution[i]:
            equal = False

    assert equal
示例#14
0
def main():
    ####################################################################################################################
    # Define the circuit
    #
    # A circuit contains all the grid information regardless of the islands formed or the amount of devices
    ####################################################################################################################


    grid = MultiCircuit(name='lynn 5 bus')

    ####################################################################################################################
    # Define the buses
    ####################################################################################################################
    # I will define this bus with all the properties so you see
    bus1 = Bus(name='Bus1',
               vnom=10,   # Nominal voltage in kV
               vmin=0.9,  # Bus minimum voltage in per unit
               vmax=1.1,  # Bus maximum voltage in per unit
               xpos=0,    # Bus x position in pixels
               ypos=0,    # Bus y position in pixels
               height=0,  # Bus height in pixels
               width=0,   # Bus width in pixels
               active=True,   # Is the bus active?
               is_slack=False,  # Is this bus a slack bus?
               area='Defualt',  # Area (for grouping purposes only)
               zone='Default',  # Zone (for grouping purposes only)
               substation='Default'  # Substation (for grouping purposes only)
               )

    # the rest of the buses are defined with the default parameters
    bus2 = Bus(name='Bus2')
    bus3 = Bus(name='Bus3')
    bus4 = Bus(name='Bus4')
    bus5 = Bus(name='Bus5')

    # add the bus objects to the circuit
    grid.add_bus(bus1)
    grid.add_bus(bus2)
    grid.add_bus(bus3)
    grid.add_bus(bus4)
    grid.add_bus(bus5)

    ####################################################################################################################
    # Add the loads
    ####################################################################################################################
    # In GridCal, the loads, generators ect are stored within each bus object:

    # we'll define the first load completely
    l2 = Load(name='Load',
              G=0,  # Impedance of the ZIP model in MVA at the nominal voltage
              B=0,
              Ir=0,
              Ii=0,  # Current of the ZIP model in MVA at the nominal voltage
              P=40,
              Q=20,  # Power of the ZIP model in MVA
              P_prof=None,  # Impedance profile
              Q_prof=None,  # Current profile
              Ir_prof=None,  # Power profile
              Ii_prof=None,
              G_prof=None,
              B_prof=None,
              active=True,  # Is active?
              mttf=0.0,  # Mean time to failure
              mttr=0.0  # Mean time to recovery
              )
    grid.add_load(bus2, l2)

    # Define the others with the default parameters
    grid.add_load(bus3, Load(P=25, Q=15))
    grid.add_load(bus4, Load(P=40, Q=20))
    grid.add_load(bus5, Load(P=50, Q=20))

    ####################################################################################################################
    # Add the generators
    ####################################################################################################################

    g1 = Generator(name='gen',
                   active_power=0.0,  # Active power in MW, since this generator is used to set the slack , is 0
                   voltage_module=1.0,  # Voltage set point to control
                   Qmin=-9999,  # minimum reactive power in MVAr
                   Qmax=9999,  # Maximum reactive power in MVAr
                   Snom=9999,  # Nominal power in MVA
                   power_prof=None,  # power profile
                   vset_prof=None,  # voltage set point profile
                   active=True  # Is active?
                   )
    grid.add_generator(bus1, g1)

    ####################################################################################################################
    # Add the lines
    ####################################################################################################################

    br1 = Branch(bus_from=bus1,
                 bus_to=bus2,
                 name='Line 1-2',
                 r=0.05,  # resistance of the pi model in per unit
                 x=0.11,  # reactance of the pi model in per unit
                 g=1e-20,  # conductance of the pi model in per unit
                 b=0.02,  # susceptance of the pi model in per unit
                 rate=50,  # Rate in MVA
                 tap=1.0,  # Tap value (value close to 1)
                 shift_angle=0,  # Tap angle in radians
                 active=True,  # is the branch active?
                 mttf=0,  # Mean time to failure
                 mttr=0,  # Mean time to recovery
                 branch_type=BranchType.Line,  # Branch type tag
                 length=1,  # Length in km (to be used with templates)
                 template=BranchTemplate()  # Branch template (The default one is void)
                 )
    grid.add_branch(br1)

    grid.add_branch(Branch(bus1, bus3, name='Line 1-3', r=0.05, x=0.11, b=0.02, rate=50))
    grid.add_branch(Branch(bus1, bus5, name='Line 1-5', r=0.03, x=0.08, b=0.02, rate=80))
    grid.add_branch(Branch(bus2, bus3, name='Line 2-3', r=0.04, x=0.09, b=0.02, rate=3))
    grid.add_branch(Branch(bus2, bus5, name='Line 2-5', r=0.04, x=0.09, b=0.02, rate=10))
    grid.add_branch(Branch(bus3, bus4, name='Line 3-4', r=0.06, x=0.13, b=0.03, rate=30))
    grid.add_branch(Branch(bus4, bus5, name='Line 4-5', r=0.04, x=0.09, b=0.02, rate=30))

    ####################################################################################################################
    # Run a power flow simulation
    ####################################################################################################################

    # We need to specify power flow options
    pf_options = PowerFlowOptions(solver_type=SolverType.NR,  # Base method to use
                                  verbose=False,  # Verbose option where available
                                  tolerance=1e-6,  # power error in p.u.
                                  max_iter=25,  # maximum iteration number
                                  control_q=True  # if to control the reactive power
                                  )

    # Declare and execute the power flow simulation
    pf = PowerFlowDriver(grid, pf_options)
    pf.run()

    # now, let's compose a nice DataFrame with the voltage results
    headers = ['Vm (p.u.)', 'Va (Deg)', 'Vre', 'Vim']
    Vm = np.abs(pf.results.voltage)
    Va = np.angle(pf.results.voltage, deg=True)
    Vre = pf.results.voltage.real
    Vim = pf.results.voltage.imag
    data = np.c_[Vm, Va, Vre, Vim]
    v_df = pd.DataFrame(data=data, columns=headers, index=grid.bus_names)
    print('\n', v_df)


    # Let's do the same for the branch results
    headers = ['Loading (%)', 'Current(p.u.)', 'Power (MVA)']
    loading = np.abs(pf.results.loading) * 100
    current = np.abs(pf.results.Ibranch)
    power = np.abs(pf.results.Sbranch)
    data = np.c_[loading, current, power]
    br_df = pd.DataFrame(data=data, columns=headers, index=grid.branch_names)
    print('\n', br_df)

    # Finally the execution metrics
    print('\nError:', pf.results.error)
    print('Elapsed time (s):', pf.results.elapsed, '\n')

    print(v_df)
    print()
    print(br_df)
示例#15
0
class GridGeneratorGUI(QDialog):
    def __init__(
        self,
        parent=None,
    ):
        """

        :param parent:
        """
        QDialog.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setWindowTitle('Grid Generator')

        self.g = RpgAlgorithm()
        self.circuit = MultiCircuit()
        self.applied = False

        self.ui.applyButton.clicked.connect(self.apply)
        self.ui.previewButton.clicked.connect(self.preview)

    def msg(self, text, title="Warning"):
        """
        Message box
        :param text: Text to display
        :param title: Name of the window
        """
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Information)
        msg.setText(text)
        # msg.setInformativeText("This is additional information")
        msg.setWindowTitle(title)
        # msg.setDetailedText("The details are as follows:")
        msg.setStandardButtons(QMessageBox.Ok)
        retval = msg.exec_()

    def fill_graph(self):
        """
        # set desired parameters and perform algorithm
        :return:
        """
        self.g = RpgAlgorithm()

        n = self.ui.nodes_spinBox.value()
        n0 = 10
        r = self.ui.ratio_SpinBox.value()
        if n0 >= n:
            n0 = n - 1

        self.g.set_params(n=n, n0=n0, r=r)
        self.g.initialise()
        self.g.grow()

    def preview(self):
        """

        :return:
        """
        self.fill_graph()
        G = nx.Graph(self.g.edges)
        pos = {
            i: (self.g.lat[i], self.g.lon[i])
            for i in range(self.g.added_nodes)
        }

        self.ui.plotwidget.clear()
        nx.draw(G,
                ax=self.ui.plotwidget.get_axis(),
                pos=pos,
                with_labels=True,
                node_color='lightblue')
        self.ui.plotwidget.redraw()

    def apply(self):
        """
        Create graph, then the circuit and close
        :return: Nothing
        """
        self.fill_graph()

        self.circuit = MultiCircuit()

        explosion_factor = 10000.0

        # number of nodes
        n = self.g.added_nodes

        # assign the load and generation buses
        genbus = self.ui.generation_nodes_SpinBox.value()
        loadbus = self.ui.load_nodes_SpinBox.value()

        if (genbus + loadbus) > 100:
            s = genbus + loadbus
            genbus /= s
            loadbus /= s

        gen_buses_num = int(np.floor(n * genbus / 100))
        load_buses_num = int(np.floor(n * loadbus / 100))

        rng = default_rng()
        numbers = rng.choice(n,
                             size=gen_buses_num + load_buses_num,
                             replace=False)

        gen_buses = numbers[:gen_buses_num]
        load_buses = numbers[gen_buses_num:]

        pmax = self.ui.power_SpinBox.value()

        # generate buses
        bus_dict = dict()
        for i in range(n):

            bus = Bus(name='Bus ' + str(i + 1),
                      xpos=self.g.lat[i] * explosion_factor,
                      ypos=-self.g.lon[i] * explosion_factor)

            bus_dict[i] = bus

            self.circuit.add_bus(bus)

        # generate loads
        factor = np.random.random(load_buses_num)
        factor /= factor.sum()
        pf = self.ui.power_factor_SpinBox.value()
        for k, i in enumerate(load_buses):
            bus = bus_dict[i]
            p = pmax * factor[k]
            q = p * pf
            load = Load(name='Load@bus' + str(i + 1), P=p, Q=q)
            self.circuit.add_load(bus, load)

        # generate generators
        factor = np.random.random(gen_buses_num)
        factor /= factor.sum()
        for k, i in enumerate(gen_buses):
            bus = bus_dict[i]
            gen = Generator(name='Generator@bus' + str(i + 1),
                            active_power=pmax * factor[k])
            self.circuit.add_generator(bus, gen)

        # generate lines
        r = self.ui.r_SpinBox.value()
        x = self.ui.x_SpinBox.value()
        b = self.ui.b_SpinBox.value()

        for f, t in self.g.edges:
            dx = (self.g.lat[f] - self.g.lat[t]) * explosion_factor
            dy = (self.g.lon[f] - self.g.lon[t]) * explosion_factor
            m = np.sqrt(
                dx * dx +
                dy * dy) / 10.0  # divided by 10 to have more meaningful values

            b1 = bus_dict[f]
            b2 = bus_dict[t]
            lne = Line(bus_from=b1,
                       bus_to=b2,
                       name='Line ' + str(f) + '-' + str(t),
                       r=r * m,
                       x=x * m,
                       b=b * m,
                       length=m)
            self.circuit.add_line(lne)

        # quit
        self.applied = True
        self.close()
示例#16
0
def parse_json_data_v2(data: dict, logger: Logger):
    """
    New Json parser
    :param data:
    :param logger:
    :return:
    """
    devices = data['devices']
    profiles = data['profiles']

    if DeviceType.CircuitDevice.value in devices.keys():

        dta = devices[DeviceType.CircuitDevice.value]
        circuit = MultiCircuit(name=str(dta['name']),
                               Sbase=float(dta['sbase']),
                               fbase=float(dta['fbase']),
                               idtag=str(dta['id']))

        jcircuit = devices["Circuit"]
        circuit.Sbase = jcircuit["sbase"]

        bus_dict = dict()

        if 'Bus' in devices.keys():
            buses = devices["Bus"]
            for jentry in buses:
                bus = Bus(name=str(jentry['name']),
                          idtag=str(jentry['id']),
                          vnom=float(jentry['vnom']),
                          vmin=float(jentry['vmin']),
                          vmax=float(jentry['vmax']),
                          r_fault=float(jentry['rf']),
                          x_fault=float(jentry['xf']),
                          xpos=float(jentry['x']),
                          ypos=float(jentry['y']),
                          height=float(jentry['h']),
                          width=float(jentry['w']),
                          active=bool(jentry['active']),
                          is_slack=bool(jentry['is_slack']),
                          # is_dc=jbus['id'],
                          area=jentry['area'],
                          zone=jentry['zone'],
                          substation=jentry['substation'],
                          # country=jbus['id'],
                          longitude=float(jentry['lon']),
                          latitude=float(jentry['lat']) )

                bus_dict[jentry['id']] = bus
                circuit.add_bus(bus)

        if 'Generator' in devices.keys():
            generators = devices["Generator"]
            for jentry in generators:
                gen = Generator(name=str(jentry['name']),
                                idtag=str(jentry['id']),
                                active_power=float(jentry['p']),
                                power_factor=float(jentry['pf']),
                                voltage_module=float(jentry['vset']),
                                is_controlled=bool(jentry['is_controlled']),
                                Qmin=float(jentry['qmin']),
                                Qmax=float(jentry['qmax']),
                                Snom=float(jentry['snom']),
                                # power_prof=jgen['name'],
                                # power_factor_prof=jgen['name'],
                                # vset_prof=jgen['name'],
                                # Cost_prof=jgen['name'],
                                active=bool(jentry['active']),
                                p_min=float(jentry['pmin']),
                                p_max=float(jentry['pmax']),
                                op_cost=float(jentry['cost']),
                                # Sbase=jgen['name'],
                                # enabled_dispatch=jgen['name'],
                                # mttf=jgen['name'],
                                # mttr=jgen['name']
                                )
                gen.bus = bus_dict[jentry['bus']]
                circuit.add_generator(gen.bus, gen)

        if 'Battery' in devices.keys():
            batteries = devices["Battery"]
            for jentry in batteries:
                gen = Battery(name=str(jentry['name']),
                              idtag=str(jentry['id']),
                              active_power=float(jentry['p']),
                              power_factor=float(jentry['pf']),
                              voltage_module=float(jentry['vset']),
                              is_controlled=bool(jentry['is_controlled']),
                              Qmin=float(jentry['qmin']),
                              Qmax=float(jentry['qmax']),
                              Snom=float(jentry['snom']),
                              # power_prof=jgen['name'],
                              # power_factor_prof=jgen['name'],
                              # vset_prof=jgen['name'],
                              # Cost_prof=jgen['name'],
                              active=bool(jentry['active']),
                              p_min=float(jentry['pmin']),
                              p_max=float(jentry['pmax']),
                              op_cost=float(jentry['cost']),
                              # Sbase=jgen['name'],
                              # enabled_dispatch=jgen['name'],
                              # mttf=jgen['name'],
                              # mttr=jgen['name']
                              )
                gen.bus = bus_dict[jentry['bus']]
                circuit.add_battery(gen.bus, gen)

        if 'Load' in devices.keys():
            loads = devices["Load"]
            for jentry in loads:
                elm = Load(name=str(jentry['name']),
                           idtag=str(jentry['id']),
                           # G: float = 0.0,
                           # B: float = 0.0,
                           # Ir: float = 0.0,
                           # Ii: float = 0.0,
                           P=float(jentry['p']),
                           Q=float(jentry['q']),
                           # cost=jentry['cost'],
                           # G_prof: Any = None,
                           # B_prof: Any = None,
                           # Ir_prof: Any = None,
                           # Ii_prof: Any = None,
                           # P_prof: Any = None,
                           # Q_prof: Any = None,
                           active=bool(jentry['active']))
                elm.bus = bus_dict[jentry['bus']]
                circuit.add_load(elm.bus, elm)

        if "Shunt" in devices.keys():
            shunts = devices["Shunt"]
            for jentry in shunts:
                elm = Shunt(name=str(jentry['name']),
                            idtag=str(jentry['id']),
                            G=float(jentry['g']),
                            B=float(jentry['b']),
                            # G_prof: Any = None,
                            # B_prof: Any = None,
                            active=bool(jentry['active']))
                elm.bus = bus_dict[jentry['bus']]
                circuit.add_shunt(elm.bus, elm)

        if "Line" in devices.keys():
            lines = devices["Line"]
            for entry in lines:
                elm = Line(bus_from=bus_dict[entry['bus_from']],
                           bus_to=bus_dict[entry['bus_to']],
                           name=str(entry['name']),
                           idtag=str(entry['id']),
                           r=float(entry['r']),
                           x=float(entry['x']),
                           b=float(entry['b']),
                           rate=float(entry['rate']),
                           active=entry['active'],
                           # tolerance: int = 0,
                           # cost: float = 0.0,
                           # mttf: int = 0,
                           # mttr: int = 0,
                           # r_fault: float = 0.0,
                           # x_fault: float = 0.0,
                           # fault_pos: float = 0.5,
                           length=float(entry['length']),
                           # temp_base: int = 20,
                           # temp_oper: int = 20,
                           # alpha: float = 0.00330,
                           # template: LineTemplate = LineTemplate(),
                           # rate_prof: Any = None,
                           # Cost_prof: Any = None,
                           # active_prof: Any = None,
                           # temp_oper_prof: Any = None
                           )
                circuit.add_line(elm)

        if "Transformer" in devices.keys():
            transformers = devices["Transformer"]
            for entry in transformers:
                elm = Transformer2W(bus_from=bus_dict[entry['bus_from']],
                                    bus_to=bus_dict[entry['bus_to']],
                                    name=str(entry['name']),
                                    idtag=str(entry['id']),
                                    r=float(entry['r']),
                                    x=float(entry['x']),
                                    g=float(entry['g']),
                                    b=float(entry['b']),
                                    rate=float(entry['rate']),
                                    active=bool(entry['active']),
                                    tap=float(entry['tap_module']),
                                    shift_angle=float(entry['tap_angle']),
                                    # tolerance: int = 0,
                                    # cost: float = 0.0,
                                    # mttf: int = 0,
                                    # mttr: int = 0,
                                    # r_fault: float = 0.0,
                                    # x_fault: float = 0.0,
                                    # fault_pos: float = 0.5,
                                    # temp_base: int = 20,
                                    # temp_oper: int = 20,
                                    # alpha: float = 0.00330,
                                    # template: LineTemplate = LineTemplate(),
                                    # rate_prof: Any = None,
                                    # Cost_prof: Any = None,
                                    # active_prof: Any = None,
                                    # temp_oper_prof: Any = None
                                    )
                circuit.add_transformer2w(elm)

        if "VSC" in devices.keys():
            vsc = devices["VSC"]

        if "HVDC Line" in devices.keys():
            hvdc = devices["HVDC Line"]

        return circuit

    else:
        logger.add('The Json structure does not have a Circuit inside the devices!')
        return MultiCircuit()
示例#17
0
def get_grid_lynn_5_bus_wiki():
    grid = MultiCircuit(name='lynn 5 bus')

    bus_1 = Bus(
        name='bus_1',
        vnom=10,  # Nominal voltage in kV
        vmin=0.9,  # Bus minimum voltage in per unit
        vmax=1.1,  # Bus maximum voltage in per unit
        xpos=0,  # Bus x position in pixels
        ypos=0,  # Bus y position in pixels
        height=0,  # Bus height in pixels
        width=0,  # Bus width in pixels
        active=True,  # Is the bus active?
        is_slack=False,  # Is this bus a slack bus?
        area='Default',  # Area (for grouping purposes only)
        zone='Default',  # Zone (for grouping purposes only)
        substation='Default'  # Substation (for grouping purposes only)
    )
    bus_2 = Bus(name='bus_2')
    bus_3 = Bus(name='bus_3')
    bus_4 = Bus(name='bus_4')
    bus_5 = Bus(name='bus_5')
    grid.add_bus(bus_1)
    grid.add_bus(bus_2)
    grid.add_bus(bus_3)
    grid.add_bus(bus_4)
    grid.add_bus(bus_5)
    load_2 = Load(
        name='Load',
        # impedance=complex(0, 0),
        # Impedance of the ZIP model in MVA at the nominal voltage
        # current=complex(0, 0),
        # Current of the ZIP model in MVA at the nominal voltage
        # power=complex(40, 20),  # Power of the ZIP model in MVA
        # impedance_prof=None,  # Impedance profile
        # current_prof=None,  # Current profile
        # power_prof=None,  # Power profile
        active=True,  # Is active?
        mttf=0.0,  # Mean time to failure
        mttr=0.0  # Mean time to recovery
    )
    grid.add_load(bus_2, load_2)
    grid.add_load(
        bus_3,
        Load(
            # power=complex(25, 15)
        ))
    grid.add_load(
        bus_4,
        Load(
            # power=complex(40, 20)
        ))
    grid.add_load(
        bus_5,
        Load(
            # power=complex(50, 20)
        ))
    generator_1 = Generator(
        name='gen',
        active_power=0.0,
        # Active power in MW, since this generator is used to set the slack , is 0
        voltage_module=1.0,  # Voltage set point to control
        Qmin=-9999,  # minimum reactive power in MVAr
        Qmax=9999,  # Maximum reactive power in MVAr
        Snom=9999,  # Nominal power in MVA
        power_prof=None,  # power profile
        vset_prof=None,  # voltage set point profile
        active=True  # Is active?
    )
    grid.add_generator(bus_1, generator_1)
    branch_1 = Branch(
        bus_from=bus_1,
        bus_to=bus_2,
        name='Line 1-2',
        r=0.05,  # resistance of the pi model in per unit
        x=0.11,  # reactance of the pi model in per unit
        g=1e-20,  # conductance of the pi model in per unit
        b=0.02,  # susceptance of the pi model in per unit
        rate=50,  # Rate in MVA
        tap=1.0,  # Tap value (value close to 1)
        shift_angle=0,  # Tap angle in radians
        active=True,  # is the branch active?
        mttf=0,  # Mean time to failure
        mttr=0,  # Mean time to recovery
        branch_type=BranchType.Line,  # Branch type tag
        length=1,  # Length in km (to be used with templates)
        # type_obj=BranchTemplate()
        # Branch template (The default one is void)
    )
    grid.add_branch(branch_1)
    grid.add_branch(
        Branch(bus_1, bus_3, name='Line 1-3', r=0.05, x=0.11, b=0.02, rate=50))
    grid.add_branch(
        Branch(bus_1, bus_5, name='Line 1-5', r=0.03, x=0.08, b=0.02, rate=80))
    grid.add_branch(
        Branch(bus_2, bus_3, name='Line 2-3', r=0.04, x=0.09, b=0.02, rate=3))
    grid.add_branch(
        Branch(bus_2, bus_5, name='Line 2-5', r=0.04, x=0.09, b=0.02, rate=10))
    grid.add_branch(
        Branch(bus_3, bus_4, name='Line 3-4', r=0.06, x=0.13, b=0.03, rate=30))
    grid.add_branch(
        Branch(bus_4, bus_5, name='Line 4-5', r=0.04, x=0.09, b=0.02, rate=30))

    grid.compile()

    return grid
示例#18
0
def interprete_excel_v2(circuit: MultiCircuit, data):
    """
    Interpret the file version 2
    :param circuit:
    :param data: Dictionary with the excel file sheet labels and the corresponding DataFrame
    :return: Nothing, just applies the loaded data to this MultiCircuit instance
    """

    # print('Interpreting V2 data...')

    # clear all the data
    circuit.clear()

    circuit.name = data['name']

    # set the base magnitudes
    circuit.Sbase = data['baseMVA']

    # dictionary of branch types [name] -> type object
    branch_types = dict()

    # Set comments
    circuit.comments = data['Comments'] if 'Comments' in data.keys() else ''

    circuit.time_profile = None

    circuit.logger = Logger()

    # common function
    def set_object_attributes(obj_, attr_list, values):
        for a, attr in enumerate(attr_list):

            # Hack to change the enabled by active...
            if attr == 'is_enabled':
                attr = 'active'

            if attr == 'type_obj':
                attr = 'template'

            if hasattr(obj_, attr):
                conv = obj_.editable_headers[
                    attr].tpe  # get the type converter
                if conv is None:
                    setattr(obj_, attr, values[a])
                elif conv is BranchType:
                    cbr = BranchTypeConverter(None)
                    setattr(obj_, attr, cbr(values[a]))
                else:
                    setattr(obj_, attr, conv(values[a]))
            else:

                if attr in [
                        'Y', 'Z', 'I', 'S', 'seq_resistance', 'seq_admittance',
                        'Zf'
                ]:

                    if attr == 'Z':
                        val = complex(values[a])
                        re = 1 / val.real if val.real != 0.0 else 0
                        im = 1 / val.imag if val.imag != 0.0 else 0
                        setattr(obj_, 'G', re)
                        setattr(obj_, 'B', im)

                    if attr == 'Zf':
                        val = complex(values[a])
                        re = 1 / val.real if val.real != 0.0 else 0
                        im = 1 / val.imag if val.imag != 0.0 else 0
                        setattr(obj_, 'r_fault', re)
                        setattr(obj_, 'x_fault', im)

                    if attr == 'Y':
                        val = complex(values[a])
                        re = val.real
                        im = val.imag
                        setattr(obj_, 'G', re)
                        setattr(obj_, 'B', im)

                    elif attr == 'I':
                        val = complex(values[a])
                        setattr(obj_, 'Ir', val.real)
                        setattr(obj_, 'Ii', val.imag)

                    elif attr == 'S':
                        val = complex(values[a])
                        setattr(obj_, 'P', val.real)
                        setattr(obj_, 'Q', val.imag)

                    elif attr == 'seq_resistance':
                        val = complex(values[a])
                        setattr(obj_, 'R1', val.real)
                        setattr(obj_, 'X1', val.imag)

                    elif attr == 'seq_admittance':
                        val = complex(values[a])
                        setattr(obj_, 'Gsh1', val.real)
                        setattr(obj_, 'Bsh1', val.imag)

                else:
                    warn(str(obj_) + ' has no ' + attr + ' property.')

    # Add the buses ################################################################################################
    bus_dict = dict()
    if 'bus' in data.keys():
        lst = data['bus']
        hdr = lst.columns.values
        vals = lst.values
        for i in range(len(lst)):
            obj = Bus()
            set_object_attributes(obj, hdr, vals[i, :])
            bus_dict[obj.name] = obj
            circuit.add_bus(obj)
    else:
        circuit.logger.append('No buses in the file!')

    # add the loads ################################################################################################
    if 'load' in data.keys():
        lst = data['load']
        bus_from = lst['bus'].values
        hdr = lst.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus'))
        vals = lst[hdr].values
        for i in range(len(lst)):
            obj = Load()
            set_object_attributes(obj, hdr, vals[i, :])

            if 'load_Sprof' in data.keys():

                idx = data['load_Sprof'].index

                # create all the profiles
                obj.create_profiles(index=idx)

                # create the power profiles
                val = np.array(
                    [complex(v) for v in data['load_Sprof'].values[:, i]])
                obj.create_profile(magnitude='P', index=idx, arr=val.real)
                obj.create_profile(magnitude='Q', index=idx, arr=val.imag)

                if circuit.time_profile is None or len(
                        circuit.time_profile) < len(idx):
                    circuit.time_profile = idx

            if 'load_Iprof' in data.keys():
                val = np.array(
                    [complex(v) for v in data['load_Iprof'].values[:, i]])
                idx = data['load_Iprof'].index
                obj.create_profile(magnitude='Ir', index=idx, arr=val.real)
                obj.create_profile(magnitude='Ii', index=idx, arr=val.imag)

                if circuit.time_profile is None or len(
                        circuit.time_profile) < len(idx):
                    circuit.time_profile = idx

            if 'load_Zprof' in data.keys():
                val = np.array(
                    [complex(v) for v in data['load_Zprof'].values[:, i]])
                idx = data['load_Zprof'].index
                obj.create_profile(magnitude='G', index=idx, arr=val.real)
                obj.create_profile(magnitude='B', index=idx, arr=val.imag)

                if circuit.time_profile is None or len(
                        circuit.time_profile) < len(idx):
                    circuit.time_profile = idx

            try:
                bus = bus_dict[str(bus_from[i])]
            except KeyError as ex:
                raise Exception(
                    str(i) + ': Load bus is not in the buses list.\n' +
                    str(ex))

            if obj.name == 'Load':
                obj.name += str(len(bus.loads) + 1) + '@' + bus.name

            obj.bus = bus
            bus.loads.append(obj)
            obj.ensure_profiles_exist(circuit.time_profile)
    else:
        circuit.logger.append('No loads in the file!')

    # add the controlled generators ################################################################################
    if 'controlled_generator' in data.keys():
        lst = data['controlled_generator']
        bus_from = lst['bus'].values
        hdr = lst.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus'))
        vals = lst[hdr].values
        for i in range(len(lst)):
            obj = Generator()
            set_object_attributes(obj, hdr, vals[i, :])

            if 'CtrlGen_P_profiles' in data.keys():
                val = data['CtrlGen_P_profiles'].values[:, i]
                idx = data['CtrlGen_P_profiles'].index
                obj.create_profile(magnitude='P', index=idx, arr=val)
                # also create the Pf array because there might not be values in the file
                obj.create_profile(magnitude='Pf', index=idx)

            if 'CtrlGen_Pf_profiles' in data.keys():
                val = data['CtrlGen_Pf_profiles'].values[:, i]
                idx = data['CtrlGen_Pf_profiles'].index
                obj.create_profile(magnitude='Pf', index=idx, arr=val)

            if 'CtrlGen_Vset_profiles' in data.keys():
                val = data['CtrlGen_Vset_profiles'].values[:, i]
                idx = data['CtrlGen_Vset_profiles'].index
                obj.create_profile(magnitude='Vset', index=idx, arr=val)

            try:
                bus = bus_dict[str(bus_from[i])]
            except KeyError as ex:
                raise Exception(
                    str(i) +
                    ': Controlled generator bus is not in the buses list.\n' +
                    str(ex))

            if obj.name == 'gen':
                obj.name += str(len(bus.controlled_generators) +
                                1) + '@' + bus.name

            obj.bus = bus
            bus.controlled_generators.append(obj)
            obj.ensure_profiles_exist(circuit.time_profile)
    else:
        circuit.logger.append('No controlled generator in the file!')

    # add the batteries ############################################################################################
    if 'battery' in data.keys():
        lst = data['battery']
        bus_from = lst['bus'].values
        hdr = lst.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus'))
        vals = lst[hdr].values
        for i in range(len(lst)):
            obj = Battery()
            set_object_attributes(obj, hdr, vals[i, :])

            if 'battery_P_profiles' in data.keys():
                val = data['battery_P_profiles'].values[:, i]
                idx = data['battery_P_profiles'].index
                obj.create_profile(magnitude='P', index=idx, arr=val)
                obj.create_profile(magnitude='Pf', index=idx)

            if 'battery_Pf_profiles' in data.keys():
                val = data['battery_Pf_profiles'].values[:, i]
                idx = data['battery_Pf_profiles'].index
                obj.create_profile(magnitude='Pf', index=idx, arr=val)

            if 'battery_Vset_profiles' in data.keys():
                val = data['battery_Vset_profiles'].values[:, i]
                idx = data['battery_Vset_profiles'].index
                obj.create_profile(magnitude='Vset', index=idx, arr=val)

            try:
                bus = bus_dict[str(bus_from[i])]
            except KeyError as ex:
                raise Exception(
                    str(i) + ': Battery bus is not in the buses list.\n' +
                    str(ex))

            if obj.name == 'batt':
                obj.name += str(len(bus.batteries) + 1) + '@' + bus.name

            obj.bus = bus
            bus.batteries.append(obj)
            obj.ensure_profiles_exist(circuit.time_profile)
    else:
        circuit.logger.append('No battery in the file!')

    # add the static generators ####################################################################################
    if 'static_generator' in data.keys():
        lst = data['static_generator']
        bus_from = lst['bus'].values
        hdr = lst.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus'))
        vals = lst[hdr].values
        for i in range(len(lst)):
            obj = StaticGenerator()
            set_object_attributes(obj, hdr, vals[i, :])

            if 'static_generator_Sprof' in data.keys():
                val = data['static_generator_Sprof'].values[:, i]
                idx = data['static_generator_Sprof'].index
                obj.create_profile(magnitude='P', index=idx, arr=val.real)
                obj.create_profile(magnitude='Q', index=idx, arr=val.imag)

            if 'static_generator_P_prof' in data.keys():
                val = data['static_generator_P_prof'].values[:, i]
                idx = data['static_generator_P_prof'].index
                obj.create_profile(magnitude='P', index=idx, arr=val)

            if 'static_generator_Q_prof' in data.keys():
                val = data['static_generator_Q_prof'].values[:, i]
                idx = data['static_generator_Q_prof'].index
                obj.create_profile(magnitude='Q', index=idx, arr=val)

            try:
                bus = bus_dict[str(bus_from[i])]
            except KeyError as ex:
                raise Exception(
                    str(i) +
                    ': Static generator bus is not in the buses list.\n' +
                    str(ex))

            if obj.name == 'StaticGen':
                obj.name += str(len(bus.static_generators) +
                                1) + '@' + bus.name

            obj.bus = bus
            bus.static_generators.append(obj)
            obj.ensure_profiles_exist(circuit.time_profile)
    else:
        circuit.logger.append('No static generator in the file!')

    # add the shunts ###############################################################################################
    if 'shunt' in data.keys():
        lst = data['shunt']
        bus_from = lst['bus'].values
        hdr = lst.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus'))
        vals = lst[hdr].values
        for i in range(len(lst)):
            obj = Shunt()
            set_object_attributes(obj, hdr, vals[i, :])

            if 'shunt_Y_profiles' in data.keys():
                val = data['shunt_Y_profiles'].values[:, i]
                idx = data['shunt_Y_profiles'].index
                obj.create_profile(magnitude='G', index=idx, arr=val.real)
                obj.create_profile(magnitude='B', index=idx, arr=val.imag)
            try:
                bus = bus_dict[str(bus_from[i])]
            except KeyError as ex:
                raise Exception(
                    str(i) + ': Shunt bus is not in the buses list.\n' +
                    str(ex))

            if obj.name == 'shunt':
                obj.name += str(len(bus.shunts) + 1) + '@' + bus.name

            obj.bus = bus
            bus.shunts.append(obj)
            obj.ensure_profiles_exist(circuit.time_profile)
    else:
        circuit.logger.append('No shunt in the file!')

    # Add the wires ################################################################################################
    if 'wires' in data.keys():
        lst = data['wires']
        hdr = lst.columns.values
        vals = lst.values
        for i in range(len(lst)):
            obj = Wire()
            set_object_attributes(obj, hdr, vals[i, :])
            circuit.add_wire(obj)
    else:
        circuit.logger.append('No wires in the file!')

    # Add the overhead_line_types ##################################################################################
    if 'overhead_line_types' in data.keys():
        lst = data['overhead_line_types']
        if data['overhead_line_types'].values.shape[0] > 0:
            for tower_name in lst['tower_name'].unique():
                obj = Tower()
                vals = lst[lst['tower_name'] == tower_name].values

                # set the tower values
                set_object_attributes(obj, obj.editable_headers.keys(),
                                      vals[0, :])

                # add the wires
                for i in range(vals.shape[0]):
                    wire = Wire()
                    set_object_attributes(wire, obj.get_wire_properties(),
                                          vals[i,
                                               len(obj.editable_headers):])
                    obj.wires_in_tower.append(wire)

                circuit.add_overhead_line(obj)
                branch_types[str(obj)] = obj
        else:
            pass
    else:
        circuit.logger.append('No overhead_line_types in the file!')

    # Add the wires ################################################################################################
    if 'underground_cable_types' in data.keys():
        lst = data['underground_cable_types']
        hdr = lst.columns.values
        vals = lst.values
        # for i in range(len(lst)):
        #     obj = UndergroundLineType()
        #     set_object_attributes(obj, hdr, vals[i, :])
        #     circuit.underground_cable_types.append(obj)
        #     branch_types[str(obj)] = obj
    else:
        circuit.logger.append('No underground_cable_types in the file!')

    # Add the sequence line types ##################################################################################
    if 'sequence_line_types' in data.keys():
        lst = data['sequence_line_types']
        hdr = lst.columns.values
        vals = lst.values
        for i in range(len(lst)):
            obj = SequenceLineType()
            set_object_attributes(obj, hdr, vals[i, :])
            circuit.add_sequence_line(obj)
            branch_types[str(obj)] = obj
    else:
        circuit.logger.append('No sequence_line_types in the file!')

    # Add the transformer types ####################################################################################
    if 'transformer_types' in data.keys():
        lst = data['transformer_types']
        hdr = lst.columns.values
        vals = lst.values
        for i in range(len(lst)):
            obj = TransformerType()
            set_object_attributes(obj, hdr, vals[i, :])
            circuit.add_transformer_type(obj)
            branch_types[str(obj)] = obj
    else:
        circuit.logger.append('No transformer_types in the file!')

    # Add the branches #############################################################################################
    if 'branch' in data.keys():
        lst = data['branch']

        # fix the old 'is_transformer' property
        if 'is_transformer' in lst.columns.values:
            lst['is_transformer'] = lst['is_transformer'].map({
                True: 'transformer',
                False: 'line'
            })
            lst.rename(columns={'is_transformer': 'branch_type'}, inplace=True)

        bus_from = lst['bus_from'].values
        bus_to = lst['bus_to'].values
        hdr = lst.columns.values
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus_from'))
        hdr = np.delete(hdr, np.argwhere(hdr == 'bus_to'))
        vals = lst[hdr].values
        for i in range(len(lst)):
            try:
                obj = Branch(bus_from=bus_dict[str(bus_from[i])],
                             bus_to=bus_dict[str(bus_to[i])])
            except KeyError as ex:
                raise Exception(
                    str(i) + ': Branch bus is not in the buses list.\n' +
                    str(ex))

            set_object_attributes(obj, hdr, vals[i, :])

            # correct the branch template object
            template_name = str(obj.template)
            if template_name in branch_types.keys():
                obj.template = branch_types[template_name]
                print(template_name, 'updated!')

            # set the branch
            circuit.add_branch(obj)
            obj.ensure_profiles_exist(circuit.time_profile)

    else:
        circuit.logger.append('No branches in the file!')

    # Other actions ################################################################################################
    circuit.logger += circuit.apply_all_branch_types()
示例#19
0
def interpret_data_v1(circuit: MultiCircuit, data) -> MultiCircuit:
    """
    Pass the loaded table-like data to the  structures
    :param circuit:
    :param data: Data dictionary
    :return:
    """

    circuit.clear()

    # time profile
    if 'master_time' in data.keys():
        master_time_array = data['master_time']
    else:
        master_time_array = None

    import GridCal.Engine.IO.matpower_bus_definitions as e
    # Buses
    table = data['bus']

    n = table.shape[0]

    # load profiles
    if 'Lprof' in data.keys():
        Pprof = data['Lprof']
        Qprof = data['LprofQ']
        are_load_prfiles = True
        print('There are load profiles')
    else:
        are_load_prfiles = False

    if 'bus_names' in data.keys():
        names = data['bus_names']
    else:
        names = ['bus ' + str(i+1) for i in range(n)]

    # Buses
    bus_idx_dict = dict()
    for i in range(n):
        # Create bus
        bus = Bus(name=names[i],
                  vnom=table[i, e.BASE_KV],
                  vmax=table[i, e.VMAX],
                  vmin=table[i, e.VMIN])

        # store the given bus index in relation to its real index in the table for later
        bus_idx_dict[table[i, e.BUS_I]] = i

        # determine if the bus is set as slack manually
        tpe = table[i, e.BUS_TYPE]
        if tpe == e.REF:
            bus.is_slack = True
        else:
            bus.is_slack = False

        # Add the load
        if table[i, e.PD] != 0 or table[i, e.QD] != 0:
            load = Load(P=table[i, e.PD], Q=table[i, e.QD])
            load.bus = bus
            bus.loads.append(load)

        # Add the shunt
        if table[i, e.GS] != 0 or table[i, e.BS] != 0:
            shunt = Shunt(G=table[i, e.GS], B=table[i, e.BS])
            shunt.bus = bus
            bus.shunts.append(shunt)

        # Add the bus to the circuit buses
        circuit.add_bus(bus)

    import GridCal.Engine.IO.matpower_gen_definitions as e
    # Generators
    table = data['gen']
    n = len(table)
    # load profiles
    if 'Gprof' in data.keys():
        Gprof = data['Gprof']
        are_gen_prfiles = True
        print('There are gen profiles')
    else:
        are_gen_prfiles = False

    if 'gen_names' in data.keys():
        names = data['gen_names']
    else:
        names = ['gen ' + str(i) for i in range(n)]
    for i in range(len(table)):
        bus_idx = bus_idx_dict[int(table[i, e.GEN_BUS])]
        gen = Generator(name=names[i],
                        active_power=table[i, e.PG],
                        voltage_module=table[i, e.VG],
                        Qmax=table[i, e.QMAX],
                        Qmin=table[i, e.QMIN])

        # Add the generator to the bus
        gen.bus = circuit.buses[bus_idx]
        circuit.buses[bus_idx].controlled_generators.append(gen)

    import GridCal.Engine.IO.matpower_branch_definitions as e
    # Branches
    table = data['branch']
    n = len(table)
    if 'branch_names' in data.keys():
        names = data['branch_names']
    else:
        names = ['branch ' + str(i) for i in range(n)]
    for i in range(len(table)):
        f = circuit.buses[bus_idx_dict[int(table[i, e.F_BUS])]]
        t = circuit.buses[bus_idx_dict[int(table[i, e.T_BUS])]]

        if table.shape[1] == 37:  # FUBM model

            matpower_mode = table[i, e.CONV_A]

            if matpower_mode > 0:  # it is a converter

                # this is by design of the matpower FUBM model, if it is a converter,
                # the DC bus is always the from bus
                f.is_dc = True

                # determine the converter control mode
                Pset = table[i, e.PF]
                Vac_set = table[i, e.VT_SET]
                Vdc_set = table[i, e.VF_SET]
                Qset = table[i, e.QF]
                m = table[i, e.TAP] if table[i, e.TAP] > 0 else 1.0

                if matpower_mode == 1:

                    if Pset != 0.0:
                        control_mode = ConverterControlType.type_1_pf
                    elif Qset != 0.0:
                        control_mode = ConverterControlType.type_1_qf
                    elif Vac_set != 0.0:
                        control_mode = ConverterControlType.type_1_vac
                    else:
                        control_mode = ConverterControlType.type_1_free

                elif matpower_mode == 2:

                    if Pset == 0.0:
                        control_mode = ConverterControlType.type_2_vdc
                    else:
                        control_mode = ConverterControlType.type_2_vdc_pf

                elif matpower_mode == 3:
                    control_mode = ConverterControlType.type_3

                elif matpower_mode == 4:
                    control_mode = ConverterControlType.type_4
                else:
                    control_mode = ConverterControlType.type_1_free

                branch = VSC(bus_from=f,
                             bus_to=t,
                             name='VSC' + str(len(circuit.vsc_converters) + 1),
                             active=bool(table[i, e.BR_STATUS]),
                             r1=table[i, e.BR_R],
                             x1=table[i, e.BR_X],
                             m=m,
                             m_max=table[i, e.MA_MAX],
                             m_min=table[i, e.MA_MIN],
                             theta=table[i, e.SHIFT],
                             theta_max=np.deg2rad(table[i, e.ANGMAX]),
                             theta_min=np.deg2rad(table[i, e.ANGMIN]),
                             G0=table[i, e.GSW],
                             Beq=table[i, e.BEQ],
                             Beq_max=table[i, e.BEQ_MAX],
                             Beq_min=table[i, e.BEQ_MIN],
                             rate=table[i, e.RATE_A],
                             kdp=table[i, e.KDP],
                             control_mode=control_mode,
                             Pset=Pset,
                             Qset=Qset,
                             Vac_set=Vac_set,
                             Vdc_set=Vdc_set,
                             alpha1=table[i, e.ALPHA1],
                             alpha2=table[i, e.ALPHA2],
                             alpha3=table[i, e.ALPHA3])
                circuit.add_vsc(branch)

            else:

                if f.Vnom != t.Vnom or (table[i, e.TAP] != 1.0 and table[i, e.TAP] != 0) or table[i, e.SHIFT] != 0.0:

                    branch = Transformer2W(bus_from=f,
                                           bus_to=t,
                                           name=names[i],
                                           r=table[i, e.BR_R],
                                           x=table[i, e.BR_X],
                                           g=0,
                                           b=table[i, e.BR_B],
                                           rate=table[i, e.RATE_A],
                                           tap=table[i, e.TAP],
                                           shift_angle=table[i, e.SHIFT],
                                           active=bool(table[i, e.BR_STATUS]))
                    circuit.add_transformer2w(branch)

                else:
                    branch = Line(bus_from=f,
                                  bus_to=t,
                                  name=names[i],
                                  r=table[i, e.BR_R],
                                  x=table[i, e.BR_X],
                                  b=table[i, e.BR_B],
                                  rate=table[i, e.RATE_A],
                                  active=bool(table[i, e.BR_STATUS]))
                    circuit.add_line(branch)

        else:

            if f.Vnom != t.Vnom or (table[i, e.TAP] != 1.0 and table[i, e.TAP] != 0) or table[i, e.SHIFT] != 0.0:

                branch = Transformer2W(bus_from=f,
                                       bus_to=t,
                                       name=names[i],
                                       r=table[i, e.BR_R],
                                       x=table[i, e.BR_X],
                                       g=0,
                                       b=table[i, e.BR_B],
                                       rate=table[i, e.RATE_A],
                                       tap=table[i, e.TAP],
                                       shift_angle=table[i, e.SHIFT],
                                       active=bool(table[i, e.BR_STATUS]))
                circuit.add_transformer2w(branch)

            else:
                branch = Line(bus_from=f,
                              bus_to=t,
                              name=names[i],
                              r=table[i, e.BR_R],
                              x=table[i, e.BR_X],
                              b=table[i, e.BR_B],
                              rate=table[i, e.RATE_A],
                              active=bool(table[i, e.BR_STATUS]))
                circuit.add_line(branch)

    # convert normal lines into DC-lines if needed
    for line in circuit.lines:

        if line.bus_to.is_dc and line.bus_from.is_dc:
            dc_line = DcLine(bus_from=line.bus_from,
                             bus_to=line.bus_to,
                             name=line.name,
                             active=line.active,
                             rate=line.rate,
                             r=line.R,
                             active_prof=line.active_prof,
                             rate_prof=line.rate_prof)

            # add device to the circuit
            circuit.add_dc_line(dc_line)

            # delete the line from the circuit
            circuit.delete_line(line)

    # add the profiles
    if master_time_array is not None:
        circuit.format_profiles(master_time_array)

    return circuit
示例#20
0
def data_to_grid_object(data, pos_dict, codification="utf-8") -> MultiCircuit:
    """
    Turns the read data dictionary into a GridCal MultiCircuit object
    Args:
        data: Dictionary of data read from a DGS file
        pos_dict: Dictionary of objects and their positions read from a DGS file
    Returns: GridCal MultiCircuit object
    """
    ###############################################################################
    # Refactor data into classes
    ###############################################################################

    # store tables for easy reference

    '''
    ###############################################################################
    *  Line
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypLne,TypTow,TypGeo,TypCabsys
    *  chr_name: Characteristic Name
    *  dline: Parameters: Length of Line in km
    *  fline: Parameters: Derating Factor
    *  outserv: Out of Service
    *  pStoch: Failures: Element model in StoTyplne
    '''
    if "ElmLne" in data.keys():
        lines = data["ElmLne"]
    else:
        lines = np.zeros((0, 20))

    '''
    ###############################################################################
    *  Line Type
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  chr_name: Characteristic Name
    *  Ithr: Rated Short-Time (1s) Current (Conductor) in kA
    *  aohl_: Cable / OHL
    *  cline: Parameters per Length 1,2-Sequence: Capacitance C' in uF/km
    *  cline0: Parameters per Length Zero Sequence: Capacitance C0' in uF/km
    *  nlnph: Phases:1:2:3
    *  nneutral: Number of Neutrals:0:1
    *  rline: Parameters per Length 1,2-Sequence: AC-Resistance R'(20°C) in Ohm/km
    *  rline0: Parameters per Length Zero Sequence: AC-Resistance R0' in Ohm/km
    *  rtemp: Max. End Temperature in degC
    *  sline: Rated Current in kA
    *  uline: Rated Voltage in kV
    *  xline: Parameters per Length 1,2-Sequence: Reactance X' in Ohm/km
    *  xline0: Parameters per Length Zero Sequence: Reactance X0' in Ohm/km
    '''
    if "TypLne" in data.keys():
        lines_types = data["TypLne"]
    else:
        lines_types = np.zeros((0, 20))

    '''
    ###############################################################################
    *  2-Winding Transformer
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypTr2
    *  chr_name: Characteristic Name
    *  sernum: Serial Number
    *  constr: Year of Construction
    *  cgnd_h: Internal Grounding Impedance, HV Side: Star Point:Connected:Not connected
    *  cgnd_l: Internal Grounding Impedance, LV Side: Star Point:Connected:Not connected
    *  i_auto: Auto Transformer
    *  nntap: Tap Changer 1: Tap Position
    *  ntrcn: Controller, Tap Changer 1: Automatic Tap Changing
    *  outserv: Out of Service
    *  ratfac: Rating Factor
    '''
    if "ElmTr2" in data.keys():
        transformers = data["ElmTr2"]
    else:
        transformers = np.zeros((0, 20))

    '''
    ###############################################################################
    *  2-Winding Transformer Type
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  chr_name: Characteristic Name
    *  curmg: Magnetising Impedance: No Load Current in %
    *  dutap: Tap Changer 1: Additional Voltage per Tap in %
    *  frnom: Nominal Frequency in Hz
    *  manuf: Manufacturer
    *  nntap0: Tap Changer 1: Neutral Position
    *  nt2ag: Vector Group: Phase Shift in *30deg
    *  ntpmn: Tap Changer 1: Minimum Position
    *  ntpmx: Tap Changer 1: Maximum Position
    *  pcutr: Positive Sequence Impedance: Copper Losses in kW
    *  pfe: Magnetising Impedance: No Load Losses in kW
    *  phitr: Tap Changer 1: Phase of du in deg
    *  strn: Rated Power in MVA
    *  tap_side: Tap Changer 1: at Side:HV:LV
    *  tr2cn_h: Vector Group: HV-Side:Y :YN:Z :ZN:D
    *  tr2cn_l: Vector Group: LV-Side:Y :YN:Z :ZN:D
    *  uk0tr: Zero Sequence Impedance: Short-Circuit Voltage uk0 in %
    *  uktr: Positive Sequence Impedance: Short-Circuit Voltage uk in %
    *  ur0tr: Zero Sequence Impedance: SHC-Voltage (Re(uk0)) uk0r in %
    *  utrn_h: Rated Voltage: HV-Side in kV
    *  utrn_l: Rated Voltage: LV-Side in kV
    *  zx0hl_n: Zero Sequence Magnetising Impedance: Mag. Impedance/uk0
    '''
    if "TypTr2" in data.keys():
        transformers_types = data["TypTr2"]
    else:
        transformers_types = np.zeros((0, 20))

    '''
    ###############################################################################
    *  Terminal
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypBar
    *  chr_name: Characteristic Name
    *  iUsage: Usage:Busbar:Junction Node:Internal Node
    *  outserv: Out of Service
    *  phtech: Phase Technology:ABC:ABC-N:BI:BI-N:2PH:2PH-N:1PH:1PH-N:N
    *  uknom: Nominal Voltage: Line-Line in kV
    '''
    if "ElmTerm" in data.keys():
        buses = data["ElmTerm"]
    else:
        buses = np.zeros((0, 20))

    '''
    ###############################################################################
    *  Cubicle
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  chr_name: Characteristic Name
    *  obj_bus: Bus Index
    *  obj_id: Connected with in Elm*
    '''
    if "StaCubic" in data.keys():
        cubicles = data["StaCubic"]
    else:
        cubicles = np.zeros((0, 20))

    '''
    ###############################################################################
    *  General Load
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypLod,TypLodind
    *  chr_name: Characteristic Name
    *  outserv: Out of Service
    *  plini: Operating Point: Active Power in MW
    *  qlini: Operating Point: Reactive Power in Mvar
    *  scale0: Operating Point: Scaling Factor
    '''
    if "ElmLod" in data.keys():
        loads = data["ElmLod"]
    else:
        loads = np.zeros((0, 20))

    '''
    ###############################################################################
    *  External Grid
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  chr_name: Characteristic Name
    *  bustp: Bus Type:PQ:PV:SL
    *  cgnd: Internal Grounding Impedance: Star Point:Connected:Not connected
    *  iintgnd: Neutral Conductor: N-Connection:None:At terminal (ABC-N):Separate terminal
    *  ikssmin: Min. Values: Short-Circuit Current Ik''min in kA
    *  r0tx0: Max. Values Impedance Ratio: R0/X0 max.
    *  r0tx0min: Min. Values Impedance Ratio: R0/X0 min.
    *  rntxn: Max. Values: R/X Ratio (max.)
    *  rntxnmin: Min. Values: R/X Ratio (min.)
    *  snss: Max. Values: Short-Circuit Power Sk''max in MVA
    *  snssmin: Min. Values: Short-Circuit Power Sk''min in MVA
    '''
    if "ElmXnet" in data.keys():
        external = data["ElmXnet"]
    else:
        external = np.zeros((0, 20))

    '''
    ###############################################################################
    *  Grid
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  frnom: Nominal Frequency in Hz
    '''
    if "ElmNet" in data.keys():
        grid = data["ElmNet"]
    else:
        grid = np.zeros((0, 20))

    '''
    ###############################################################################
    '''
    if "ElmGenstat" in data.keys():
        static_generators = data["ElmGenstat"]
    else:
        static_generators = np.zeros((0, 20))

    '''
    ###############################################################################
    *  Synchronous Machine
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypSym
    *  chr_name: Characteristic Name
    *  i_mot: Generator/Motor
    *  iv_mode: Local Controller
    *  ngnum: Number of: parallel Machines
    *  outserv: Out of Service
    *  pgini: Dispatch: Active Power in MW
    *  q_max: Reactive Power Operational Limits: Max. in p.u.
    *  q_min: Reactive Power Operational Limits: Min. in p.u.
    *  qgini: Dispatch: Reactive Power in Mvar
    *  usetp: Dispatch: Voltage in p.u.
    '''
    if "ElmSym" in data.keys():
        synchronous_machine = data["ElmSym"]
    else:
        synchronous_machine = np.zeros((0, 20))

    '''
    ###############################################################################
    *  Synchronous Machine Type
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  cosn: Power Factor
    *  rstr: Stator Resistance: rstr in p.u.
    *  satur: For single fed short-circuit: Machine Type IEC909/IEC60909
    *  sgn: Nominal Apparent Power in MVA
    *  ugn: Nominal Voltage in kV
    *  xd: Synchronous Reactances: xd in p.u.
    *  xdsat: For single fed short-circuit: Reciprocal of short-circuit ratio (xdsat) in p.u.
    *  xdsss: Subtransient Reactance: saturated value xd''sat in p.u.
    *  xq: Synchronous Reactances: xq in p.u.
    '''
    if "TypSym" in data.keys():
        synchronous_machine_type = data["TypSym"]
    else:
        synchronous_machine_type = np.zeros((0, 20))

    '''
    ###############################################################################
    *  Asynchronous Machine
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypAsm*,TypAsmo*,TypAsm1*
    *  chr_name: Characteristic Name
    *  i_mot: Generator/Motor
    *  ngnum: Number of: parallel Machines
    *  outserv: Out of Service
    *  pgini: Dispatch: Active Power in MW
    '''
    if "ElmAsm" in data.keys():
        asynchronous_machine = data["ElmAsm"]
    else:
        asynchronous_machine = np.zeros((0, 20))

    '''
    ###############################################################################
    *  Synchronous Machine Type
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  i_mode: Input Mode
    *  aiazn: Consider Transient Parameter: Locked Rotor Current (Ilr/In) in p.u.
    *  amazn: Locked Rotor Torque in p.u.
    *  amkzn: Torque at Stalling Point in p.u.
    *  anend: Nominal Speed in rpm
    *  cosn: Rated Power Factor
    *  effic: Efficiency at nominal Operation in %
    *  frequ: Nominal Frequency in Hz
    *  i_cage: Rotor
    *  nppol: No of Pole Pairs
    *  pgn: Power Rating: Rated Mechanical Power in kW
    *  ugn: Rated Voltage in kV
    *  xmrtr: Rotor Leakage Reac. Xrm in p.u.
    *  xstr: Stator Reactance Xs in p.u.
    '''
    if "TypAsmo" in data.keys():
        asynchronous_machine_type = data["TypAsmo"]
    else:
        asynchronous_machine_type = np.zeros((0, 20))

    '''
    ###############################################################################
    *  Shunt/Filter
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  chr_name: Characteristic Name
    *  ctech: Technology
    *  fres: Design Parameter (per Step): Resonance Frequency in Hz
    *  greaf0: Design Parameter (per Step): Quality Factor (at fr)
    *  iswitch: Controller: Switchable
    *  ncapa: Controller: Act.No. of Step
    *  ncapx: Controller: Max. No. of Steps
    *  outserv: Out of Service
    *  qtotn: Design Parameter (per Step): Rated Reactive Power, L-C in Mvar
    *  shtype: Shunt Type
    *  ushnm: Nominal Voltage in kV
    '''
    if "ElmShnt" in data.keys():
        shunts = data["ElmShnt"]
    else:
        shunts = np.zeros((0, 20))

    '''
    ###############################################################################
    *  Breaker/Switch
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypSwitch
    *  chr_name: Characteristic Name
    *  aUsage: Switch Type
    *  nneutral: No. of Neutrals:0:1
    *  nphase: No. of Phases:1:2:3
    *  on_off: Closed
    '''
    if "ElmCoup" in data.keys():
        switches = data["ElmCoup"]
    else:
        switches = np.zeros((0, 20))

        ###############################################################################
        # Post process the data
        ###############################################################################

    # put the tables that connect to a terminal in a list
    classes = [lines, transformers, loads, external, static_generators, shunts,
               synchronous_machine, asynchronous_machine]

    # construct the terminals dictionary
    '''
    $$StaCubic;ID(a:40);loc_name(a:40);fold_id(p);chr_name(a:20);obj_bus(i);obj_id(p)
    ********************************************************************************
    *  Cubicle
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  chr_name: Characteristic Name
    *  obj_bus: Bus Index
    *  obj_id: Connected with in Elm*
    ********************************************************************************
    '''
    terminals_dict = dict()  # dictionary to store the terminals ID associated with an object ID
    cub_obj_idx = cubicles['obj_id'].values
    cub_term_idx = cubicles['fold_id'].values

    # for i, elm_id in enumerate(cub_obj_idx):
    #     bus_idx = cub_term_idx[i]
    #     terminals_dict[elm_id] = bus_idx

    ID_idx = 0
    for cla in classes:
        if cla.__len__() > 0:
            for ID in cla['ID'].values:
                idx = np.where(cubicles == ID)[0]
                terminals_dict[ID] = cub_term_idx[idx]

    ###############################################################################
    # Generate GridCal data
    ###############################################################################

    # general values
    baseMVA = 100
    frequency = grid['frnom'][0]
    w = 2.0 * math.pi * frequency

    circuit = MultiCircuit()

    ####################################################################################################################
    # Terminals (nodes)
    ####################################################################################################################
    '''
    ********************************************************************************
    *  Terminal
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypBar
    *  iUsage: Usage:Busbar:Junction Node:Internal Node
    *  uknom: Nominal Voltage: Line-Line in kV
    *  chr_name: Characteristic Name
    *  outserv: Out of Service
    ********************************************************************************
    '''
    # print('Parsing terminals')
    buses_dict = dict()
    for i in range(len(buses)):
        ID = buses['ID'][i]
        x, y = pos_dict[ID]
        buses_dict[ID] = i
        bus_name = buses['loc_name'][i].decode(codification)   # BUS_Name
        vnom = buses['uknom'][i]
        bus = Bus(name=bus_name, vnom=vnom, vmin=0.9, vmax=1.1, xpos=x, ypos=-y, active=True)
        circuit.add_bus(bus)

    ####################################################################################################################
    # External grids (slacks)
    ####################################################################################################################
    '''
    ###############################################################################
    ********************************************************************************
    *  External Grid
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  outserv: Out of Service
    *  snss: Max. Values: Short-Circuit Power Sk''max in MVA
    *  rntxn: Max. Values: R/X Ratio (max.)
    *  z2tz1: Max. Values Impedance Ratio: Z2/Z1 max.
    *  snssmin: Min. Values: Short-Circuit Power Sk''min in MVA
    *  rntxnmin: Min. Values: R/X Ratio (min.)
    *  z2tz1min: Min. Values Impedance Ratio: Z2/Z1 min.
    *  chr_name: Characteristic Name
    *  bustp: Bus Type:PQ:PV:SL
    *  pgini: Operation Point: Active Power in MW
    *  qgini: Operation Point: Reactive Power in Mvar
    *  phiini: Operation Point: Angle in deg
    *  usetp: Operation Point: Voltage Setpoint in p.u.
    ********************************************************************************
    '''

    for i in range(len(external)):
        ID = external['ID'][i]

        if 'phiini' in external.columns.values:
            va = external['phiini'][i]
            vm = external['usetp'][i]
        else:
            va = 0
            vm = 1

        buses = terminals_dict[ID]  # array with the ID of the connection Buses
        bus1 = buses_dict[buses[0]]  # index of the bus

        bus_obj = circuit.buses[bus1]

        # apply the slack values to the buses structure if the element is marked as slack
        if external['bustp'].values[i] == b'SL':
            # create the slack entry on buses
            bus_obj.is_slack = True

            # BUSES[bus1, bd.BUS_TYPE] = 3
            # BUSES[bus1, bd.VA] = va
            # BUSES[bus1, bd.VM] = vm
            #
            # # create the slack entry on generators (add the slack generator)
            # gen_ = gen_line.copy()
            # gen_[gd.GEN_BUS] = bus1
            # gen_[gd.MBASE] = baseMVA
            # gen_[gd.VG] = vm
            # gen_[gd.GEN_STATUS] = 1
            # gen_[gd.PG] += external['pgini'].values[i]
            #
            # GEN.append(gen_)
            # GEN_NAMES.append(external['loc_name'][i])

        elif external['bustp'].values[i] == b'PV':

            if 'pgini' in external.columns.values:
                p = external['pgini'].values[i]
            else:
                p = 0

            # add a generator to the bus
            gen = Generator(name=external['loc_name'][i].decode(codification),
                            active_power=p,
                            voltage_module=vm, Qmin=-9999, Qmax=9999, Snom=9999,
                            power_prof=None, vset_prof=None)
            circuit.add_generator(bus_obj, gen)

            # # mark the bus as pv
            # BUSES[bus1, bd.BUS_TYPE] = 2
            # BUSES[bus1, bd.VA] = 0.0
            # BUSES[bus1, bd.VM] = vm
            # # add the PV entry on generators
            # gen_ = gen_line.copy()
            # gen_[gd.GEN_BUS] = bus1
            # gen_[gd.MBASE] = baseMVA
            # gen_[gd.VG] = vm
            # gen_[gd.GEN_STATUS] = 1
            # gen_[gd.PG] += external['pgini'].values[i]
            #
            # GEN.append(gen_)
            # GEN_NAMES.append(external['loc_name'][i])

        elif external['bustp'].values[i] == b'PQ':
            # Add a load to the bus
            load = Load(name=external['loc_name'][i].decode(codification),
                        P=external['pgini'].values[i],
                        Q=external['qgini'].values[i])
            circuit.add_load(bus_obj, load)

            # BUSES[bus1, bd.BUS_TYPE] = 1
            # BUSES[bus1, bd.VA] = va
            # BUSES[bus1, bd.VM] = vm
            # BUSES[bus1, bd.PD] += external['pgini'].values[i]
            # BUSES[bus1, bd.QD] += external['qgini'].values[i]

    ####################################################################################################################
    # Lines (branches)
    ####################################################################################################################
    # print('Parsing lines')

    if lines_types.__len__() > 0:
        lines_ID = lines['ID'].values
        lines_type_id = lines['typ_id'].values
        line_types_ID = lines_types['ID'].values
        lines_lenght = lines['dline'].values

        if 'outserv' in lines.keys():
            lines_enables = lines['outserv']
        else:
            lines_enables = np.ones(len(lines_ID))

        lines_R = lines_types['rline'].values
        lines_L = lines_types['xline'].values
        lines_C = lines_types['cline'].values
        lines_rate = lines_types['sline'].values
        lines_voltage = lines_types['uline'].values
        for i in range(len(lines)):
            # line_ = branch_line.copy()

            ID = lines_ID[i]
            ID_Type = lines_type_id[i]
            type_idx = np.where(line_types_ID == ID_Type)[0][0]

            buses = terminals_dict[ID]  # array with the ID of the connection Buses
            bus1 = buses_dict[buses[0]]
            bus2 = buses_dict[buses[1]]

            bus_from = circuit.buses[bus1]
            bus_to = circuit.buses[bus2]

            status = lines_enables[i]

            # impedances
            lenght = np.double(lines_lenght[i])
            R = np.double(lines_R[type_idx]) * lenght  # Ohm
            L = np.double(lines_L[type_idx]) * lenght  # Ohm
            C = np.double(lines_C[type_idx]) * lenght * w * 1e-6  # S (siemens)

            # pass impedance to per unit
            vbase = np.double(lines_voltage[type_idx])  # kV
            zbase = vbase**2 / baseMVA  # Ohm
            ybase = 1.0 / zbase  # S
            r = R / zbase  # pu
            l = L / zbase  # pu
            b = C / ybase  # pu

            # rated power
            Irated = np.double(lines_rate[type_idx])  # kA
            Smax = Irated * vbase  # MVA

            line = Branch(bus_from=bus_from, bus_to=bus_to,
                          name=lines['loc_name'][i].decode(codification),
                          r=r,
                          x=l,
                          g=1e-20,
                          b=b,
                          rate=Smax,
                          tap=1,
                          shift_angle=0,
                          active=status, mttf=0, mttr=0)

            circuit.add_branch(line)

            # # put all in the correct column
            # line_[brd.F_BUS] = bus1
            # line_[brd.T_BUS] = bus2
            # line_[brd.BR_R] = r
            # line_[brd.BR_X] = l
            # line_[brd.BR_B] = c
            # line_[brd.RATE_A] = Smax
            # line_[brd.BR_STATUS] = status
            # BRANCHES.append(line_)
            #
            # name_ = lines['loc_name'][i]  # line_Name
            # BRANCH_NAMES.append(name_)
            #
            # # add edge to graph
            # g.add_edge(bus1, bus2)
    else:
        warn('Line types are empty')

    ####################################################################################################################
    # Transformers (Branches)
    ####################################################################################################################
    # print('Parsing transformers')

    '''
    ********************************************************************************
    *  2-Winding Transformer
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypTr2
    *  outserv: Out of Service
    *  nntap: Tap Changer 1: Tap Position
    *  sernum: Serial Number
    *  constr: Year of Construction
    *  chr_name: Characteristic Name
    ********************************************************************************
    '''

    if len(transformers_types) > 0:
        '''
        ********************************************************************************
        *  2-Winding Transformer Type
        *
        *  ID: Unique identifier for DGS file
        *  loc_name: Name
        *  fold_id: In Folder
        *  strn: Rated Power in MVA
        *  frnom: Nominal Frequency in Hz
        *  utrn_h: Rated Voltage: HV-Side in kV
        *  utrn_l: Rated Voltage: LV-Side in kV
        *  uktr: Positive Sequence Impedance: Short-Circuit Voltage uk in %
        *  pcutr: Positive Sequence Impedance: Copper Losses in kW
        *  uk0tr: Zero Sequence Impedance: Short-Circuit Voltage uk0 in %
        *  ur0tr: Zero Sequence Impedance: SHC-Voltage (Re(uk0)) uk0r in %
        *  tr2cn_h: Vector Group: HV-Side:Y :YN:Z :ZN:D
        *  tr2cn_l: Vector Group: LV-Side:Y :YN:Z :ZN:D
        *  nt2ag: Vector Group: Phase Shift in *30deg
        *  curmg: Magnetizing Impedance: No Load Current in %
        *  pfe: Magnetizing Impedance: No Load Losses in kW
        *  zx0hl_n: Zero Sequence Magnetizing Impedance: Mag. Impedance/uk0
        *  tap_side: Tap Changer 1: at Side:HV:LV
        *  dutap: Tap Changer 1: Additional Voltage per Tap in %
        *  phitr: Tap Changer 1: Phase of du in deg
        *  nntap0: Tap Changer 1: Neutral Position
        *  ntpmn: Tap Changer 1: Minimum Position
        *  ntpmx: Tap Changer 1: Maximum Position
        *  manuf: Manufacturer
        *  chr_name: Characteristic Name
        ********************************************************************************
        '''
        type_ID = transformers_types['ID'].values
        HV_nominal_voltage = transformers_types['utrn_h'].values
        LV_nominal_voltage = transformers_types['utrn_l'].values
        Nominal_power = transformers_types['strn'].values
        Copper_losses = transformers_types['pcutr'].values
        Iron_losses = transformers_types['pfe'].values
        No_load_current = transformers_types['curmg'].values
        Short_circuit_voltage = transformers_types['uktr'].values
        # GR_hv1 = transformers_types['ID']
        # GX_hv1 = transformers_types['ID']
        for i in range(len(transformers)):

            # line_ = branch_line.copy()

            ID = transformers['ID'][i]
            ID_Type = transformers['typ_id'][i]

            if ID_Type in type_ID:
                type_idx = np.where(type_ID == ID_Type)[0][0]
                buses = terminals_dict[ID]  # array with the ID of the connection Buses
                bus1 = buses_dict[buses[0]]
                bus2 = buses_dict[buses[1]]

                bus_from = circuit.buses[bus1]
                bus_to = circuit.buses[bus2]

                Smax = Nominal_power[type_idx]

                # Uhv, Ulv, Sn, Pcu, Pfe, I0, Usc
                tpe = TransformerType(hv_nominal_voltage=HV_nominal_voltage[type_idx],
                                      lv_nominal_voltage=LV_nominal_voltage[type_idx],
                                      nominal_power=Smax,
                                      copper_losses=Copper_losses[type_idx],
                                      iron_losses=Iron_losses[type_idx],
                                      no_load_current=No_load_current[type_idx],
                                      short_circuit_voltage=Short_circuit_voltage[type_idx],
                                      gr_hv1=0.5,
                                      gx_hv1=0.5)

                Zs, Zsh = tpe.get_impedances()

                if Zsh != 0:
                    Ysh = 1.0 / Zsh
                else:
                    Ysh = 0j

                status = 1 - transformers['outserv'][i]

                trafo = Branch(bus_from=bus_from,
                               bus_to=bus_to,
                               name=transformers['loc_name'][i].decode(codification),
                               r=Zs.real,
                               x=Zs.imag,
                               g=Ysh.real,
                               b=Ysh.imag,
                               rate=Smax,
                               tap=1.0,
                               shift_angle=0.0,
                               active=status,
                               mttf=0,
                               mttr=0,
                               branch_type=BranchType.Transformer)

                circuit.add_branch(trafo)

            else:
                warn('Transformer type not found!')
    else:
        warn('Transformer types are empty')

    ####################################################################################################################
    # Loads (nodes)
    ####################################################################################################################
    '''
    ********************************************************************************
    *  General Load
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypLod,TypLodind
    *  chr_name: Characteristic Name
    *  plini: Operating Point: Active Power in MW
    *  qlini: Operating Point: Reactive Power in Mvar
    *  scale0: Operating Point: Scaling Factor
    ********************************************************************************
    '''
    # print('Parsing Loads')
    if len(loads) > 0:
        loads_ID = loads['ID']
        loads_P = loads['plini']
        loads_Q = loads['qlini']
        scale = loads['scale0']
        for i in range(len(loads)):
            ID = loads_ID[i]
            bus_idx = buses_dict[(terminals_dict[ID][0])]
            bus_obj = circuit.buses[bus_idx]
            p = loads_P[i] * scale[i]  # in MW
            q = loads_Q[i] * scale[i]  # in MVA

            load = Load(name=loads['loc_name'][i].decode(codification),
                        P=p,
                        Q=q)

            circuit.add_load(bus_obj, load)

            # BUSES[bus_idx, 2] += p
            # BUSES[bus_idx, 3] += q
    else:
        warn('There are no loads')

    ####################################################################################################################
    # Shunts
    ####################################################################################################################
    '''
    ********************************************************************************
    *  Shunt/Filter
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  chr_name: Characteristic Name
    *  shtype: Shunt Type
    *  ushnm: Nominal Voltage in kV
    *  qcapn: Design Parameter (per Step): Rated Reactive Power, C in Mvar
    *  ncapx: Controller: Max. No. of Steps
    *  ncapa: Controller: Act.No. of Step
    *  outserv: Out of Service
    ********************************************************************************
    '''
    for i in range(len(shunts)):
        ID = shunts['ID'][i]
        buses = terminals_dict[ID]  # array with the ID of the connection Buses
        bus1 = buses_dict[buses[0]]
        bus_obj = circuit.buses[bus1]
        name = shunts['loc_name'][i].decode(codification)

        if 'qcapn' in shunts.columns.values:
            b = shunts['ushnm'][i] / shunts['qcapn'][i]
        elif 'qtotn' in shunts.columns.values:
            b = shunts['ushnm'][i] / shunts['qtotn'][i]
        else:
            b = 1e-20

        shunt = Shunt(name=name, B=b)
        circuit.add_shunt(bus_obj, shunt)

    ####################################################################################################################
    # Static generators (Gen)
    ####################################################################################################################
    '''
    ********************************************************************************
    *  Static Generator
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  bus1: Terminal in StaCubic
    *  outserv: Out of Service
    *  sgn: Ratings: Nominal Apparent Power in MVA
    *  cosn: Ratings: Power Factor
    *  ngnum: Number of: parallel Machines
    *  pgini: Dispatch: Active Power in MW
    *  qgini: Dispatch: Reactive Power in Mvar
    *  av_mode: Local Controller
    *  ip_ctrl: Reference Machine
    ********************************************************************************
    '''
    for i in range(len(static_generators)):
        ID = static_generators['ID'][i]
        buses = terminals_dict[ID]  # array with the ID of the connection Buses
        bus1 = buses_dict[buses[0]]
        bus_obj = circuit.buses[bus1]
        mode = static_generators['av_mode'][i]
        num_machines = static_generators['ngnum'][i]

        gen = StaticGenerator(name=static_generators['loc_name'][i].decode(codification),
                              P=static_generators['pgini'][i] * num_machines,
                              Q=static_generators['qgini'][i] * num_machines)
        circuit.add_static_generator(bus_obj, gen)

    ####################################################################################################################
    # Synchronous Machine (Gen)
    ####################################################################################################################
    '''
    ********************************************************************************
    *  Synchronous Machine
    *
    *  ID: Unique identifier for DGS file
    *  loc_name: Name
    *  fold_id: In Folder
    *  typ_id: Type in TypSym
    *  ngnum: Number of: parallel Machines
    *  i_mot: Generator/Motor
    *  chr_name: Characteristic Name
    *  outserv: Out of Service
    *  pgini: Dispatch: Active Power in MW
    *  qgini: Dispatch: Reactive Power in Mvar
    *  usetp: Dispatch: Voltage in p.u.
    *  iv_mode: Mode of Local Voltage Controller
    *  q_min: Reactive Power Operational Limits: Min. in p.u.
    *  q_max: Reactive Power Operational Limits: Max. in p.u.
    ********************************************************************************
    '''
    for i in range(len(synchronous_machine)):
        ID = synchronous_machine['ID'][i]
        buses = terminals_dict[ID]  # array with the ID of the connection Buses
        bus1 = buses_dict[buses[0]]
        bus_obj = circuit.buses[bus1]
        num_machines = synchronous_machine['ngnum'][i]

        # Get the type element
        '''
        ********************************************************************************
        *  Synchronous Machine Type
        *
        *  ID: Unique identifier for DGS file
        *  loc_name: Name
        *  fold_id: In Folder
        *  sgn: Nominal Apparent Power in MVA
        *  ugn: Nominal Voltage in kV
        *  cosn: Power Factor
        *  xd: Synchronous Reactances: xd in p.u.
        *  xq: Synchronous Reactances: xq in p.u.
        *  xdsss: Subtransient Reactance: saturated value xd''sat in p.u.
        *  rstr: Stator Resistance: rstr in p.u.
        *  xdsat: For single fed short-circuit: Reciprocal of short-circuit ratio (xdsat) in p.u.
        *  satur: For single fed short-circuit: Machine Type IEC909/IEC60909
        ********************************************************************************
        '''
        typ = synchronous_machine_type[synchronous_machine_type.ID == synchronous_machine['typ_id'][i]]

        snom = typ['sgn'].values[0]
        vnom = synchronous_machine['usetp'][i]
        name = synchronous_machine['loc_name'][i].decode(codification)
        gen = Generator(name=name,
                        active_power=synchronous_machine['pgini'][i] * num_machines,
                        voltage_module=vnom,
                        Qmin=synchronous_machine['q_min'][i] * num_machines * snom,
                        Qmax=synchronous_machine['q_max'][i] * num_machines * snom,
                        Snom=snom,
                        power_prof=None,
                        vset_prof=None)
        circuit.add_generator(bus_obj, gen)

        # if synchronous_machine['pgini'][i] != 0:
        #     # gen = StaticGenerator(name=name, power=complex(0, synchronous_machine['pgini'][i]))
        #     gen = Generator(name=name, active_power=synchronous_machine['pgini'][i])
        #     circuit.add_static_generator(bus_obj, gen)

    return circuit
def test_gridcal_regulator():
    """
    GridCal test for the new implementation of transformer voltage regulators.
    """
    test_name = "test_gridcal_regulator"
    grid = MultiCircuit(name=test_name)
    grid.Sbase = 100.0  # MVA
    grid.time_profile = None
    grid.logger = Logger()

    # Create buses
    POI = Bus(
        name="POI",
        vnom=100,  # kV
        is_slack=True)
    grid.add_bus(POI)

    B_C3 = Bus(name="B_C3", vnom=10)  # kV
    grid.add_bus(B_C3)

    B_MV_M32 = Bus(name="B_MV_M32", vnom=10)  # kV
    grid.add_bus(B_MV_M32)

    B_LV_M32 = Bus(name="B_LV_M32", vnom=0.6)  # kV
    grid.add_bus(B_LV_M32)

    # Create voltage controlled generators (or slack, a.k.a. swing)
    UT = Generator(name="Utility")
    UT.bus = POI
    grid.add_generator(POI, UT)

    # Create static generators (with fixed power factor)
    M32 = StaticGenerator(name="M32", P=4.2, Q=0.0)  # MVA (complex)
    M32.bus = B_LV_M32
    grid.add_static_generator(B_LV_M32, M32)

    # Create transformer types
    s = 100  # MVA
    z = 8  # %
    xr = 40
    SS = TransformerType(
        name="SS",
        hv_nominal_voltage=100,  # kV
        lv_nominal_voltage=10,  # kV
        nominal_power=s,  # MVA
        copper_losses=complex_impedance(z, xr).real * s * 1000.0 /
        grid.Sbase,  # kW
        iron_losses=125,  # kW
        no_load_current=0.5,  # %
        short_circuit_voltage=z)  # %
    grid.add_transformer_type(SS)

    s = 5  # MVA
    z = 6  # %
    xr = 20
    PM = TransformerType(
        name="PM",
        hv_nominal_voltage=10,  # kV
        lv_nominal_voltage=0.6,  # kV
        nominal_power=s,  # MVA
        copper_losses=complex_impedance(z, xr).real * s * 1000.0 /
        grid.Sbase,  # kW
        iron_losses=6.25,  # kW
        no_load_current=0.5,  # %
        short_circuit_voltage=z)  # %
    grid.add_transformer_type(PM)

    # Create branches
    X_C3 = Branch(bus_from=POI,
                  bus_to=B_C3,
                  name="X_C3",
                  branch_type=BranchType.Transformer,
                  template=SS,
                  bus_to_regulated=True,
                  vset=1.05)
    X_C3.tap_changer = TapChanger(taps_up=16,
                                  taps_down=16,
                                  max_reg=1.1,
                                  min_reg=0.9)
    X_C3.tap_changer.set_tap(X_C3.tap_module)
    grid.add_branch(X_C3)

    C_M32 = Branch(bus_from=B_C3,
                   bus_to=B_MV_M32,
                   name="C_M32",
                   r=7.84,
                   x=1.74)
    grid.add_branch(C_M32)

    X_M32 = Branch(bus_from=B_MV_M32,
                   bus_to=B_LV_M32,
                   name="X_M32",
                   branch_type=BranchType.Transformer,
                   template=PM)
    grid.add_branch(X_M32)

    # Apply templates (device types)
    grid.apply_all_branch_types()

    print("Buses:")
    for i, b in enumerate(grid.buses):
        print(f" - bus[{i}]: {b}")
    print()

    options = PowerFlowOptions(SolverType.NR,
                               verbose=True,
                               initialize_with_existing_solution=True,
                               multi_core=True,
                               control_q=ReactivePowerControlMode.Direct,
                               control_taps=TapsControlMode.Direct,
                               tolerance=1e-6,
                               max_iter=99)

    power_flow = PowerFlowDriver(grid, options)
    power_flow.run()

    approx_volt = [round(100 * abs(v), 1) for v in power_flow.results.voltage]
    solution = [100.0, 105.2, 130.0, 130.1]  # Expected solution from GridCal

    print()
    print(f"Test: {test_name}")
    print(f"Results:  {approx_volt}")
    print(f"Solution: {solution}")
    print()

    print("Generators:")
    for g in grid.get_generators():
        print(f" - Generator {g}: q_min={g.Qmin}pu, q_max={g.Qmax}pu")
    print()

    print("Branches:")
    branches = grid.get_branches()
    for b in grid.transformers2w:
        print(
            f" - {b}: R={round(b.R, 4)}pu, X={round(b.X, 4)}pu, X/R={round(b.X/b.R, 1)}, vset={b.vset}"
        )
    print()

    print("Transformer types:")
    for t in grid.transformer_types:
        print(
            f" - {t}: Copper losses={int(t.Pcu)}kW, Iron losses={int(t.Pfe)}kW, SC voltage={t.Vsc}%"
        )
    print()

    print("Losses:")
    for i in range(len(branches)):
        print(
            f" - {branches[i]}: losses={round(power_flow.results.losses[i], 3)} MVA"
        )
    print()

    tr_vset = [tr.vset for tr in grid.transformers2w]
    print(f"Voltage settings: {tr_vset}")

    equal = np.isclose(approx_volt, solution, atol=1e-3).all()

    assert equal
示例#22
0
def load_iPA(file_name):

    circuit = MultiCircuit()

    with open(file_name) as json_file:
        data = json.load(json_file)

    # elements dictionaries
    xfrm_dict = {entry['IdEnRed']: entry for entry in data['Transformadores']}

    # nodes_dict = {entry['id']: entry for entry in data['Nudos']}
    nodes_dict = dict()
    buses_dict = dict()
    for entry in data['Nudos']:
        nodes_dict[entry['id']] = entry
        bus = Bus(name=str(entry['id']))
        buses_dict[entry['id']] = bus
        if entry['id'] > 0:  # omit the node 0 because it is the "earth node"...
            circuit.add_bus(bus)

    gen_dict = {entry['IdEnRed']: entry for entry in data['Generadores']}

    load_dict = {entry['IdEnRed']: entry for entry in data['Consumos']}

    sw_dict = {entry['IdEnRed']: entry for entry in data['Interruptores']}

    # main grid
    vector_red = data['Red']
    '''
    {'id': 0, 
    'Tipo': 1, 
    'E': 0, 
    'EFase': 0, 
    'Tomas': 0, 
    'R1': 1e-05, 
    'X1': 1e-05, 
    'R0': 1e-05, 
    'X0': 1e-05, 
    'RN': 1e-05, 
    'XN': 1e-05, 
    'P': 0, 
    'Q': 0, 
    'Nudo1': 2410, 
    'Nudo2': 2403, 
    'Carga_Max': -1, 
    'ClassID': 1090, 
    'ClassMEMBER': 98076366, 
    'Conf': 'abc', 
    'LineaMT': '2030:98075347', 
    'Unom': 15.0}
    '''

    for entry in vector_red:

        # pick the general attributes
        identifier = entry['id']
        tpe = entry['Tipo']
        n1_id = entry['Nudo1']
        n2_id = entry['Nudo2']

        # get the Bus objects associated to the bus indices
        if n1_id in buses_dict.keys():
            bus1 = buses_dict[n1_id]
        if n2_id in buses_dict.keys():
            bus2 = buses_dict[n2_id]

        if tpe == 0:  # Fuente de  Tensión(elemento  Ptheta)

            # pick the bus that is not the earth bus...
            if n1_id == 0:
                bus = bus2
            else:
                bus = bus1

            bus.is_slack = True
            elm = Generator(name='Slack')
            circuit.add_generator(bus, elm)

        elif tpe == 1:  # Elemento impedancia(lineas)

            V = entry['Unom']
            Zbase = V * V / circuit.Sbase

            if identifier in load_dict.keys():
                # load!!!
                print('Load found in lines: WTF?')
            else:
                # line!!!
                r = entry['R1'] / Zbase
                x = entry['X1'] / Zbase

                if r > 1e-5:
                    branch_type = BranchType.Line
                else:
                    # mark as "generic branch" the branches with very low resistance
                    branch_type = BranchType.Branch

                elm = Branch(bus_from=bus1,
                             bus_to=bus2,
                             name=str(identifier),
                             r=r,
                             x=x,
                             branch_type=branch_type)
                circuit.add_branch(elm)

        elif tpe == 2:  # Elemento PQ

            # pick the bus that is not the earth bus...
            if n1_id == 0:
                bus = bus2
            else:
                bus = bus1

            p = entry['P']  # power in MW
            q = entry['Q']
            elm = Load(name=str(identifier), P=p * 1e-3, Q=q * 1e-3)
            circuit.add_load(bus, elm)

        elif tpe == 3:  # Elemento  PV
            pass

        elif tpe == 4:  # Reg  de  tensión

            V = entry['Unom']
            Zbase = V * V / circuit.Sbase

            r = entry['R1'] / Zbase
            x = entry['X1'] / Zbase
            elm = Branch(bus_from=bus1,
                         bus_to=bus2,
                         name=str(identifier),
                         r=r,
                         x=x,
                         branch_type=BranchType.Transformer)
            circuit.add_branch(elm)

        elif tpe == 5:  # Transformador

            V = entry['Unom']
            Zbase = V * V / circuit.Sbase

            r = entry['R1'] / Zbase
            x = entry['X1'] / Zbase
            elm = Branch(bus_from=bus1,
                         bus_to=bus2,
                         name=str(identifier),
                         r=r,
                         x=x,
                         branch_type=BranchType.Transformer)
            circuit.add_branch(elm)

    # return the circuit
    return circuit
示例#23
0
def test_corr_line_losses():
    test_name = "test_corr_line_losses"

    grid = MultiCircuit(name=test_name)
    grid.Sbase = Sbase
    grid.time_profile = None
    grid.logger = list()

    # Create buses
    Bus0 = Bus(name="Bus0", vnom=10, is_slack=True)
    bus_1 = Bus(name="bus_1", vnom=10)

    grid.add_bus(Bus0)
    grid.add_bus(bus_1)

    # Create load
    grid.add_load(bus_1, Load(name="Load0", P=1.0, Q=0.4))

    # Create slack bus
    grid.add_generator(Bus0, Generator(name="Utility"))

    # Create cable
    cable = Branch(bus_from=Bus0,
                   bus_to=bus_1,
                   name="Cable0",
                   r=0.784,
                   x=0.174,
                   temp_base=20,  # °C
                   temp_oper=90,  # °C
                   alpha=0.00323)  # Copper

    grid.add_branch(cable)

    options = PowerFlowOptions(verbose=True,
                               apply_temperature_correction=True)

    power_flow = PowerFlow(grid, options)
    power_flow.run()

    # Check solution
    approx_losses = round(power_flow.results.losses[0], 3)
    solution = complex(0.011, 0.002)  # Expected solution from GridCal
                                      # Tested on ETAP 16.1.0

    print("\n=================================================================")
    print(f"Test: {test_name}")
    print("=================================================================\n")
    print(f"Results:  {approx_losses}")
    print(f"Solution: {solution}")
    print()

    print("Buses:")
    for i, b in enumerate(grid.buses):
        print(f" - bus[{i}]: {b}")
    print()

    print("Branches:")
    for b in grid.branches:
        print(f" - {b}:")
        print(f"   R = {round(b.R, 4)} pu")
        print(f"   X = {round(b.X, 4)} pu")
        print(f"   X/R = {round(b.X/b.R, 2)}")
    print()

    print("Voltages:")
    for i in range(len(grid.buses)):
        print(f" - {grid.buses[i]}: voltage={round(power_flow.results.voltage[i], 3)} pu")
    print()

    print("Losses:")
    for i in range(len(grid.branches)):
        print(f" - {grid.branches[i]}: losses={round(power_flow.results.losses[i], 3)} MVA")
    print()

    print("Loadings (power):")
    for i in range(len(grid.branches)):
        print(f" - {grid.branches[i]}: loading={round(power_flow.results.Sbranch[i], 3)} MVA")
    print()

    print("Loadings (current):")
    for i in range(len(grid.branches)):
        print(f" - {grid.branches[i]}: loading={round(power_flow.results.Ibranch[i], 3)} pu")
    print()

    assert approx_losses == solution
示例#24
0
def load_dpx(file_name, contraction_factor=1000) -> MultiCircuit:
    """
    Read DPX file
    :param file_name: file name
    :param contraction_factor: contraction factor
    :return: MultiCircuit
    """

    circuit = MultiCircuit()

    Sbase = 100
    circuit.Sbase = Sbase

    SQRT3 = np.sqrt(3)

    # read the raw data into a structured dictionary
    print('Reading file...')
    structures_dict, logger = read_dpx_data(file_name=file_name)

    # format the read data
    print('Packing data...')
    data_structures, logger = repack(data_structures=structures_dict,
                                     logger=logger)

    buses_id_dict = dict()
    #  create nodes
    for tpe in data_structures['Nodes']:
        # Airline support post
        # __headers__['Nodes']['APOIO'] = ['CLASS', 'ID', 'NAME', 'VBASE', 'GX', 'GY', 'SX', 'SY', 'EXIST']
        # __headers__['Nodes']['ARM'] = ['CLASS', 'ID', 'NAME', 'VBASE', 'GX', 'GY', 'SX', 'SY', 'EXIST', 'YEAR']
        # __headers__['Nodes']['CX'] = ['CLASS', 'ID', 'NAME', 'VBASE', 'GX', 'GY', 'SX', 'SY', 'EXIST']
        # __headers__['Nodes']['CXN'] = ['CLASS', 'ID', 'NAME', 'VBASE', 'GX', 'GY', 'SX', 'SY', 'EXIST']
        # __headers__['Nodes']['LOAD'] = ['CLASS', 'ID', 'NAME', 'VBASE', 'GX', 'GY', 'SX', 'SY', 'EXIST', 'VMIN', 'VMAX', 'NCMPLAN']  # fill to fit...
        if tpe in ['APOIO', 'ARM', 'CX', 'CXN', 'LOAD']:
            df = data_structures['Nodes'][tpe]

            for i in range(df.shape[0]):
                name = 'B' + str(len(circuit.buses) + 1) + '_' + str(
                    df['NAME'].values[i])
                Vnom = float(df['VBASE'].values[i])
                x = float(df['GX'].values[i]) / contraction_factor
                y = float(df['GY'].values[i]) / contraction_factor
                id_ = df['ID'].values[i]
                bus = Bus(name=name,
                          vnom=Vnom,
                          xpos=x,
                          ypos=y,
                          height=40,
                          width=60)

                circuit.add_bus(bus)
                buses_id_dict[id_] = bus

        # Network Equivalent
        # __headers__['Nodes']['EQUIV'] = ['CLASS', 'ID', 'NAME', 'VBASE', 'GX', 'GY', 'SX', 'SY', 'VMIN', 'VMAX', 'ZONE',
        #                                  'SEPNET', 'AUTOUP', 'P', 'Q', 'ELAST', 'SIMUL', 'HTYP', 'HARM5', 'HARM7',
        #                                  'HARM11',
        #                                  'HARM13', 'NOGRW', 'RS', 'XS', 'R1', 'X1', 'R2', 'X2', 'RH', 'XH', 'COM']
        elif tpe == 'EQUIV':
            df = data_structures['Nodes'][tpe]

            for i in range(df.shape[0]):
                name = 'B' + str(len(circuit.buses) + 1) + '_' + str(
                    df['NAME'].values[i])
                Vnom = float(df['VBASE'].values[i])
                x = float(df['GX'].values[i]) / contraction_factor
                y = float(df['GY'].values[i]) / contraction_factor
                id_ = df['ID'].values[i]
                bus = Bus(name=name,
                          vnom=Vnom,
                          xpos=x,
                          ypos=y,
                          height=40,
                          width=60,
                          is_slack=True)
                circuit.add_bus(bus)
                buses_id_dict[id_] = bus

                name = 'LD' + str(len(circuit.buses)) + '_' + str(
                    df['NAME'].values[i])
                p = float(df['P'].values[i]) * Sbase
                q = float(df['Q'].values[i]) * Sbase
                load = Load(name=name, P=p, Q=q)

                circuit.add_load(bus, load)

        # Generator
        # __headers__['Nodes']['GEN'] = ['CLASS', 'ID', 'NAME', 'VBASE', 'GX', 'GY', 'SX', 'SY', 'EXIST', 'MODEL', 'VMIN',
        #                                'VMAX',
        #                                'V', 'ENAB', 'P', 'Q', 'QMIN', 'QMAX', 'ELAST', 'HTYP', 'HARM5', 'HARM7',
        #                                'HARM11',
        #                                'HARM13', 'VNOM', 'RAT', 'TGEN', 'COST', 'YEAR']
        elif tpe == 'GEN':
            df = data_structures['Nodes'][tpe]

            for i in range(df.shape[0]):
                name = 'B' + str(len(circuit.buses) + 1) + '_' + str(
                    df['NAME'].values[i])
                Vnom = float(df['VBASE'].values[i])
                x = float(df['GX'].values[i]) / contraction_factor
                y = float(df['GY'].values[i]) / contraction_factor
                id_ = df['ID'].values[i]
                bus = Bus(name=name,
                          vnom=Vnom,
                          xpos=x,
                          ypos=y,
                          height=40,
                          width=60)
                circuit.add_bus(bus)
                buses_id_dict[id_] = bus

                mode = int(df['MODEL'].values[i])

                if mode == 1:
                    name = 'GEN' + str(len(circuit.buses)) + '_' + str(
                        df['NAME'].values[i])
                    p = float(df['P'].values[i]) * Sbase
                    q = float(df['Q'].values[i]) * Sbase
                    v = float(df['V'].values[i])  # p.u.
                    gen = Generator(name=name,
                                    active_power=p,
                                    voltage_module=v)

                    circuit.add_generator(bus, gen)
                else:
                    name = 'GENSTAT' + str(len(circuit.buses)) + '_' + str(
                        df['NAME'].values[i])
                    p = float(df['P'].values[i]) * Sbase
                    q = float(df['Q'].values[i]) * Sbase
                    gen = StaticGenerator(name=name, P=p, Q=q)
                    circuit.add_static_generator(bus, gen)

        # Transformation station
        # __headers__['Nodes']['PT'] = ['CLASS', 'ID', 'NAME', 'VBASE', 'GX', 'GY', 'SX', 'SY', 'EXIST', 'VMIN', 'VMAX',
        #                               'ZONE',
        #                               'ENAB', 'P', 'Q', 'ELAST', 'SIMUL', 'HTYP', 'HARM5', 'HARM7', 'HARM11', 'HARM13',
        #                               'NOGRW',
        #                               'EQEXIST', 'EQPOSS1', 'MCOST1', 'ICOST1', 'EQPOSS2', 'MCOST2', 'ICOST2',
        #                               'EQPOSS3', 'MCOST3',
        #                               'ICOST3', 'NCLI', 'EQTYPE', 'YEAR', 'COM', 'INFOCOM', 'ID_AUX']
        elif tpe in ['PT', 'PTC']:

            df = data_structures['Nodes'][tpe]

            for i in range(df.shape[0]):

                name = 'B' + str(len(circuit.buses) + 1) + '_' + str(
                    df['NAME'].values[i])
                Vnom = float(df['VBASE'].values[i])
                x = float(df['GX'].values[i]) / contraction_factor
                y = float(df['GY'].values[i]) / contraction_factor
                id_ = df['ID'].values[i]
                bus = Bus(name=name,
                          vnom=Vnom,
                          xpos=x,
                          ypos=y,
                          height=40,
                          width=60)

                name = 'LD' + str(len(circuit.buses) + 1) + '_' + str(
                    df['NAME'].values[i])
                p = float(df['P'].values[i]) * Sbase
                q = float(df['Q'].values[i]) * Sbase
                load = Load(name=name, P=p, Q=q)

                circuit.add_bus(bus)
                circuit.add_load(bus, load)
                buses_id_dict[id_] = bus

        # Reference node
        # __headers__['Nodes']['REF'] = ['CLASS', 'ID', 'NAME', 'VBASE', 'GX', 'GY', 'SX', 'SY', 'VREF', 'RAT',
        #                                'COST', 'TGEN', 'YEAR']
        elif tpe == 'REF':
            df = data_structures['Nodes'][tpe]

            for i in range(df.shape[0]):
                name = 'B' + str(len(circuit.buses) + 1) + '_' + str(
                    df['NAME'].values[i])
                Vnom = float(df['VBASE'].values[i])
                x = float(df['GX'].values[i]) / contraction_factor
                y = float(df['GY'].values[i]) / contraction_factor
                id_ = df['ID'].values[i]
                bus = Bus(name=name,
                          vnom=Vnom,
                          xpos=x,
                          ypos=y,
                          height=40,
                          width=60,
                          is_slack=True)

                circuit.add_bus(bus)
                buses_id_dict[id_] = bus

        # Voltage Transformer
        # __headers__['Nodes']['TT'] = ['CLASS', 'ID', 'NAME', 'VBASE', 'GX', 'GY', 'SX', 'SY', 'EXIST', 'VMIN', 'VMAX',
        #                               'DISABLE', 'HARM5', 'HARM7', 'HARM11', 'HARM13', 'EQEXIST', 'TAP', 'YEAR',
        #                               'ID_AUX']
        elif tpe == 'TT':
            df = data_structures['Nodes'][tpe]

            for i in range(df.shape[0]):
                name = 'B' + str(len(circuit.buses) + 1) + '_' + str(
                    df['NAME'].values[i])
                Vnom = float(df['VBASE'].values[i])
                x = float(df['GX'].values[i]) / contraction_factor
                y = float(df['GY'].values[i]) / contraction_factor
                id_ = df['ID'].values[i]
                bus = Bus(name=name,
                          vnom=Vnom,
                          xpos=x,
                          ypos=y,
                          height=40,
                          width=60)

                circuit.add_bus(bus)
                buses_id_dict[id_] = bus

        else:
            logger.add_error('Not recognised under Nodes', tpe)

    # create branches
    for tpe in data_structures['Branches']:

        # Condenser series or shunt
        # __headers__['Branches']['CAP'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'EXIST', 'STAT', 'PERM', 'EQ', 'YEAR']
        if tpe in ['CAP', 'IND']:

            df = data_structures['Branches'][tpe]

            for i in range(df.shape[0]):
                name = df['NAME'].values[i]
                id1 = df['ID1'].values[i]
                id2 = df['ID2'].values[i]
                b1 = buses_id_dict[id1]
                b2 = buses_id_dict[id2]

                # get equipment reference in the catalogue
                eq_id = df['EQ'].values[i]
                df_cat = data_structures['CatalogBranch'][tpe]
                cat_elm = df_cat[df_cat['EQ'] == eq_id]

                try:
                    x = float(cat_elm['REAC'].values[0]) * Sbase
                except:
                    x = 1e-20

                br = Branch(bus_from=b1,
                            bus_to=b2,
                            name=name,
                            x=x,
                            branch_type=BranchType.Branch)
                circuit.add_branch(br)

        # Estimator
        # __headers__['Branches']['ESTIM'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'INDEP', 'I', 'SIMULT']
        if tpe in ['ESTIM']:
            df = data_structures['Branches'][tpe]

            for i in range(df.shape[0]):
                name = df['NAME'].values[i]
                id1 = df['ID1'].values[i]
                id2 = df['ID2'].values[i]
                b1 = buses_id_dict[id1]
                b2 = buses_id_dict[id2]
                br = Branch(bus_from=b1,
                            bus_to=b2,
                            name=name,
                            branch_type=BranchType.Branch)
                circuit.add_branch(br)

        # Breaker
        # __headers__['Branches']['DISJ'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'EXIST', 'STAT', 'PERM', 'FAILRT',
        #                                    'TISOL', 'TRECONF', 'TREPAIR', 'EQ', 'YEAR', 'CONTROL']

        # Fuse
        # __headers__['Branches']['FUS'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'EXIST', 'STAT', 'PERM', 'FAILRT',
        #                                   'TISOL','TRECONF', 'TREPAIR', 'EQ', 'YEAR']

        # Switch
        # __headers__['Branches']['INTR'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'EXIST', 'STAT', 'PERM', 'FAILRT',
        #                                    'TISOL', 'TRECONF', 'TREPAIR', 'EQ', 'YEAR', 'DRIVE', 'CONTROL']

        # Disconnector
        # __headers__['Branches']['SECC'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'EXIST', 'STAT', 'PERM', 'FAILRT',
        #                                    'TISOL', 'TRECONF', 'TREPAIR', 'EQ', 'YEAR', 'DRIVE', 'CONTROL']
        if tpe in ['DISJ', 'FUS', 'INTR', 'SECC']:
            df = data_structures['Branches'][tpe]

            for i in range(df.shape[0]):
                name = df['NAME'].values[i]
                id1 = df['ID1'].values[i]
                id2 = df['ID2'].values[i]
                state = bool(int(df['STAT'].values[i]))
                b1 = buses_id_dict[id1]
                b2 = buses_id_dict[id2]
                br = Branch(bus_from=b1,
                            bus_to=b2,
                            name=name,
                            active=state,
                            branch_type=BranchType.Switch)
                circuit.add_branch(br)

        # Lines, cables and bars
        # fill until it fits or truncate the data
        # __headers__['Branches']['LINE'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'EXIST', 'COLOR', 'GEOLEN', 'LEN',
        #                                    'STAT',
        #                                    'PERM', 'FAILRT', 'TISOL', 'TRECONF', 'TREPAIR', 'RERAT', 'EQEXIST', 'NPOSS',
        #                                    'CHOOSEQ', 'INSRTCOST', 'EQPOSS1', 'MATCOST1', 'EQPOSS2', 'MATCOST2',
        #                                    'EQPOSS3',
        #                                    'MATCOST3', 'NCOOG', 'GX1', 'GY1', 'GX2', 'GY2']
        if tpe in ['LINE']:
            df = data_structures['Branches'][tpe]

            for i in range(df.shape[0]):
                name = df['NAME'].values[i]
                id1 = df['ID1'].values[i]
                id2 = df['ID2'].values[i]
                b1 = buses_id_dict[id1]
                b2 = buses_id_dict[id2]

                length = float(df['LEN'].values[i])

                # get equipment reference in the catalogue
                eq_id = df['EQEXIST'].values[i]
                df_cat = data_structures['CatalogBranch'][tpe]
                cat_elm = df_cat[df_cat['EQ'] == eq_id]

                try:
                    r = float(cat_elm['R'].values[0]) * length / 1000
                except:
                    r = 1e-20
                try:
                    x = float(cat_elm['X'].values[0]) * length / 1000
                except:
                    x = 1e-20
                try:
                    b = float(cat_elm['B'].values[0]) * length / 1000
                except:
                    b = 1e-20

                Imax = float(
                    cat_elm['RATTYP'].values[0]) / 1000.0  # pass from A to kA
                Vnom = float(cat_elm['VNOM'].values[0])  # kV
                Smax = Imax * Vnom * SQRT3  # MVA
                # correct for zero values which are problematic
                r = r if r > 0.0 else 1e-20
                x = x if x > 0.0 else 1e-20
                b = b if b > 0.0 else 1e-20

                br = Branch(bus_from=b1,
                            bus_to=b2,
                            name=name,
                            r=r,
                            x=x,
                            b=b,
                            rate=Smax,
                            length=length,
                            branch_type=BranchType.Line)
                circuit.add_branch(br)

        # Intensity Transformer
        # __headers__['Branches']['TI'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'INDEP', 'I', 'SIMULT', 'EXIST', 'STAT',
        #                                  'PERM', 'FAILRT', 'TISOL', 'TRECONF', 'TREPAIR', 'EQ', 'TAP1', 'TAP2', 'YEAR']
        if tpe in ['TI']:
            df = data_structures['Branches'][tpe]

            for i in range(df.shape[0]):
                name = df['NAME'].values[i]
                id1 = df['ID1'].values[i]
                id2 = df['ID2'].values[i]
                b1 = buses_id_dict[id1]
                b2 = buses_id_dict[id2]

                # get equipment reference in the catalogue
                eq_id = df['EQ'].values[i]
                df_cat = data_structures['CatalogBranch'][tpe]
                cat_elm = df_cat[df_cat['EQ'] == eq_id]

                br = Branch(bus_from=b1,
                            bus_to=b2,
                            name=name,
                            branch_type=BranchType.Transformer)
                circuit.add_branch(br)

        # Self-transformer
        # __headers__['Branches']['XFORM1'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'ID3', 'ID1N', 'ID2N', 'ID3N',
        #                                      'EXIST',
        #                                      'STAT', 'FAILRT', 'TISOL', 'TRECONF', 'TREPAIR', 'RERAT', 'CON1', 'RE1',
        #                                      'XE1',
        #                                      'CON2', 'RE2', 'XE2', 'CON3', 'RE3', 'XE3', 'LOSS', 'TPERM', 'SETVSEL',
        #                                      'SETV',
        #                                      'EQ', 'TAP1', 'TAP2', 'TAP3', 'YEAR', 'NUM']
        if tpe in ['XFORM1', 'XFORM2']:
            df = data_structures['Branches'][tpe]

            for i in range(df.shape[0]):
                name = df['NAME'].values[i]
                id1 = df['ID1'].values[i]
                id2 = df['ID2'].values[i]
                b1 = buses_id_dict[id1]
                b2 = buses_id_dict[id2]

                # get equipment reference in the catalogue
                # eq_id = df['EQ'].values[i]
                eq_id = df['XE3'].values[
                    i]  # to correct the bad data formatting these file has...
                df_cat = data_structures['CatalogBranch'][tpe]
                cat_elm = df_cat[df_cat['EQ'] == eq_id]

                if cat_elm.shape[0] > 0:
                    r1 = float(cat_elm['RD1'].values[0])
                    r2 = float(cat_elm['RD2'].values[0])
                    x1 = float(cat_elm['XD1'].values[0])
                    x2 = float(cat_elm['XD2'].values[0])

                    s1 = float(cat_elm['SNOMTYP1'].values[0]
                               ) / 1000.0  # from kVA to MVA
                    s2 = float(cat_elm['SNOMTYP2'].values[0]
                               ) / 1000.0  # from kVA to MVA

                    r = r1 + r2
                    x = x1 + x2
                    s = s1 + s2

                    r = r if r > 0.0 else 1e-20
                    x = x if x > 0.0 else 1e-20
                    s = s if s > 0.0 else 1e-20
                else:
                    r = 1e-20
                    x = 1e-20
                    s = 1e-20
                    logger.add_error('Not found.', tpe + ':' + eq_id)

                br = Branch(bus_from=b1,
                            bus_to=b2,
                            name=name,
                            r=r,
                            x=x,
                            rate=s,
                            branch_type=BranchType.Transformer)
                circuit.add_branch(br)

        # 3-winding transformer
        # __headers__['Branches']['XFORM3'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'ID3', 'ID1N', 'ID2N', 'ID3N',
        #                                      'EXIST',
        #                                      'STAT', 'FAILRT', 'TISOL', 'TRECONF', 'TREPAIR', 'RERAT', 'CON1', 'RE1',
        #                                      'XE1',
        #                                      'CON2', 'RE2', 'XE2', 'CON3', 'RE3', 'XE3', 'LOSS', 'TPERM', 'SETVSEL',
        #                                      'SETV',
        #                                      'EQ', 'TAP1', 'TAP2', 'TAP3', 'YEAR', 'NUM']
        if tpe in ['XFORM3']:
            df = data_structures['Branches'][tpe]

            for i in range(df.shape[0]):
                name = df['NAME'].values[i]
                id1 = df['ID1'].values[i]
                id2 = df['ID2'].values[i]
                id3 = df['ID3'].values[i]
                b1 = buses_id_dict[id1]
                b2 = buses_id_dict[id2]
                b3 = buses_id_dict[id3]

                # get equipment reference in the catalogue
                eq_id = df['EQ'].values[i]
                df_cat = data_structures['CatalogBranch'][tpe]
                cat_elm = df_cat[df_cat['EQ'] == eq_id]

                r1 = float(cat_elm['RD1'].values[0])
                r2 = float(cat_elm['RD2'].values[0])
                r3 = float(cat_elm['RD3'].values[0])
                x1 = float(cat_elm['XD1'].values[0])
                x2 = float(cat_elm['XD2'].values[0])
                x3 = float(cat_elm['XD3'].values[0])

                s1 = float(
                    cat_elm['SNOMTYP1'].values[0]) / 1000.0  # from kVA to MVA
                s2 = float(
                    cat_elm['SNOMTYP2'].values[0]) / 1000.0  # from kVA to MVA
                s3 = float(
                    cat_elm['SNOMTYP3'].values[0]) / 1000.0  # from kVA to MVA

                r12 = r1 + r2
                x12 = x1 + x2
                s12 = s1 + s2

                r13 = r1 + r3
                x13 = x1 + x3
                s13 = s1 + s3

                r23 = r2 + r3
                x23 = x2 + x3
                s23 = s2 + s3

                r12 = r12 if r12 > 0.0 else 1e-20
                x12 = x12 if x12 > 0.0 else 1e-20
                s12 = s12 if s12 > 0.0 else 1e-20

                r13 = r13 if r13 > 0.0 else 1e-20
                x13 = x13 if x13 > 0.0 else 1e-20
                s13 = s13 if s13 > 0.0 else 1e-20

                r23 = r23 if r23 > 0.0 else 1e-20
                x23 = x23 if x23 > 0.0 else 1e-20
                s23 = s23 if s23 > 0.0 else 1e-20

                br = Branch(bus_from=b1,
                            bus_to=b2,
                            name=name,
                            r=r12,
                            x=x12,
                            rate=s12,
                            branch_type=BranchType.Transformer)
                circuit.add_branch(br)

                br = Branch(bus_from=b1,
                            bus_to=b3,
                            name=name,
                            r=r13,
                            x=x13,
                            rate=s13,
                            branch_type=BranchType.Transformer)
                circuit.add_branch(br)

                br = Branch(bus_from=b2,
                            bus_to=b3,
                            name=name,
                            r=r23,
                            x=x23,
                            rate=s23,
                            branch_type=BranchType.Transformer)
                circuit.add_branch(br)

        # Neutral impedance
        # __headers__['Branches']['ZN'] = ['CLASS', 'ID', 'NAME', 'ID1', 'ID2', 'EXIST', 'STAT', 'PERM', 'FAILRT',
        #                                  'TISOL','TRECONF', 'TREPAIR', 'EQ', 'YEAR']
        if tpe in ['ZN']:
            df = data_structures['Branches'][tpe]

            for i in range(df.shape[0]):
                name = df['NAME'].values[i]
                id1 = df['ID1'].values[i]
                id2 = df['ID2'].values[i]
                b1 = buses_id_dict[id1]
                b2 = buses_id_dict[id2]
                br = Branch(bus_from=b1,
                            bus_to=b2,
                            name=name,
                            branch_type=BranchType.Branch)
                circuit.add_branch(br)

    # return the circuit and the logs
    return circuit, logger
示例#25
0
                    obj2
                )  # call this again, but this time it is not a Branch object
            else:
                raise Exception('Unrecognized branch type ' +
                                obj.device_type.value)

        # Draw schematic subset
        self.grid_editor.add_elements_to_schematic(
            buses=list(buses),
            lines=lines,
            dc_lines=dc_lines,
            transformers2w=transformers2w,
            hvdc_lines=hvdc_lines,
            vsc_devices=vsc_converters,
            upfc_devices=upfc_devices,
            explode_factor=1.0,
            prog_func=None,
            text_func=print)
        self.grid_editor.center_nodes()


if __name__ == "__main__":

    app = QApplication(sys.argv)
    circuit_ = MultiCircuit()
    circuit_.add_bus(Bus('bus1'))
    window = BusViewerGUI(circuit=circuit_, root_bus=circuit_.buses[0])
    window.resize(1.61 * 700.0, 600.0)  # golden ratio
    window.show()
    sys.exit(app.exec_())
示例#26
0
def test_line_losses_1():
    """
    Basic line losses test.
    """
    test_name = "test_line_losses_1"
    grid = MultiCircuit(name=test_name)
    Sbase = 100  # MVA
    grid.Sbase = Sbase
    grid.time_profile = None
    grid.logger = Logger()

    # Create buses
    Bus0 = Bus(name="Bus0", vnom=25, is_slack=True)
    Bus1 = Bus(name="Bus1", vnom=25)

    grid.add_bus(Bus0)
    grid.add_bus(Bus1)

    # Create load
    grid.add_load(Bus1, Load(name="Load0", P=1.0, Q=0.4))

    # Create slack bus
    grid.add_generator(Bus0, Generator(name="Utility"))

    # Create cable (r and x should be in pu)
    grid.add_branch(
        Line(bus_from=Bus0, bus_to=Bus1, name="Cable1", r=0.01, x=0.05))

    # Run non-linear load flow
    options = PowerFlowOptions(verbose=True)

    power_flow = PowerFlowDriver(grid, options)
    power_flow.run()

    # Check solution
    approx_losses = round(1000 * power_flow.results.losses[0], 3)
    solution = complex(0.116, 0.58)  # Expected solution from GridCal
    # Tested on ETAP 16.1.0 and pandapower

    print(
        "\n=================================================================")
    print(f"Test: {test_name}")
    print(
        "=================================================================\n")
    print(f"Results:  {approx_losses}")
    print(f"Solution: {solution}")
    print()

    print("Buses:")
    for i, b in enumerate(grid.buses):
        print(f" - bus[{i}]: {b}")
    print()

    print("Branches:")
    branches = grid.get_branches()
    for b in branches:
        print(f" - {b}:")
        print(f"   R = {round(b.R, 4)} pu")
        print(f"   X = {round(b.X, 4)} pu")
        print(f"   X/R = {round(b.X/b.R, 2)}")
    print()

    print("Voltages:")
    for i in range(len(grid.buses)):
        print(
            f" - {grid.buses[i]}: voltage={round(power_flow.results.voltage[i], 3)} pu"
        )
    print()

    print("Losses:")
    for i in range(len(branches)):
        print(
            f" - {branches[i]}: losses={round(power_flow.results.losses[i], 3)} MVA"
        )
    print()

    print("Loadings (power):")
    for i in range(len(branches)):
        print(
            f" - {branches[i]}: loading={round(power_flow.results.Sf[i], 3)} MVA"
        )
    print()

    print("Loadings (current):")
    for i in range(len(branches)):
        print(
            f" - {branches[i]}: loading={round(power_flow.results.If[i], 3)} pu"
        )
    print()

    assert approx_losses == solution
示例#27
0
def interpret_data_v1(circuit: MultiCircuit, data) -> MultiCircuit:
    """
    Pass the loaded table-like data to the  structures
    :param circuit:
    :param data: Data dictionary
    :return:
    """

    circuit.clear()

    # time profile
    if 'master_time' in data.keys():
        master_time_array = data['master_time']
    else:
        master_time_array = None

    import GridCal.Engine.IO.matpower_bus_definitions as e
    # Buses
    table = data['bus']
    buses_dict = dict()
    n = len(table)

    # load profiles
    if 'Lprof' in data.keys():
        Pprof = data['Lprof']
        Qprof = data['LprofQ']
        are_load_prfiles = True
        print('There are load profiles')
    else:
        are_load_prfiles = False

    if 'bus_names' in data.keys():
        names = data['bus_names']
    else:
        names = ['bus ' + str(i) for i in range(n)]

    # Buses
    bus_idx_dict = dict()
    for i in range(n):
        # Create bus
        bus = Bus(name=names[i],
                  vnom=table[i, e.BASE_KV],
                  vmax=table[i, e.VMAX],
                  vmin=table[i, e.VMIN])

        # store the given bus index in relation to its real index in the table for later
        bus_idx_dict[table[i, e.BUS_I]] = i

        # determine if the bus is set as slack manually
        tpe = table[i, e.BUS_TYPE]
        if tpe == e.REF:
            bus.is_slack = True
        else:
            bus.is_slack = False

        # Add the load
        if table[i, e.PD] != 0 or table[i, e.QD] != 0:
            load = Load(P=table[i, e.PD], Q=table[i, e.QD])
            load.bus = bus
            bus.loads.append(load)

        # Add the shunt
        if table[i, e.GS] != 0 or table[i, e.BS] != 0:
            shunt = Shunt(G=table[i, e.GS], B=table[i, e.BS])
            shunt.bus = bus
            bus.shunts.append(shunt)

        # Add the bus to the circuit buses
        circuit.add_bus(bus)

    import GridCal.Engine.IO.matpower_gen_definitions as e
    # Generators
    table = data['gen']
    n = len(table)
    # load profiles
    if 'Gprof' in data.keys():
        Gprof = data['Gprof']
        are_gen_prfiles = True
        print('There are gen profiles')
    else:
        are_gen_prfiles = False

    if 'gen_names' in data.keys():
        names = data['gen_names']
    else:
        names = ['gen ' + str(i) for i in range(n)]
    for i in range(len(table)):
        bus_idx = bus_idx_dict[int(table[i, e.GEN_BUS])]
        gen = Generator(name=names[i],
                        active_power=table[i, e.PG],
                        voltage_module=table[i, e.VG],
                        Qmax=table[i, e.QMAX],
                        Qmin=table[i, e.QMIN])

        # Add the generator to the bus
        gen.bus = circuit.buses[bus_idx]
        circuit.buses[bus_idx].controlled_generators.append(gen)

    import GridCal.Engine.IO.matpower_branch_definitions as e
    # Branches
    table = data['branch']
    n = len(table)
    if 'branch_names' in data.keys():
        names = data['branch_names']
    else:
        names = ['branch ' + str(i) for i in range(n)]
    for i in range(len(table)):
        f = circuit.buses[bus_idx_dict[int(table[i, e.F_BUS])]]
        t = circuit.buses[bus_idx_dict[int(table[i, e.T_BUS])]]

        if f.Vnom != t.Vnom or table[i, e.TAP] != 1.0 or table[i, e.SHIFT] != 0.0:

            branch = Transformer2W(bus_from=f,
                                   bus_to=t,
                                   name=names[i],
                                   r=table[i, e.BR_R],
                                   x=table[i, e.BR_X],
                                   g=0,
                                   b=table[i, e.BR_B],
                                   rate=table[i, e.RATE_A],
                                   tap=table[i, e.TAP],
                                   shift_angle=table[i, e.SHIFT],
                                   active=bool(table[i, e.BR_STATUS]))
            circuit.add_transformer2w(branch)

        else:
            branch = Line(bus_from=f,
                          bus_to=t,
                          name=names[i],
                          r=table[i, e.BR_R],
                          x=table[i, e.BR_X],
                          b=table[i, e.BR_B],
                          rate=table[i, e.RATE_A],
                          active=bool(table[i, e.BR_STATUS]))
            circuit.add_line(branch)

    # add the profiles
    if master_time_array is not None:

        circuit.format_profiles(master_time_array)
    print('Interpreted.')
    return circuit