Exemple #1
0
    def parse_loads(self, cim: CIMCircuit, circuit: MultiCircuit, busbar_dict):
        """

        :param cim:
        :param circuit:
        :param busbar_dict:
        :return:
        """
        cim_loads = ['ConformLoad', 'EnergyConsumer', 'NonConformLoad']
        if any_in_dict(cim.elements_by_type, cim_loads):
            for elm in get_elements(cim.elements_by_type, cim_loads):

                b1 = elm.get_bus()
                B1 = try_bus(b1, busbar_dict)

                if B1 is not None:

                    p, q = elm.get_pq()

                    load = gcdev.Load(idtag=elm.uuid,
                                      name=str(elm.name),
                                      G=0,
                                      B=0,
                                      Ir=0,
                                      Ii=0,
                                      P=p if p is not None else 0,
                                      Q=q if q is not None else 0)
                    circuit.add_load(B1, load)
                else:
                    self.logger.add_error('Bus not found', elm.rfid)
Exemple #2
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
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)
Exemple #4
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
Exemple #5
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
Exemple #6
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
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()
Exemple #8
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
Exemple #9
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()
Exemple #10
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
Exemple #11
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)
Exemple #12
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()
Exemple #13
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()
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
Exemple #15
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