def _prepare(self): if not self.visual_backend and not self.store_positions: functions.warn( "No results are logged. Ensure you want a headless simulation." ) # The order in which the following effects are added is important. for population in self.populations: self.on_step_functions.append(population.step) if 'repulsion' in self.effects: self.on_step_functions.append(self.effects['repulsion'].step) if 'fire' in self.effects: self.on_step_functions.append(self.effects['fire'].step) self.on_step_functions.append(self.scene.move) if 'separation' in self.effects: self.on_step_functions.append(self.effects['separation'].step) self.on_step_functions.append(self.scene.correct_for_geometry) self.on_step_functions.append(self.scene.find_finished) if self.store_positions: self.on_step_functions.append(self.logger.step) if self.visual_backend: self.vis = VisualScene(self.scene) self.on_step_functions.append(self.vis.loop) else: self.vis = NoVisualScene(self.scene) if self.inflow: self.on_step_functions.append(self._add_new_pedestrian_sometimes) self.vis.step_callback = self.step self.vis.finish_callback = self.finish self.scene.on_pedestrian_exit_functions.append(self._check_percentage) if self.params.max_time > 0: self.scene.on_pedestrian_exit_functions.append( self._check_max_time)
def __init__(self, args): np.seterr(all='raise') functions.VERBOSE = args.verbose self.scene = None self.step_functions = [] self.on_pedestrian_exit_functions = [] self.on_pedestrian_init_functions = [] self.finish_functions = [] config = configparser.ConfigParser() has_config = config.read(args.config_file) if not has_config: raise FileNotFoundError("Configuration file %s not found" % args.config_file) functions.EPS = config['general'].getfloat('epsilon') self.config = config if args.obstacle_file: config['general']['obstacle_file'] = args.obstacle_file # Initialization scene if args.number >= 0: config['general']['number_of_pedestrians'] = str(args.number) if args.configuration == 'uniform': self.scene = scene_module.Scene(config=config) elif args.configuration == 'top': self.scene = TopScene(barrier=0.8, config=config) elif args.configuration == 'center': self.scene = ImpulseScene(impulse_location=(0.5, 0.6), impulse_size=8, config=config) elif args.configuration == 'bottom': self.scene = TwoImpulseScene(impulse_locations=[(0.5, 0.4), (0.4, 0.2)], impulse_size=8, config=config) if not self.scene: raise ValueError("No scene has been initialized") # Initialization planner planner = Planner(self.scene) self.step_functions.append(planner.step) if args.store_positions: # filename = input('Specify storage file\n') import re filename = re.search('/([^/]+)\.json', config['general']['obstacle_file']).group(1) functions.log("Storing positions results in '%s%s'" % (config['general']['result_dir'], filename)) self.step_functions.append(lambda: self.store_positions_to_file(filename)) self.finish_functions.append(lambda: self.store_position_usage(filename)) self.finish_functions.append(self.store_exit_logs) if args.results: results = Result(self.scene) self.step_functions.append(results.on_step) self.on_pedestrian_exit_functions.append(results.on_pedestrian_exit) self.on_pedestrian_init_functions.append(results.on_pedestrian_entrance) self.finish_functions.append(results.on_finish) if not args.kernel: self.vis = VisualScene(self.scene) if args.step: self.vis.disable_loop() else: self.step_functions.append(self.vis.loop) else: if not (args.store_positions or args.results): functions.warn("No results are logged. Ensure you want a headless simulation.") self.vis = NoVisualScene(self.scene) self.scene.on_pedestrian_exit_functions += self.on_pedestrian_exit_functions self.scene.on_pedestrian_init_functions += self.on_pedestrian_init_functions self.vis.step_callback = self.step self.vis.finish_callback = self.finish
class SimulationManager: def __init__(self, args): np.seterr(all='raise') functions.VERBOSE = args.verbose self.scene = None self.step_functions = [] self.on_pedestrian_exit_functions = [] self.on_pedestrian_init_functions = [] self.finish_functions = [] config = configparser.ConfigParser() has_config = config.read(args.config_file) if not has_config: raise FileNotFoundError("Configuration file %s not found" % args.config_file) functions.EPS = config['general'].getfloat('epsilon') self.config = config if args.obstacle_file: config['general']['obstacle_file'] = args.obstacle_file # Initialization scene if args.number >= 0: config['general']['number_of_pedestrians'] = str(args.number) if args.configuration == 'uniform': self.scene = scene_module.Scene(config=config) elif args.configuration == 'top': self.scene = TopScene(barrier=0.8, config=config) elif args.configuration == 'center': self.scene = ImpulseScene(impulse_location=(0.5, 0.6), impulse_size=8, config=config) elif args.configuration == 'bottom': self.scene = TwoImpulseScene(impulse_locations=[(0.5, 0.4), (0.4, 0.2)], impulse_size=8, config=config) if not self.scene: raise ValueError("No scene has been initialized") # Initialization planner planner = Planner(self.scene) self.step_functions.append(planner.step) if args.store_positions: # filename = input('Specify storage file\n') import re filename = re.search('/([^/]+)\.json', config['general']['obstacle_file']).group(1) functions.log("Storing positions results in '%s%s'" % (config['general']['result_dir'], filename)) self.step_functions.append(lambda: self.store_positions_to_file(filename)) self.finish_functions.append(lambda: self.store_position_usage(filename)) self.finish_functions.append(self.store_exit_logs) if args.results: results = Result(self.scene) self.step_functions.append(results.on_step) self.on_pedestrian_exit_functions.append(results.on_pedestrian_exit) self.on_pedestrian_init_functions.append(results.on_pedestrian_entrance) self.finish_functions.append(results.on_finish) if not args.kernel: self.vis = VisualScene(self.scene) if args.step: self.vis.disable_loop() else: self.step_functions.append(self.vis.loop) else: if not (args.store_positions or args.results): functions.warn("No results are logged. Ensure you want a headless simulation.") self.vis = NoVisualScene(self.scene) self.scene.on_pedestrian_exit_functions += self.on_pedestrian_exit_functions self.scene.on_pedestrian_init_functions += self.on_pedestrian_init_functions self.vis.step_callback = self.step self.vis.finish_callback = self.finish def start(self): self.vis.start() self.finish() def step(self): [step() for step in self.step_functions] def finish(self): functions.log("Finishing simulation") [finish() for finish in self.finish_functions] def on_pedestrian_exit(self, pedestrian): [ped_exit(pedestrian) for ped_exit in self.on_pedestrian_exit_functions] def store_config(self, file_name): with open(file_name, 'w') as config_file: self.config.write(config_file) def store_exit_logs(self, file_name=None): log_dir = self.config['general']['result_dir'] if not file_name: file_name = self.config['general']['log_file'] log_dict = {exit_object.name: np.array(exit_object.log_list) for exit_object in self.scene.exit_list} sio.savemat(file_name=log_dir + file_name, mdict=log_dict) def store_positions_to_file(self, file_name): # Todo: Alter this, we need the positions stored in one file. # This way we clean up the files and we are able to extract a 4 dimension density field from one file. log_dir = self.config['general']['result_dir'] if self.scene.counter % 10 == 0: with open("%s%s-%d" % (log_dir, file_name, int(self.scene.counter / 10)), 'wb') as f: np.save(f, self.scene.position_array[self.scene.active_entries]) def store_position_usage(self, file_name): log_dir = self.config['general']['result_dir'] store_data = {"number": self.scene.counter, 'name': file_name, 'obstacle_file': self.config['general']['obstacle_file'], 'size': self.scene.size.array.tolist()} with open('%s%s.json' % (log_dir, file_name), 'w') as f: f.write(json.dumps(store_data)) @staticmethod def get_default_config(): config_file_name = 'config.ini' config = configparser.ConfigParser() config.read(config_file_name) return config
class Simulation: """ The simulation class controls all the components of the simulation. It converts the input flags to configuration options and augments them to the configuration file. It initializes the important objects and makes sure that all the event methods (step, on_exit, on_finish) are run. """ def __init__(self, scene_file=None, params=None): """ Create a new simulation. """ self.on_step_functions = [] self.on_pedestrian_exit_functions = [] self.on_pedestrian_init_functions = [] self.finish_functions = [] # All the effects added in the simulation. keys are strings of the effect name, values are the effect objects self.effects = {} self.populations = [] if not params: self.params = Parameters() else: self.params = params if scene_file: self.scene_file = scene_file self.inflow = False self.store_positions = False self.logger = None self.collect_data = None self.visual_backend = True functions.EPS = self.params.tolerance # TODO: Remove self.scene = Scene() def _prepare(self): if not self.visual_backend and not self.store_positions: functions.warn( "No results are logged. Ensure you want a headless simulation." ) # The order in which the following effects are added is important. for population in self.populations: self.on_step_functions.append(population.step) if 'repulsion' in self.effects: self.on_step_functions.append(self.effects['repulsion'].step) if 'fire' in self.effects: self.on_step_functions.append(self.effects['fire'].step) self.on_step_functions.append(self.scene.move) if 'separation' in self.effects: self.on_step_functions.append(self.effects['separation'].step) self.on_step_functions.append(self.scene.correct_for_geometry) self.on_step_functions.append(self.scene.find_finished) if self.store_positions: self.on_step_functions.append(self.logger.step) if self.visual_backend: self.vis = VisualScene(self.scene) self.on_step_functions.append(self.vis.loop) else: self.vis = NoVisualScene(self.scene) if self.inflow: self.on_step_functions.append(self._add_new_pedestrian_sometimes) self.vis.step_callback = self.step self.vis.finish_callback = self.finish self.scene.on_pedestrian_exit_functions.append(self._check_percentage) if self.params.max_time > 0: self.scene.on_pedestrian_exit_functions.append( self._check_max_time) def start(self): """ Start the simulation. When the simulation is finished, self.vis.start() returns, and cleanup is handled through self.finish() :return: None """ if self.params.scene_file: self.scene_file = self.params.scene_file if not self.scene_file: raise AttributeError("No environment provided") self.params.scene_file = self.scene_file if self.store_positions: self.logger = PositionLogger(self) self._prepare() self.scene.prepare(self.params) for effect in self.effects: self.effects[effect].prepare(self.params) for population in self.populations: population.prepare(self.params) if self.store_positions: self.logger.prepare(self.params) self.vis.prepare(self.params) self.vis.start() self.finish() def step(self): """ Increase time and run all the event listener methods that run on each time step :return: """ self.scene.time += self.params.dt self.scene.counter += 1 [step() for step in self.on_step_functions] def add_local(self, effect): effect_name = effect.lower() if effect_name == 'separation': separation = Separate(self.scene) self.effects[effect_name] = separation else: raise NotImplementedError("Local effect %s not found" % effect) def add_global(self, effect): effect_name = effect.lower() if effect_name == 'repulsion': repulsion = Repel(self.scene) self.effects[effect_name] = repulsion def add_pedestrians(self, num, behaviour='knowing'): if type(num) != int or num < 1: raise ValueError( "Provide a positive integer as a population number, not %s" % num) if behaviour.lower() == 'following': Population = Following elif behaviour.lower() == 'knowing': Population = Knowing else: raise NotImplementedError("Behaviour %s not implemented" % behaviour) population = Population(self.scene, num) self.populations.append(population) def add_fire(self, center, radius): effect = Fire(center, radius, self.scene) self.params.fire = effect self.params.smoke = True # If we want more fires, key needs to be unique (changing the fire effect) self.effects['fire'] = effect def add_cameras(self, positions, angles): """ -- Beta functionality -- Not implemented yet. Used to pass data about future camera's to post-visualisation. :param positions: :return: """ effect = Cameras(np.array(positions), np.array(angles)) self.effects['cameras'] = effect def allow_new_pedestrians(self, probability): """ -- Beta functionality -- Add a probability of entering new pedestrians on each time step. :param probability: number between 0 and 1 :return: None """ self.inflow = probability def set_visualisation(self, on): self.visual_backend = bool(on) def set_store_positions(self, on): self.store_positions = bool(on) def set_data_collector(self, on): """ Not implemented yet :param on: :return: """ self.collect_data = bool(on) # # results = Result(self.scene, None, None) # Todo: Make this work # self.on_step_functions.append(results.on_step) # self.on_pedestrian_exit_functions.append(results.on_pedestrian_exit) # self.on_pedestrian_init_functions.append(results.on_pedestrian_entrance) # self.finish_functions.append(results.on_finish) def set_params(self, params): """ Set the parameters with the given object. :param params: Parameter object :return: None """ self.params = params def print_settings(self): """ Prints the parameters used in this simulation. :return: """ print([item for item in dir(self.params) if not item.startswith("__")]) def finish(self): """ Finish the simulation and run all registered methods that should be called on finish. :return: None """ functions.log("Finishing simulation. %d iterations of %.2f seconds" % (self.scene.counter, self.scene.time)) [finish() for finish in self.finish_functions] def on_pedestrian_exit(self, pedestrian): """ Run all methods required when a pedestrian exits. :param pedestrian: Pedestrian that exited the scene. :return: """ [ ped_exit(pedestrian) for ped_exit in self.on_pedestrian_exit_functions ] def store_config(self, file_name): """ Store the configuration in memory to file(containing the options from the command line and from file). Not yet implemented, I guess pickling the Parameters object would be the best option. :param file_name: File name for new config file :return: """ with open(file_name, 'w') as config_file: pass # self.params.write(config_file) def _check_max_time(self): if self.scene.time > self.params.max_time: self.vis.finish() def _check_percentage(self, _=None): """ Check whether the required percentage of evacs has been reached :param _: Placeholder parameter; ignore :return: """ if 1 - np.sum(self.scene.active_entries) / len( self.scene.active_entries) >= self.params.max_percentage: self.vis.finish() def _add_new_pedestrian_sometimes(self): """ -- Beta functionality -- Prototype for adding new pedestrians to the scene. Not suitable for research purposes yet. :return: """ if np.random.random() < self.inflow and len( self.scene.pedestrian_list) < self.scene.total_pedestrians: self.populations[0].create_new_pedestrian()