Esempio n. 1
0
 def pause(self) -> None:
     """
     Pauses the simulation if it's running.
     """
     assert self.state != SimulationState.not_started  # make sure the simulation has actually been started.
     self.state = SimulationState.paused
     log(SIMULATION_LOGGING, f"Pausing the simulation.")
Esempio n. 2
0
 def shutdown(self) -> None:
     """
     Shuts down the simulation.
     """
     log(SIMULATION_LOGGING, f"Simulation {self.name} shutting down.")
     self.__send_event(SimulationShutdownEvent())
     self.state = SimulationState.shutting_down
Esempio n. 3
0
    def run(self) -> None:
        """
        Causes the simulation thread to run.  This could be called from Simulation.start().
        """
        # Make sure this doesn't get called if the simulation is shutting down.
        if self.state == SimulationState.shutting_down:
            return

        log(SIMULATION_LOGGING, f"Simulation {self.name} starting.")

        self.__send_event(SimulationStartupEvent())
        self.state = SimulationState.paused

        # Keep running until shutting down.  Note that this is not a deamon, so shutdowns can be abrupt.
        while self.state != SimulationState.shutting_down:
            # If the state is not running, then sleep for a second and see if that changes.
            if self.state != SimulationState.running:
                time.sleep(0.05)
            else:  # simulation is running, see if it should step.
                if self.max_time > 0 and (self._previous_time >=
                                          self.max_time):
                    self.shutdown()

                if self.__steps_to_advance == Simulation.ADVANCE_UNLIMITED:
                    self.step()
                elif self.__steps_to_advance > 0:
                    self.step()
                    self.__steps_to_advance -= 1
                else:  # no time to advance, so pause until time to advance.
                    time.sleep(0.05)
Esempio n. 4
0
 def __send_event(self, event) -> None:
     """
     Sends the given event to interested entities.
     :param event: The event to send.
     """
     log(
         EVENT_LOGGING,
         f"sending event {event.name} at sim time {event.sim_time}: {event}"
     )
     event.sim_time = self._current_time
     self._event_mediator.send_event(event=event)
Esempio n. 5
0
    def remove_entity(self, entity) -> None:
        """
        Removes and entity from the simulation and informs other entities.  Note that any entities
        holding a reference to this entity should remove the entity.
        :param Entity entity: The entity to remove.
        """
        log(ENTITY_LOGGING,
            f"Removing entity type {entity.name} with GUID {entity.guid}")

        self._entities.pop(entity.guid)
        self._event_mediator.deregister_entity(entity=entity)
        self._previous_state.pop(entity.guid)

        self.__send_event(EntityDestroyedEvent(entity=RemoteEntity(entity)))
Esempio n. 6
0
    def test_list_logging(self):
        """Tests logging with the list logger."""
        ll1 = ListLogger("topic1")
        ll2 = ListLogger(["topic2", "topic3"])
        ll3 = ListLogger("topic3")

        log(topic="topic1", message="message 1")
        log(topic="topic2", message="message 2")
        log(topic="topic3", message="message 3")
        log(topic="topic4", message="message 4")

        self.assertEqual(1, len(ll1))
        self.assertEqual(2, len(ll2))
        self.assertEqual(1, len(ll3))

        self.assertTrue("] topic1: message 1" in ll1.get_log_messages()[0])

        self.assertTrue("] topic2: message 2" in ll2.get_log_messages()[0])
        self.assertTrue("] topic3: message 3" in ll2.get_log_messages()[1])

        self.assertTrue("] topic3: message 3" in ll3.get_log_messages()[0])

        ll1.clear()
        self.assertEqual(0, len(ll1))
        self.assertEqual(2, len(ll2))
Esempio n. 7
0
    def advance(self, steps=ADVANCE_UNLIMITED) -> None:
        """
        Manually advances time by the number of steps specified.
        :param int steps: The number of steps to advance by.  If not specified runs unlimited.
        """
        assert steps > 0 or steps == Simulation.ADVANCE_UNLIMITED

        if steps > 0:
            log(SIMULATION_LOGGING, f"Advancing the simulation {steps} times.")
        else:
            log(SIMULATION_LOGGING,
                f"Advancing the simulation until shutdown.")

        self.__steps_to_advance = steps
        self.state = SimulationState.running
        print(f"simulation state is {self.state}")
Esempio n. 8
0
    def add_entity(self, entity) -> None:
        """
        Adds a new entity to the simulation.  Note that this is not thread safe.
        :param Entity entity: The entity to add.
        """
        # Add the entity to the list along with the handlers and then generate an entity created event.

        # The simulation sets the guids.
        entity.guid = get_uuid()
        log(ENTITY_LOGGING,
            f"Adding entity type {entity.name} with GUID {entity.guid}")

        self._entities[entity.guid] = entity
        self.queue_event(EntityCreatedEvent(entity=RemoteEntity(entity)))

        self._event_mediator.register_entity(entity=entity)

        self._previous_state[entity.guid] = EntityState(entity=entity)
Esempio n. 9
0
    def test_file_logger(self):
        """Tests logging to a file."""
        test_file = "test.log"
        fl = FileLogger(topics="topic1", filename=test_file)

        self.assertFalse(os.path.exists(test_file))

        log(topic="topic1", message="message 1")
        log(topic="topic1", message="message 2")

        self.assertTrue(os.path.exists(test_file))

        fl.close()

        with open(test_file, "r") as f:
            line = f.readline()
            self.assertTrue("] topic1: message 1" in line)
            line = f.readline()
            self.assertTrue("] topic1: message 2" in line)

        os.remove(test_file)
Esempio n. 10
0
    def step(self) -> None:
        """
        Causes the simulation to advance a single step.
        """
        start_cycle_clock_time = time.time()

        self._current_time = self._event_queue.next_time()

        # If there are no events in the queue, cycle one in any case.
        previous_time = self._previous_time
        if not self._current_time:  # this causes the same behavior for time stepped and jumped simulations.
            self._current_time = self._previous_time + 1
        self._previous_time = self._current_time

        log(
            SIMULATION_LOGGING,
            f"Advancing the simulation from {previous_time} to {self._current_time}."
        )

        # send a time update event for the next time.
        self.__send_event(
            NewTimeEvent(previous_time=previous_time,
                         new_time=self._current_time))
        # also notify the views to update.
        self._update_views(previous_time=previous_time,
                           new_time=self._current_time)

        # send all of the events for the current time.
        while self._event_queue.next_time() == self._current_time:
            # send all events from the queue to interested simulation entities.
            self.__send_event(self._event_queue.next())

        self.__send_change_events()

        elapsed_time = time.time() - start_cycle_clock_time
        while elapsed_time < self.minimum_step_time:
            time.sleep(0.05)
            elapsed_time = time.time() - start_cycle_clock_time
Esempio n. 11
0
    def send_event(self, event) -> None:
        """
        Handles the event by sending to all of the entities that registered it.
        :param Event event:  The event to handle.
        """
        if event.name == ENTITY_CREATED_EVENT:
            entity_list = self._entity_created_interest.get(
                event.entity.name, None)
        elif event.name == ENTITY_CHANGED_EVENT:
            entity_list = self._entity_changed_interest.get(
                event.entity.name, None)
        elif event.name == ENTITY_DESTROYED_EVENT:
            entity_list = self._entity_destroyed_interest.get(
                event.entity.name, None)
        else:
            entity_list = self._named_event_interest.get(event.name, None)

        if entity_list:
            for e in entity_list:
                log(
                    EVENT_LOGGING,
                    f"sending event {event.name} to {e.guid} at time {event.sim_time}:  {event.__dict__}"
                )
                e.handle_event(event=event)