class MMCC:
    """ Simulation object tasked with conducting the MMCC system """
    def run(self, total_servers: int, total_arrival: int) -> None:
        """ Begin the simulation of a MMCC system. Process the information until
        termination criteria is meet.

        Params:
            - total_servers :: The number of servers that can handle clients at 
                               any one instance.
            - total_arrival :: The total number of clients that can be handled
                               within the simulation.
        """

        # Initialise the beginning parameters of the simulation
        self.servers = Servers(total_servers)  # Set up server handler
        self.events = EventHandler()  # Set up the event handler

        startingEvent = Event("arrival", 0)  # Construct the first event object
        startingEvent.departure_time -= startingEvent.arrival_time  # Reset times
        startingEvent.arrival_time = 0  # Reset times

        self.events.add(startingEvent)  # Create the first event

        # Begin iteration of events, record arrivals for checking
        self.num_arrival = 0
        while (self.num_arrival < total_arrival):

            # Collect next event from the event handler
            currentEvent = self.events.next()
            # Update simulation time
            self.sim_time = currentEvent.time()

            if currentEvent.type == "arrival":
                # Arrival event received
                self.num_arrival += 1  # Record number of arrivals

                # Create new arrival event
                self.events.add(Event("arrival", currentEvent.time()))

                # Check if any server is available
                if not self.servers.isFree():
                    self.events.block(
                        currentEvent)  # Arriving client is blocked
                    continue

                # Begin serving the client.
                currentEvent.servedBy(self.servers.allocate())

                # All event handler to manage departure
                self.events.add(currentEvent)

            else:
                # Departure event received
                self.servers.deallocate(
                    currentEvent.servedBy())  # Free the server
                self.events.depart(currentEvent)  # Record departure

    def blockingProbability(self) -> float:
        """ Calculate the blocking probability for the previous simulation run.
        
        Returns:
            - float :: Probability of blocking 
        """
        return len(self.events.blocked) / self.num_arrival

    def serverUtilisation(self) -> float:
        """ Calculate the server utilisation for the previous simulation run.
        
        Returns:
            - float :: Server utilisation value
        """
        return sum([e.serviceTime()
                    for e in self.events.departed]) / self.sim_time

    def report(self) -> None:
        """ Display the results of the simulation is a readible fashion. """

        print("\tEvents Handled ::")
        print("\t\tArrival:", self.num_arrival)
        incomplete = self.num_arrival - (len(self.events.departed) +
                                         len(self.events.blocked))
        print("\t\tIncomplete events:", incomplete)
        print("\t\tDeparture:", len(self.events.departed))
        print("\t\tBlocked:", len(self.events.blocked))

        print("\tBlocking rate:", self.blockingProbability())
        print("\tServer Utilisation:", self.serverUtilisation())
Example #2
0
class MMCC:
    """
    Class to simulate M/M/C/C system
    """
    def run(self, server_number: int, arrival_total: int):
        """
        Run simulation with specified parameters
        :param server_number: Number of servers
        :param arrival_total: Number of events
        """

        # Initialise Servers and EventHandler
        self.servers = Servers(server_number)
        self.events = EventHandler()

        # Create and add initial event
        starting_event = Event("arrival", 0)
        starting_event.departure_time -= starting_event.arrival_time
        starting_event.arrival_time = 0
        self.events.add(starting_event)

        # Run simulation until number of events handled
        self.arrival_number = 0

        while (self.arrival_number < arrival_total):

            # Iterate to next event and update simulation time
            current_event = self.events.next()
            self.simulation_time = current_event.time()

            # If arrival, update counter and add to appropriate list
            if current_event.event_type == "arrival":
                self.arrival_number += 1
                self.events.add(Event("arrival", current_event.time()))

                # If no servers free, block event
                if not self.servers.is_free():
                    self.events.block(current_event)
                    continue

                # Assign server to event
                current_event.served_by(self.servers.allocate())
                self.events.add(current_event)

            # If departure, free server and depart
            else:
                self.servers.deallocate(current_event.served_by())
                self.events.depart(current_event)

    def blocking_probability(self) -> float:
        """
        Obtain blocking probability of previous run
        :return: Blocking probability
        """
        return len(self.events.blocked) / self.arrival_number

    def server_utilisation(self) -> float:
        """
        Obtain server utilisation of previous run
        :return: Server utilisation
        """
        return sum([e.service_time()
                    for e in self.events.departed]) / self.simulation_time