Пример #1
0
def _classify_branch(from_bus, to_bus, line_id):
    if isinstance(from_bus, component_busdetails.BusDetails):
        if from_bus.base_voltage > 100:
            if from_bus.name[:3] == 'MF.' and to_bus.name[:3] == 'MF.':
                return component.Cable
            else:
                from_bus = from_bus.number
                to_bus = to_bus.number
        else:
            return component.Line

    if MonsterPssPy.busdat(from_bus, 'KV')[1] > 100.0:
        length = MonsterPssPy.brndat(from_bus, to_bus, line_id, 'LENGTH')
        charging = MonsterPssPy.brndat(from_bus, to_bus, line_id, 'CHARG')
        from_bus_name = MonsterPssPy.notona(from_bus)
        to_bus_name = MonsterPssPy.notona(to_bus)
        if from_bus_name[:3] == 'MF.' and to_bus_name[:3] == 'MF.':
            return component.Cable

        if length > 0.0:
            normed_charging = charging / length
        else:
            normed_charging = 0.0
        tol = 0.005
        if normed_charging > tol:
            return component.Cable
        else:
            return component.Line
    else:
        return component.Line
Пример #2
0
    def _change_status(self, from_status, to_status):
        """ Take a two winding transformer out of service in the PSSE model.

        This function uses the psspy API to manually set a line in out
        of service. It manipulates the 'status' argument of the
        :func:`psspy.two_winding_data_3` function and sets it to 0.

        Warnings
        ========
        If the line is a part of a multi-line section a waring is issued.
        In this case the same line might be tripped more than once.

        Raises
        ======
        A psspy.PsseException is rasied if one tries to trip an already
        disconnected line.

        """

        if self.status() == from_status:
            MonsterPssPy.three_wnd_imped_chng(
                self.from_bus.number,
                self.to_bus.number,
                self.other_bus.number,
                self.identificator,
                [MonsterPssPy._i()] * 7 + [to_status.get_index()],
                []
            )
Пример #3
0
 def _change_status(self, from_status, to_status):
     if self.status() == from_status:
         MonsterPssPy.two_winding_data(
             self.from_bus.number,
             self.to_bus.number,
             self.identificator,
             [to_status.get_index()],
             []
         )
Пример #4
0
def get_loads(sid, bus_dict):
    flag = IncludeStatus.NotAddStepAndNotInService.value
    (bus_numbers,) = MonsterPssPy.aloadint(sid, flag=flag, string='NUMBER')
    load_ids = [
        name.strip() for name in MonsterPssPy.aloadchar(sid, flag=flag, string='ID')[0]
    ]
    load_dict = dict()
    for bus_number, load_id in zip(bus_numbers, load_ids):
        load = component.Load(
            load_bus=bus_dict[bus_number].from_bus,
            load_id=load_id
        )
        load_dict[load.get_sorted_short_tuple()] = load
    return load_dict
Пример #5
0
 def get_real_power(self):
     buses = collections.deque(self.get_busnumbers())
     pct = -1
     for i in range(3):
         buses.rotate(1)
         pct_wnd = MonsterPssPy.wnddat(
             buses[0], buses[1], buses[2], self.identificator, 'PCTRTA'
         )
         if pct_wnd > pct:
             pct = pct_wnd
             n_rotate = i + 1
     buses.rotate(n_rotate)
     return MonsterPssPy.wnddt2(
         buses[0], buses[1], buses[2], self.identificator, 'FLOW'
     ).real
Пример #6
0
 def _change_status(self, from_status, to_status):
     if self.status() == from_status and not self.msl_component:
         if self.msl_lines:
             MonsterPssPy.multi_section_line_edit(
                 self.from_bus.number,
                 self.to_bus.number,
                 self.identificator,
                 [to_status.get_index()]
             )
         else:
             MonsterPssPy.branch_data(
                 self.from_bus.number,
                 self.to_bus.number,
                 self.identificator,
                 [to_status.get_index()]
             )
Пример #7
0
 def _flow(self, *args):
     try:
         s = MonsterPssPy.brnflo(*args)
     except PsseBrnfloException as e:
         if e._ierr == 3:
             return []
         raise
     return s
Пример #8
0
 def set_rx(self):
     buses = collections.deque(self.get_busnumbers(False))
     self.rx = []
     for i in range(3):
         self.rx.append(
             MonsterPssPy.wnddt2(buses[0], buses[1], buses[2], self.identificator, 'RX')
         )
         buses.rotate(-1)
Пример #9
0
 def set_rate(self, file_path):
     buses = collections.deque(self.get_busnumbers(False))
     self._rate[file_path] = []
     for i in range(3):
         self._rate[file_path].append(
             MonsterPssPy.wnddat(buses[0], buses[1], buses[2], self.identificator, RATE_NAME)
         )
         buses.rotate(-1)
Пример #10
0
def get_lines(sid, bus_dict):
    """ Extract line data from the PSSE case

    Parameters
    ==========
    include_only_in_service: Bool (optional=True)
        whether to include only in service line or not

    """
    flag = IncludeStatus.NotAddStepAndNotInService.value
    ties = 3
    (from_buses, to_buses) = MonsterPssPy.abrnint(
        sid, flag=flag, ties=ties, string=['FROMNUMBER', 'TONUMBER']
    )

    line_ids = [
        name.strip() for name in MonsterPssPy.abrnchar(
            sid, flag=flag, ties=ties, string='ID'
        )[0]
    ]

    (line_length, rates, ) = MonsterPssPy.abrnreal(
        sid, flag=flag, ties=ties, string=['LENGTH', RATE_NAME]
    )

    rxes = MonsterPssPy.abrncplx(
        sid, flag=flag, ties=ties, string='RX'
    )

    line_dict = dict()
    for from_bus, to_bus, line_id, length, rate_c, rx in zip(
            from_buses, to_buses, line_ids, line_length, rates, rxes[0]
    ):
        comp_func = _classify_branch(from_bus, to_bus, line_id)
        line = comp_func(
            from_bus=bus_dict[from_bus].from_bus,
            to_bus=bus_dict[to_bus].from_bus,
            identificator=line_id,
            length=length,
            rate_c=rate_c,
            rx=rx,
        )
        if not (line.from_bus.dummy or line.to_bus.dummy):
            line_dict[line.get_sorted_short_tuple()] = line
    return line_dict
Пример #11
0
    def _change_status(self, from_status, to_status):

        # Do we need to scale production on generators due to droop?
        if len(self._scale_area):
            scale_area = self._scale_area
        else:
            scale_area = MonsterPssPy.aareaint(-1, 1, 'NUMBER')[0]

        # Get total load
        s_total = self.get_pq(to_status)

        if self.status() == to_status:
            if to_status == ComponentStatus.off:
                raise PsseBaseException('Machine component already out of service.', None)
            else:
                raise PsseBaseException('Machine component already in service.', None)

        try:
            MonsterPssPy.machine_data(
                self.from_bus.number, self.identificator,
                [ComponentStatus.off.get_index()]
            )
            # Define SID for scale area
            sid = 2
            MonsterPssPy.bsys(sid, numarea=len(scale_area), areas=scale_area)
            # Scale with (3) incremental powers, (0) ignore machine
            # power limits, (0) No Q changes and (2) only type 2 and 3
            # buses.
            MonsterPssPy.scal(sid, 0, 0, [0, 0, 0, 2, 0], [0.0, s_total.real] + [0.0] * 5)

        except PsseBaseException:
            raise
Пример #12
0
    def flow_amp_rate(self):
        args = self.get_busnumbers(True)
        s = self._flow(*args)
        if s:
            s_rate = self.get_rate()
            irate_1 = MonsterPssPy.brnmsc(*args, string='PCTRTA')
            irate_2 = MonsterPssPy.brnmsc(args[1],
                                          args[0],
                                          args[2],
                                          string='PCTRTA')

            s_rate *= max(irate_1, irate_2) / 100.0
            if s_rate < abs(s.real):
                return complex(s.real, 0)
            else:
                return complex(s.real, math.sqrt(s_rate**2 - s.real**2))
        else:
            return s
Пример #13
0
 def status(self):
     _status = MonsterPssPy.tr3int(
         self.from_bus.number,
         self.to_bus.number,
         self.other_bus.number,
         self.identificator,
         'STATUS'
     )
     return self._component_status(_status)
Пример #14
0
 def status(self):
     try:
         _status = MonsterPssPy.macint(self.from_bus.number, self.identificator, 'STATUS')
     except PsseMacintException as e:
         if e._ierr == 4:
             _status = e._value
         else:
             raise
     return self._component_status(_status)
Пример #15
0
 def _flow(self, *branch_buses_and_id):
     try:
         s = MonsterPssPy.wnddt2(*branch_buses_and_id, string='FLOW')
     except PsseWnddtException as e:
         if e._ierr == 7:
             s = []
         else:
             raise
     return s
Пример #16
0
    def get_p_lim(self):
        """ Get pmin and pmax as a tuple (pmin, pmax)

        """
        try:
            pmin = MonsterPssPy.macdat(self.from_bus.number, self.identificator, 'PMIN')
        except PsseMacdatdException as e:
            if e._ierr == 4:  # machine offline. ignore error and continue
                pmin = e._value
            else:
                raise e
        try:
            pmax = MonsterPssPy.macdat(self.from_bus.number, self.identificator, 'PMAX')
        except PsseMacdatdException as e:
            if e._ierr == 4:  # machine offline. ignore error and continue
                pmax = e._value
            else:
                raise e
        return (pmin, pmax)
Пример #17
0
def get_machines(sid, bus_dict):
    """ Extract machine data from the PSSE case

    Parameters
    ==========
    include_only_in_service: Bool (optional=True)
        whether to include only in service machines or not

    """
    flag = IncludeStatus.NotAddStepAndNotInService.value
    bus_numbers = MonsterPssPy.amachint(sid, flag=flag, string='NUMBER')[0]

    machine_ids = [
        name.strip() for name in MonsterPssPy.amachchar(sid, flag=flag, string='ID')[0]
    ]
    machine_dict = dict()
    for bus_number, machine_id in zip(bus_numbers, machine_ids):
        machine = component.Machine(bus_dict[bus_number].from_bus, machine_id)
        machine_dict[machine.get_sorted_short_tuple()] = machine
    return machine_dict
Пример #18
0
    def get_pq(self, to_status=ComponentStatus.off):
        """ Get PQ actual machine power output from case as a complex value

        """
        try:
            s_total = MonsterPssPy.macdt2(self.from_bus.number, self.identificator, 'PQ')
        except PsseMacdatdException as e:
            if to_status == ComponentStatus.on and e._ierr == 4:
                s_total = -e._value
            else:
                raise
        return s_total
Пример #19
0
    def set_p(self, p):
        """Set active power output of machine in case as MW

        """
        try:
            return MonsterPssPy.machine_chng(
                self.from_bus.number,
                self.identificator,
                realar1=p,
            )
        except PsseBaseException:
            raise
Пример #20
0
    def set_pq(self, cmplx_pq):
        """Set PQ value in case as actual MVA load

        """
        try:
            return MonsterPssPy.load_chng(
                self.from_bus.number,
                self.identificator,
                realar1=cmplx_pq.real,
                realar2=cmplx_pq.imag
            )
        except PsseBaseException:
            raise
Пример #21
0
def get_buses(sid):
    """ Extract bus data from the PSSE case

    Parameters
    ==========
    include_only_in_service: Bool (optional=True)
        whether to include only in service buses or not

    """
    flag = IncludeStatus.NotAddStepAndNotInService.value

    bus_names = [
        name.strip() for name in MonsterPssPy.abuschar(
            sid, flag=flag, string='NAME'
        )[0]
    ]

    (bus_voltages,) = MonsterPssPy.abusreal(sid, flag=flag, string='BASE')
    (bus_numbers, bus_areas, bus_zones, bus_dummies, bus_types) = MonsterPssPy.abusint(
        sid, flag=flag, string=['NUMBER', 'AREA', 'ZONE', 'DUMMY', 'TYPE']
    )
    bus_dummies = [bool(bus_dummy) for bus_dummy in bus_dummies]
    bus_dict = dict()
    for bus_number, bus_name, bus_voltage, bus_area, bus_zone, bus_dummy, bus_type in \
            zip(bus_numbers, bus_names, bus_voltages, bus_areas, bus_zones, bus_dummies, bus_types):
        bus_details = component_busdetails.BusDetails(
            bus_number=bus_number,
            bus_name=bus_name,
            base_voltage=bus_voltage,
            areanum=bus_area,
            zonenum=bus_zone,
            dummy=bus_dummy,
            bus_type=bus_type
        )
        bus = component_base.Bus(from_bus=bus_details)
        bus_dict[bus_number] = bus
    return bus_dict
Пример #22
0
def get_two_winding_transformers(sid, bus_dict):
    """ Extract two winding transformer data from the PSSE case

    Parameters
    ==========
    include_only_in_service: Bool (optional=True)
        whether to include only in service line or not

    """
    flag = IncludeStatus.NotAddStepAndNotInService.value + 4
    ties = 3
    (from_buses, to_buses) = MonsterPssPy.abrnint(
        sid, flag=flag, ties=ties, string=['FROMNUMBER', 'TONUMBER']
    )
    two_winding_transformer_id = [
        name.strip() for name in MonsterPssPy.abrnchar(
            sid, flag=flag, ties=ties, string='ID'
        )[0]
    ]
    rxes = MonsterPssPy.atrncplx(
        sid, ties=ties, flag=2, string='RXACT'
    )

    two_winding_transformer_dict = dict()
    for from_bus, to_bus, two_winding_transformer_id, rx in zip(
            from_buses, to_buses, two_winding_transformer_id, rxes[0]
    ):
        two_winding_transformer = component.TwoWindingTransformer(
            from_bus=bus_dict[from_bus].from_bus,
            to_bus=bus_dict[to_bus].from_bus,
            identificator=two_winding_transformer_id,
            rx=rx
        )
        two_winding_transformer_dict[
            two_winding_transformer.get_sorted_short_tuple()
        ] = two_winding_transformer
    return two_winding_transformer_dict
Пример #23
0
 def flow_amp_rate(self):
     buses = collections.deque(self.get_busnumbers(False))
     flow = []
     rate_a = self.get_rate()
     for i in range(3):
         branch_buses_and_id = [buses[0], buses[1], buses[2], self.identificator]
         s = self._flow(branch_buses_and_id)
         if s:
             i_rate = MonsterPssPy.wnddat(*branch_buses_and_id, string='PCTRTA')
             s_rate = rate_a[i] * i_rate / 100.0
             if s_rate < abs(s.real):
                 flow.append(complex(s.real, 0))
             else:
                 flow.append(complex(s.real, math.sqrt(s_rate**2 - s.real**2)))
         buses.rotate(-1)
     return flow
Пример #24
0
def get_msl_components(sid, bus_dict, line_dict):
    msl_parents = dict()
    msl_children = dict()
    flag = IncludeStatus.NotAddStepAndNotInService.value
    for from_bus, to_bus, identificator in MonsterPssPy.find_multisections(sid, flag=flag):
        try:
            MonsterPssPy.inimsl(from_bus, to_bus, identificator)
            msl_lines = []
            line = component.Line(
                from_bus=bus_dict[from_bus].from_bus,
                to_bus=bus_dict[to_bus].from_bus,
                identificator=identificator.strip(),
                length=0,
                rate_a=-1,
                msl_lines=msl_lines
            )
            msl_parents[line.get_sorted_short_tuple()] = line
            while True:
                try:
                    ibus, jbus, ickt = MonsterPssPy.nxtmsl()
                    from_bus = bus_dict[ibus].from_bus
                    to_bus = bus_dict[jbus].from_bus
                    component_func = _classify_branch(from_bus, to_bus, ickt)
                    elem_rate_a = MonsterPssPy.brndat(
                        ibus=ibus, jbus=jbus, ickt=ickt, string=RATE_NAME)
                    elem_length = MonsterPssPy.brndat(
                        ibus=ibus, jbus=jbus, ickt=ickt, string='LENGTH')
                    rx = MonsterPssPy.brndt2(
                        ibus=ibus, jbus=jbus, ickt=ickt, string='RX')
                    line = component_func(
                        from_bus=from_bus,
                        to_bus=to_bus,
                        identificator=ickt.strip(),
                        length=elem_length,
                        rate_a=elem_rate_a,
                        rx=rx,
                        msl_component=True
                    )
                    msl_lines.append(line)
                    msl_children[line.get_sorted_short_tuple()] = line
                except PsseNxtMslException:
                    break
        except PsseIniMslException:
            pass
    return msl_parents, msl_children
Пример #25
0
    def _change_status(self, from_status, to_status):
        # Do we need to scale production on generators due to droop?
        if len(self._scale_area):
            scale_area = self._scale_area
        else:
            scale_area = MonsterPssPy.aareaint(-1, 1, 'NUMBER')[0]

        # Get total load
        try:
            s_total = MonsterPssPy.loddt2(self.from_bus.number, self.identificator, 'TOTAL', 'ACT')
        except PsseLoddtException as e:
            if to_status == ComponentStatus.on and e._ierr == 4:
                s_total = -e._value
            else:
                raise

        if self.status() == to_status:
            if to_status == ComponentStatus.off:
                raise PsseBaseException('Load component already out of service.', None)
            else:
                raise PsseBaseException('Load component already in service.', None)
        try:
            MonsterPssPy.load_chng(
                self.from_bus.number, self.identificator,
                intgar1=to_status.get_index()
            )
            # Define SID for scale area
            sid = 2
            MonsterPssPy.bsys(sid, numarea=len(scale_area), areas=scale_area)
            # Scale with (3) incremental powers, (0) ignore machine
            # power limits, (0) No Q changes and (2) only type 2 and 3
            # buses.
            MonsterPssPy.scal(sid, 0, 0, [0, 0, 0, 2, 0], [0.0, -s_total.real] + [0.0] * 5)

        except PsseBaseException:
            raise
Пример #26
0
    def sensitivity(self,
                    mainsys,
                    dfxfile,
                    netmod='ac',
                    brnflowtyp='amp',
                    transfertyp='export',
                    dispmod=2,
                    toln=0.3):
        busnr = self.get_busnumbers(False)
        if self._component_type == ComponentTypeEnum.ThreeWindingTransformerComponent:
            n = 3
        else:
            n = 1
            busnr.append(0)

        busnr = collections.deque(busnr)
        sens = []
        for _ in range(n):
            sens.append(
                MonsterPssPy.sensitivity_flow_to_mw(busnr[0],
                                                    busnr[1],
                                                    mainsys,
                                                    dfxfile,
                                                    busnr[2],
                                                    self.identificator,
                                                    netmod=netmod,
                                                    brnflowtyp=brnflowtyp,
                                                    transfertyp=transfertyp,
                                                    dispmod=dispmod,
                                                    toln=toln))
            if n == 3:
                busnr.rotate(-1)
            else:
                sens = sens[0]

        return sens
Пример #27
0
def get_full_topology(case_path_dict):
    MonsterPssPy.case(case_path_dict.values()[0])
    monster_topology = extract_components_from_case(
        case_path_dict
    )
    return monster_topology
Пример #28
0
 def set_rate(self, file_path):
     self._rate[file_path] = MonsterPssPy.brndat(*self.get_busnumbers(True),
                                                 string=RATE_NAME)
Пример #29
0
 def get_real_power(self):
     args = self.get_busnumbers(True) + ['P']
     return MonsterPssPy.brnmsc(*args)
Пример #30
0
 def status(self):
     status = MonsterPssPy.brnint(self.from_bus.number, self.to_bus.number,
                                  self.identificator, 'STATUS')
     return ComponentStatus.get_enum(status)