예제 #1
0
파일: core.py 프로젝트: bhenne/MoSP
 def __init__(self, geo, start_timestamp=None, rel_speed=None, seed=1, allow_dup=False):
     """Initialize the MOSP Simulation.
     
     @param geo: geo model for simulation, a mosp.geo.osm.OSMModel extending the mops.collide.World
     @param start_timestamp: time.time timestamp when simulation starts - used to calc DateTime of simlation out of simulation ticks.
     @param rel_speed: (SimPy) ratio simulation time over wallclock time; example: rel_speed=200 executes 200 units of simulation time in about one second
     @param seed: seed for simulation random generator
     @param allow_dup: allow duplicates? only one or multiple Simulations can be startet at once
     """
     SimulationRT.SimulationRT.__init__(self)
     assert allow_dup or osm.GLOBAL_SIM is None
     osm.GLOBAL_SIM = self
     self.initialize()           #  init SimPy.SimulationRT
     self.geo = geo              #: the geo-modell of the Simulation
     self.monitors = []          #: contains all Monitors of the Simulation
     self.rel_speed = rel_speed if rel_speed else 1
     self.start_timestamp = self.start_timestamp if start_timestamp else time.time()
     self.random = random.Random(seed)       #: central simulation-wide random generator
     self.next_person_id = 0                 #: the next id that will be given to a new person
     self.persons = group.PersonGroup()      #: stores simulated Persons
     self.removed_persons = {}               #: stores removed Persons for later use
     self.person_alarm_clock = PersonWakeUp('Omni-present person wake up alarm', self)   #: central Process for waking up Persons on pause
     self.messages = []      #: stores scheduled Calls of PersonGroups for execution as zombie's infect()
     group.Message.sim = self
     geo.initialize(self)        # load OSM data, load/calculate routing table and grid
예제 #2
0
파일: core.py 프로젝트: bhenne/MoSP
class Simulation(SimulationRT.SimulationRT):
    """A MOSP Simulation.
    
    Extends SimPy's SimulationRT (Simulation with Real Time Synchronization)
    to store MOSP specific data and implement specific methods.
    @author: F. Ludwig
    @author: P. Tute
    @author: B. Henne"""
    
    def __init__(self, geo, start_timestamp=None, rel_speed=None, seed=1, allow_dup=False):
        """Initialize the MOSP Simulation.
        
        @param geo: geo model for simulation, a mosp.geo.osm.OSMModel extending the mops.collide.World
        @param start_timestamp: time.time timestamp when simulation starts - used to calc DateTime of simlation out of simulation ticks.
        @param rel_speed: (SimPy) ratio simulation time over wallclock time; example: rel_speed=200 executes 200 units of simulation time in about one second
        @param seed: seed for simulation random generator
        @param allow_dup: allow duplicates? only one or multiple Simulations can be startet at once
        """
        SimulationRT.SimulationRT.__init__(self)
        assert allow_dup or osm.GLOBAL_SIM is None
        osm.GLOBAL_SIM = self
        self.initialize()           #  init SimPy.SimulationRT
        self.geo = geo              #: the geo-modell of the Simulation
        self.monitors = []          #: contains all Monitors of the Simulation
        self.rel_speed = rel_speed if rel_speed else 1
        self.start_timestamp = self.start_timestamp if start_timestamp else time.time()
        self.random = random.Random(seed)       #: central simulation-wide random generator
        self.next_person_id = 0                 #: the next id that will be given to a new person
        self.persons = group.PersonGroup()      #: stores simulated Persons
        self.removed_persons = {}               #: stores removed Persons for later use
        self.person_alarm_clock = PersonWakeUp('Omni-present person wake up alarm', self)   #: central Process for waking up Persons on pause
        self.messages = []      #: stores scheduled Calls of PersonGroups for execution as zombie's infect()
        group.Message.sim = self
        geo.initialize(self)        # load OSM data, load/calculate routing table and grid

    def add_monitor(self, monitor_cls, tick=1, **kwargs):
        """Add a Monitor to Simulation to produce any kind of output.
        @param monitor_cls: the monitor class from mops.monitors
        @param tick: new monitor will observe every tick tick
        @param kwargs: keyword parameters for monitor class instantiation
        @return: reference to new, added monitor instance
        """
        mon = monitor_cls('mon'+str(len(self.monitors)), self, tick, kwargs)
        self.monitors.append(mon)
        return mon

    def add_persons(self, pers_cls, n=1, monitor=None, args=None):
        """Add a Person to Simulation.
        @param pers_cls: the person class (inherited from mosp.core.Person)
        @param n: the number of new, added instances of pers_cls
        @param monitor: (list of) monitor(s) the person(s) shall be observed by
        @param args: dictionary of arguments for pers_cls instantiation
        """
        if not args:
            args = {}
        for i in xrange(n):
            seed = self.random.randrange(2**24) # must be >> number of persons!
            pers = pers_cls(self.next_person_id, self, random.Random(seed), **args)
            self.next_person_id += 1
            if monitor is not None:
                if isinstance(monitor, monitors.EmptyMonitor):
                    # a single monitor
                    monitor.append(pers)
                elif hasattr(monitor,'__iter__'):
                    # an iterable list of monitors
                    for mon in monitor:
                        mon.append(pers)
            self.activate(pers, pers.go(), 0)
            self.persons.add(pers)

    def get_person(self, id):
        """Find a person by its ID.

        @param: the ID of the person
        @return: the person or None, if the ID was not found

        """
        result = self.persons.filter(p_id=id)
        if len(result) == 1:
            return result.pop()
        else:
            return None

    def del_person(self, person):
        """Remove a person from the simulation.

        The person will be saved in self.removed_persons for later reference.
        @todo: try using Process.cancel() from SimPy (is broken atm and may stay broken...try again with new go)
        @todo: maybe remove person from monitors 
        @param person: the person to be removed. The person must have been added and must be active.
        """
        self.removed_persons[person.p_id] = person
        person.stop_actions(True)
        person.remove_from_sim = True
        self.persons.remove(person)
        
    def readd_person(self, id, changes={}):
        """Add a previously removed person to the simulation again.

        @param id: id of the removed person
        @type id: int
        @param changes: changes to be made when reinserting the person
        @type changes: dict with pairs of 'variable_name': value (variable_name in a string)
        """
        if id not in self.removed_persons:
            print 'Tried to re-add unknown person...ignored.'
            print id, type(id)
            print self.removed_persons
            return
        person = self.removed_persons[id]
        person.__dict__.update(changes)
        person.current_way.persons.append(person)
        person.current_coords = person.current_coords_impl
        for a in person._stopped_actions_for_removal:
            a.start()
        person._stopped_actions_for_removal = []
        self.persons.add(person)
        # Bad hack: unterminate
        person._terminated = False
        person._nextTime = None
        self.activate(person, person.go())
        person.readd_actions()

    def run(self, until, real_time, monitor=True):
        """Runs Simulation after setup.
        
        @param until: simulation runs until this tick
        @param real_time: run in real-time? or as fast as possible
        @param monitor: start defined monitors?
        """
        if monitor:
            if len(self.monitors) == 0:
                raise monitors.NoSimulationMonitorDefinedException('at mosp.Simulation.run()')
            for mon in self.monitors:
                mon.init()
        
        # alarm for person.pause_movement()
        self.activate(self.person_alarm_clock, self.person_alarm_clock.serve(), 0)
        
        # based on code from SimPy.SimulationRT.simulate
        self.rtstart = self.wallclock()
        self.rtset(self.rel_speed)

        last_event_time = 0
        avg_delta = 0
        while self._timestamps and not self._stop:
            next_event_time = self.peek()

            # new implementation of real_time, only rel_speed = 1
            if real_time and self.rel_speed == 1:
                now = time.time()
                sim_now = self.start_timestamp + self.now()
                delta = now - sim_now
                #avg_delta = 0.8 * avg_delta + 0.2 * delta

                #print '-'*50
                #print 'delta (>0, wenn sim zu langsam)', delta
                #print 'avg_delta', avg_delta
                if delta < 0:
                    time.sleep(-delta)

            if last_event_time != next_event_time:
                pass # replaces next logging statement
                #logging.debug('Simulation.run.next_event_time = %s' % next_event_time)
                last_event_time = next_event_time
                if next_event_time > until:
                    break

                #print '-'*50
                #print 'delta (>0, wenn sim zu langsam)', delta
                #print 'avg_delta', avg_delta
                if real_time and self.rel_speed != 1: 
                    delay = ( 
                            next_event_time / self.rel_speed - 
                            (self.wallclock() - self.rtstart) 
                            ) 
                    if delay > 0: time.sleep(delay) 

                # do communication stuff
                while self.messages and self.messages[0].time < next_event_time:
                    # execute messages
                    heappop(self.messages)()    # execute __call__() of popped object

            self.step()

        # There are still events in the timestamps list and the simulation
        # has not been manually stopped. This means we have reached the stop
        # time.
        for m in self.monitors:
            m.end()
        if not self._stop and self._timestamps:
            self._t = until
            return 'SimPy: Normal exit'
        else:
            return 'SimPy: No activities scheduled'

    def __getstate__(self):
        """Returns Simulation information for pickling using the pickle module."""
        state = self.__dict__
        #print 'get state', state
        del state['sim']
        return state