def shutdown(self): """Shut-down all simulators and close the server socket.""" for sim in self.sims.values(): util.sync_process(sim.stop(), self, ignore_errors=True) if self.srv_sock is not None: self.srv_sock.close() self.srv_sock = None
def get_data(self, entity_set, *attributes): """Get and return the values of all *attributes* for each entity of an *entity_set*. The return value is a dict mapping the entities of *entity_set* to dicts containing the values of each attribute in *attributes*:: { Entity(...): { 'attr_1': 'val_1', 'attr_2': 'val_2', ... }, ... } """ outputs_by_sim = defaultdict(dict) for entity in entity_set: outputs_by_sim[entity.sid][entity.eid] = attributes def request_data(): requests = { self.sims[sid].proxy.get_data(outputs): sid for sid, outputs in outputs_by_sim.items() } try: results = yield self.env.all_of(requests) except ConnectionError as e: msg = ('Simulator "%s" closed its connection while executing ' '"World.get_data()".') # Try to find the simulator that closed its connection for req, sid in requests.items(): if req.triggered and not req.ok: raise SimulationError(msg % sid, e) from None else: raise RuntimeError('Could not determine which simulator ' 'closed its connection.') results_by_sim = {} for request, value in results.items(): sid = requests[request] results_by_sim[sid] = value return results_by_sim results_by_sim = util.sync_process(request_data(), self) results = {} for entity in entity_set: results[entity] = results_by_sim[entity.sid][entity.eid] return results
def run(self, until, rt_factor=None, rt_strict=False): """Start the simulation until the simulation time *until* is reached. In order to perform real-time simulations, you can set *rt_factor* to a number > 0. An rt-factor of 1 means that 1 simulation time unit (usually a second) takes 1 second in real-time. An rt-factor 0f 0.5 will let the simulation run twice as fast as real-time. If the simulators are too slow for the rt-factor you chose, mosaik prints by default only a warning. In order to raise a :exc:`RuntimeError`, you can set *rt_strict* to ``True``. Before this method returns, it stops all simulators and closes mosaik's server socket. So this method should only be called once. """ if self.srv_sock is None: raise RuntimeError('Simulation has already been run and can only ' 'be run once for a World instance.') # Check if a simulator is not connected to anything: for sid, deg in sorted(list(networkx.degree(self.df_graph))): if deg == 0: print('WARNING: %s has no connections.' % sid) print('Starting simulation.') import mosaik._debug as dbg # always import, enable when requested if self._debug: dbg.enable() try: util.sync_process(scheduler.run(self, until, rt_factor, rt_strict), self) print('Simulation finished successfully.') except KeyboardInterrupt: print('Simulation canceled. Terminating ...') finally: self.shutdown() if self._debug: dbg.disable()
def make_proxy(world, sim_name, sim_config, sim_id, sim_params, proc=None, addr=None): """Try to establish a connection with *sim_name* and perform the ``init()`` API call. Return a new :class:`RemoteProcess` sim proxy. Raise a :exc:`~mosaik.exceptions.ScenarioError` if something goes wrong. This method is a SimPy process used by :func:`start_proc()` and :func:`start_connect()`. """ start_timeout = world.env.timeout(world.config['start_timeout']) def greeter(): if proc: # Wait for connection from "sim_name" accept_con = world.srv_sock.accept() results = yield accept_con | start_timeout if start_timeout in results: raise SimulationError('Simulator "%s" did not connect to ' 'mosaik in time.' % sim_name) else: sock = results[accept_con] else: # Connect to "sim_name" try: sock = backend.TCPSocket.connection(world.env, addr) except (ConnectionError, OSError): raise SimulationError('Simulator "%s" could not be started: ' 'Could not connect to "%s"' % (sim_name, sim_config['connect'])) rpc_con = JsonRpc(Packet(sock, max_packet_size=10 * 1024 * 1024)) # Make init() API call and wait for sim_name's meta data. init = rpc_con.remote.init(sim_id, **sim_params) try: results = yield init | start_timeout except ConnectionError as e: raise SimulationError( 'Simulator "%s" closed its connection during' ' the init() call.' % sim_name, e) if start_timeout in results: raise SimulationError('Simulator "%s" did not reply to the init() ' 'call in time.' % sim_name) else: meta = results[init] return RemoteProcess(sim_name, sim_id, meta, proc, rpc_con, world) # Add a error callback that waits for "proc" to stop if "proc" is not None: def terminate(): try: # See if it terminates on its own ... proc.wait(timeout=1) except subprocess.TimeoutExpired: # ... or kill it ... proc.terminate() proc.wait(timeout=1) cb = None if proc is None else terminate return sync_process(greeter(), world, errback=cb)
def run(self, until, rt_factor=None, rt_strict=False): if "control" in self.commands: #cerca se ci sono altri simulatori in attesa control = dict(self.commands["control"]) for sim, data in control.items(): self.sim_config[sim] = {"connect": data["port"]} if "prefix" in data: factor = self.start(sim, eid_prefix=data["prefix"]) eval( "factor." + data["create"] + ".create(" + str(len(data['dests'])) + ")" ) #bisogna mettere molti controlli prima di questa funzione for sim, data in control.items(): i = 0 if "prefix" in data: for model, conns in data["dests"].items(): string = sim + "-0." + model for conn, couples in conns.items(): for a, b in couples.items(): tupla = (a, b) self.connect(self.models[string], self.models[conn], tupla, async_requests=True) """Start the simulation until the simulation time *until* is reached. In order to perform real-time simulations, you can set *rt_factor* to a number > 0. An rt-factor of 1 means that 1 simulation time unit (usually a second) takes 1 second in real-time. An rt-factor 0f 0.5 will let the simulation run twice as fast as real-time. If the simulators are too slow for the rt-factor you chose, mosaik prints by default only a warning. In order to raise a :exc:`RuntimeError`, you can set *rt_strict* to ``True``. Before this method returns, it stops all simulators and closes mosaik's server socket. So this method should only be called once. """ if self.srv_sock is None: raise RuntimeError('Simulation has already been run and can only ' 'be run once for a World instance.') # Check if a simulator is not connected to anything: for sid, deg in sorted(list(networkx.degree(self.df_graph))): if deg == 0: print('WARNING: %s has no connections.' % sid) print('Starting simulation.') import mosaik._debug as dbg # always import, enable when requested if self._debug: dbg.enable() try: util.sync_process(scheduler.run(self, until, rt_factor, rt_strict), self) print('Simulation finished successfully.') except KeyboardInterrupt: print('Simulation canceled. Terminating ...') finally: self.shutdown() if self._debug: dbg.disable()