0

I created the class EventList as an extension of the native list class in python. The problem I am having is that when I create an instance of the class, those instances are not creating new objects.

If you run the code below (which is complete), you'll observe that the content of the class instance elm1, gets overwritten by elm2, and both by elm3. (see the bottom of the code)

What do I need to change in the class EventList to correctly extend the class list such that every instance of EventList is new and independent?

from numpy.random import exponential, normal
from enum import Enum
from matplotlib import pyplot as plt


class States(int):
    Failed = 0
    Working = 1
    Maintenance = 2


class ElementTypes(Enum):
    Generic = 100
    Bus = 0
    Gen = 1
    Branch = 2
    Switch = 3
    Load = 4
    Grid = 5


class EventList(list):

    def add(self, event):
        self.append(event)

    def size(self):
        return len(self)

    def remove_redundant(self):
        # Remove the redundant events
        n = self.size()
        i = n-2
        while i > 0:
            if self[i][1] == self[i-1][1]:
                del self[i]
            i -= 1

    def merge_events(self, event_list, remove_redundant=True):
        """
        Add another list of events to this list.
        It can also remove the redundant events
        """
        self += event_list
        # print(self)
        self.sort()
        # print(self)
        # set the final event state as the previous event state
        n = self.size()
        self[n-1] = (self[n-1][0], self[n-2][1])
        # print(self)
        # remove redundant events
        if remove_redundant:
            self.remove_redundant()

    def merge_series_component_events(self, events_list):
        """
        Composes the series events list of a number of components

        Args:
            events_list: list of EventList objects corresponding to a number of components in series
        """
        c_num = len(events_list)  # number of components

        for k in range(c_num):
            for evt in events_list[k]:
                if evt[1] == States.Failed:
                    self.add(evt)  # a down-event is always added
                else:
                    all_working = True
                    i = 0
                    while i < c_num and all_working:
                        t = evt[0]
                        if not events_list[i].state_at(t + 1e-6):
                            all_working = False
                        i += 1

                    # up-events are added only if all the components are up for the examined up-event time
                    if all_working:
                        self.add(evt)

        self.sort()
        self.remove_redundant()

    def state_at(self, t):
        """
        Returns the state at any given time
        """
        n = self.size()
        s0 = self[0]
        sn = self[n-1]

        if t <= s0[0]:
            return s0[1]

        elif t >= sn[0]:
            return sn[1]

        else:  # look for it
            for i in range(1, n):
                if t >= self[i-1][0] and t <= self[i][0]:
                    # t is found
                    return self[i-1][1]

    def plot(self, ylab=''):
        n = len(self)
        for i in range(n-1):
            #print(str(self[i][0]) + ", " + str(self[i+1][0]) + '->' + str(str(self[i][1])))
            plt.plot((self[i][0], self[i+1][0]), (self[i][1], self[i][1]), 'k-')
            plt.plot((self[i][0], self[i][0]), (0, 1), 'k-')
            plt.plot((self[i+1][0], self[i+1][0]), (0, 1), 'k-')
            if self[i][1] == States.Failed:
                color = 'r'
            else:
                color = 'g'
            plt.axvspan(ymin=0, ymax=1, xmin=self[i][0], xmax=self[i+1][0], facecolor=color, alpha=0.5)
        plt.ylabel(ylab)
        plt.xlim((0, self[n-1][0]+10))

class Element(object):
    """
    This class represents the system element.
    In a graph it is given by a node element, regardless of the element's nature
    """

    # element name
    name = ''

    type = None

    # flag denoting if the element is active or not. If not active it counts as if it was failed
    is_on_line = True

    # Current state of the element given by the possible states enumerated by the class States
    current_state = States.Working

    # Weight of the element, in an electrical grid, this value can be the element impedance
    weight = 0

    # mean time to failure
    MTTF = 0

    # mean time to repair
    MTTR = 0

    # deviation from time to repair, relevant when using normal laws for the repair time
    DEVTR = 1

    use_normal_recovery_law = False

    # list of tuples representing an event
    # each tuple if of the form: (time, state)
    events = EventList()

    # Time based maintenance event list
    time_based_maintenance_events = EventList()

    def __init__(self, name, element_type, MTTF, MTTR, DEVTR=None, state=States.Working, weight=0, online=True):
        """
        Class constructor

        Args:
            name = name of the element

            element_type = type of element given by the class ElementTypes

            MTTF = mean time to failure

            MTTR = mean time to repair

            DEVTR = deviation from time to repair

            state = initial state of the element, given by the possible states enumerated by the class States

            weight = possible weight of the element

            online = flag denoting if the element is active or not.
        """

        self.name = name
        self.type = element_type
        self.MTTF = MTTF
        self.MTTR = MTTR
        self.DEVTR = DEVTR
        self.current_state = state
        self.weight = weight
        self.is_on_line = online

        if DEVTR is not None:
            self.use_normal_recovery_law = True

    def generate_states(self, simulation_time):
        """
        Generate the system events randomly.

        Once failed, a component is accounted to be replaced (as good as new)

        Args:

            simulation_time: simulation time limit (typically the expected life of the system)
        """
        events = EventList()

        self.events.clear()
        # append the initial state event
        self.events.append((0, self.current_state * self.is_on_line))
        # append the last state event
        self.events.append((simulation_time, -1 * self.is_on_line))

        mttf = self.MTTF
        mttr = self.MTTR

        # generate failure-repair events
        t = 0
        last_state = self.current_state
        while t < simulation_time:  # simulate failures and recoveries until the time is reached
            if (not last_state) == States.Failed:  # if the state to set is failed, get the time of the failure
                t_evt = t + exponential(mttf)
                last_state = States.Failed
            else:  # the element is failed, calculate its recovery time
                if self.use_normal_recovery_law:
                    t_evt = t + normal(mttr, self.DEVTR)
                else:
                    t_evt = t + exponential(mttr)
                last_state = States.Working

            if t_evt <= simulation_time:
                events.append((t_evt, last_state * self.is_on_line))
            t = t_evt


        self.events.merge_events(events + self.time_based_maintenance_events)


if __name__ == '__main__':
    simulation_time = 172000
    name = 'element'
    type = ElementTypes.Generic
    MTTF = 36402.64
    MTTR = 6500.30

    plt.subplot(4, 1, 1)
    elm1 = Element(name, type, MTTF, MTTR)
    elm1.generate_states(simulation_time)
    print(elm1.events)
    elm1.events.plot()

    plt.subplot(4, 1, 2)
    elm2 = Element(name, type, MTTF, MTTR)
    elm2.generate_states(simulation_time)
    print(elm2.events)
    elm2.events.plot()

    plt.subplot(4, 1, 3)
    elm3 = Element(name, type, MTTF, MTTR)
    elm3.generate_states(simulation_time)
    print(elm3.events)
    elm3.events.plot()

    print('after')
    print(elm1.events)
    print(elm2.events)
    print(elm3.events)

    plt._show()
    input()
Santi Peñate-Vera
  • 1,053
  • 4
  • 33
  • 68

0 Answers0