예제 #1
0
    def convert_line_to_transformer(self, line: Line):
        """
        Convert a line to Transformer
        :param line: Line instance
        :return: Nothing
        """
        transformer = Transformer2W(bus_from=line.bus_from,
                                    bus_to=line.bus_to,
                                    name='Transformer',
                                    active=line.active,
                                    rate=line.rate,
                                    r=line.R,
                                    x=line.X,
                                    b=line.B,
                                    active_prof=line.active_prof,
                                    rate_prof=line.rate_prof)

        # add device to the circuit
        self.circuit.add_transformer2w(transformer)

        # add device to the schematic
        transformer.graphic_obj = self.add_api_transformer(transformer)

        # update position
        transformer.graphic_obj.fromPort.update()
        transformer.graphic_obj.toPort.update()

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

        # delete from the schematic
        self.diagramScene.removeItem(line.graphic_obj)
예제 #2
0
def convert_branch(branch: Branch):
    """

    :param branch:
    :return:
    """
    if branch.branch_type == BranchType.Line:

        return Line(bus_from=branch.bus_from,
                    bus_to=branch.bus_to,
                    name=branch.name,
                    r=branch.R,
                    x=branch.X,
                    b=branch.B,
                    rate=branch.rate,
                    active=branch.active,
                    tolerance=branch.tolerance,
                    cost=branch.Cost,
                    mttf=branch.mttf,
                    mttr=branch.mttr,
                    r_fault=branch.r_fault,
                    x_fault=branch.x_fault,
                    fault_pos=branch.fault_pos,
                    length=branch.length,
                    temp_base=branch.temp_base,
                    temp_oper=branch.temp_oper,
                    alpha=branch.alpha,
                    rate_prof=branch.rate_prof,
                    Cost_prof=branch.Cost_prof,
                    active_prof=branch.active_prof,
                    temp_oper_prof=branch.temp_oper_prof)

    elif branch.branch_type == BranchType.Transformer:

        return Transformer2W(bus_from=branch.bus_from,
                             bus_to=branch.bus_to,
                             name=branch.name,
                             r=branch.R,
                             x=branch.X,
                             b=branch.B,
                             rate=branch.rate,
                             active=branch.active,
                             tolerance=branch.tolerance,
                             cost=branch.Cost,
                             mttf=branch.mttf,
                             mttr=branch.mttr,
                             tap=branch.tap_module,
                             shift_angle=branch.angle,
                             vset=branch.vset,
                             bus_to_regulated=branch.bus_to_regulated,
                             temp_base=branch.temp_base,
                             temp_oper=branch.temp_oper,
                             alpha=branch.alpha,
                             template=branch.template,
                             rate_prof=branch.rate_prof,
                             Cost_prof=branch.Cost_prof,
                             active_prof=branch.active_prof,
                             temp_oper_prof=branch.temp_oper_prof)
    else:
        return branch
예제 #3
0
 def add_transformer(self, branch: Transformer2W):
     """
     Add branch to the schematic
     :param branch: Branch object
     """
     terminal_from = branch.bus_from.graphic_obj.terminal
     terminal_to = branch.bus_to.graphic_obj.terminal
     graphic_obj = TransformerGraphicItem(terminal_from, terminal_to, self.diagramScene, branch=branch)
     graphic_obj.diagramScene.circuit = self.circuit  # add pointer to the circuit
     terminal_from.hosting_connections.append(graphic_obj)
     terminal_to.hosting_connections.append(graphic_obj)
     graphic_obj.redraw()
     branch.graphic_obj = graphic_obj
예제 #4
0
    def scene_mouse_release_event(self, event):
        """
        Finalize the branch creation if its drawing ends in a terminal
        @param event:
        @return:
        """
        # Clear or finnish the started connection:
        if self.started_branch:
            pos = event.scenePos()
            items = self.diagramScene.items(pos)  # get the item (the terminal) at the mouse position

            for item in items:
                if type(item) is TerminalItem:  # connect only to terminals
                    if item.parent is not self.started_branch.fromPort.parent:  # forbid connecting to itself

                        self.started_branch.setToPort(item)
                        item.hosting_connections.append(self.started_branch)
                        self.started_branch.bus_to = item.parent

                        if self.started_branch.bus_from.api_object.is_dc != self.started_branch.bus_to.api_object.is_dc:
                            # different DC status -> VSC

                            name = 'VSC ' + str(len(self.circuit.vsc_devices) + 1)
                            obj = VSC(bus_from=self.started_branch.bus_from.api_object,
                                      bus_to=self.started_branch.bus_to.api_object,
                                      name=name)

                            obj.graphic_obj = VscGraphicItem(fromPort=self.started_branch.fromPort,
                                                             toPort=self.started_branch.toPort,
                                                             diagramScene=self.diagramScene,
                                                             branch=obj)

                        elif self.started_branch.bus_from.api_object.is_dc and self.started_branch.bus_to.api_object.is_dc:
                            # both buses are DC

                            name = 'Dc line ' + str(len(self.circuit.dc_lines) + 1)
                            obj = DcLine(bus_from=self.started_branch.bus_from.api_object,
                                         bus_to=self.started_branch.bus_to.api_object,
                                         name=name)

                            obj.graphic_obj = DcLineGraphicItem(fromPort=self.started_branch.fromPort,
                                                                toPort=self.started_branch.toPort,
                                                                diagramScene=self.diagramScene,
                                                                branch=obj)

                        else:
                            # Same DC status -> line / trafo
                            v1 = self.started_branch.bus_from.api_object.Vnom
                            v2 = self.started_branch.bus_to.api_object.Vnom

                            if abs(v1 - v2) > 1.0:
                                name = 'Transformer ' + str(len(self.circuit.transformers2w) + 1)
                                obj = Transformer2W(bus_from=self.started_branch.bus_from.api_object,
                                                    bus_to=self.started_branch.bus_to.api_object,
                                                    name=name)

                                obj.graphic_obj = TransformerGraphicItem(fromPort=self.started_branch.fromPort,
                                                                         toPort=self.started_branch.toPort,
                                                                         diagramScene=self.diagramScene,
                                                                         branch=obj)

                            else:
                                name = 'Line ' + str(len(self.circuit.lines) + 1)
                                obj = Line(bus_from=self.started_branch.bus_from.api_object,
                                           bus_to=self.started_branch.bus_to.api_object,
                                           name=name)

                                obj.graphic_obj = LineGraphicItem(fromPort=self.started_branch.fromPort,
                                                                  toPort=self.started_branch.toPort,
                                                                  diagramScene=self.diagramScene,
                                                                  branch=obj)

                        # add the new object to the circuit
                        self.circuit.add_branch(obj)

                        # update the connection placement
                        obj.graphic_obj.fromPort.update()
                        obj.graphic_obj.toPort.update()

                        # set the connection placement
                        obj.graphic_obj.setZValue(-1)

            # if self.started_branch.toPort is None:
            self.started_branch.remove_widget()

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

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

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

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

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

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

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

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

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

    # Create branches
    X_C3 = Transformer2W(bus_from=POI, bus_to=B_C3, name="X_C3", template=SS)
    grid.add_transformer2w(X_C3)

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

    X_M32 = Transformer2W(bus_from=B_MV_M32,
                          bus_to=B_LV_M32,
                          name="X_M32",
                          template=PM)
    grid.add_transformer2w(X_M32)

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

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

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

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

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

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

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

    print("Branches:")
    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, 1)}")
        print(f"   G = {round(b.G, 4)} pu")
        print(f"   B = {round(b.B, 4)} pu")
    print()

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

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

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

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

    The transformers' magnetizing branch losses are considered, but their
    voltage regulators aren't.
    """
    test_name = "test_pv_1"
    grid = MultiCircuit(name=test_name)
    Sbase = 100  # MVA
    grid.Sbase = Sbase
    grid.time_profile = None
    grid.logger = Logger()

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

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

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

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

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

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

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

    # Create branches
    X_C3 = Transformer2W(bus_from=POI,
                         bus_to=B_MV_M32,
                         name="X_C3",
                         template=SS)
    grid.add_branch(X_C3)

    X_M32 = Transformer2W(bus_from=B_MV_M32,
                          bus_to=B_LV_M32,
                          name="X_M32",
                          template=PM)
    grid.add_branch(X_M32)

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

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

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

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

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

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

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

    print("Branches:")
    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, 1)}")
        print(f"   G = {round(b.G, 4)} pu")
        print(f"   B = {round(b.B, 4)} pu")
    print()

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

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

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

    assert equal