def __init__(self, config: ConfigDict) -> None: super().__init__() #: The configuration dictionary. self.config = config #: The pseudo-random number generator; an instance of #: :class:`random.Random`. self.rand = random.Random() seed = config.setdefault('sim.seed', None) self.rand.seed(seed, version=1) timescale_str = self.config.setdefault('sim.timescale', '1 s') #: Simulation timescale ``(magnitude, units)`` tuple. The current #: simulation time is ``now * timescale``. self.timescale = parse_time(timescale_str) duration = config.setdefault('sim.duration', '0 s') #: The intended simulation duration, in units of :attr:`timescale`. self.duration = scale_time(parse_time(duration), self.timescale) #: The simulation runs "until" this event. By default, this is the #: configured "sim.duration", but may be overridden by subclasses. self.until = self.duration #: From 'meta.sim.index', the simulation's index when running multiple #: related simulations or `None` for a standalone simulation. self.sim_index: Optional[int] = config.get('meta.sim.index') #: :class:`TraceManager` instance. self.tracemgr = TraceManager(self)
def __init__(self, config: ConfigDict) -> None: self.workspace: str = config.setdefault( 'meta.sim.workspace', config.setdefault('sim.workspace', os.curdir)) self.overwrite: bool = config.setdefault('sim.workspace.overwrite', False) self.prev_dir: str = os.getcwd()
def simulate_factors( base_config: ConfigDict, factors: List[ConfigFactor], top_type: Type['Component'], env_type: Type[SimEnvironment] = SimEnvironment, jobs: Optional[int] = None, config_filter: Optional[Callable[[ConfigDict], bool]] = None, ) -> List[ResultDict]: """Run multi-factor simulations in separate processes. The `factors` are used to compose specialized config dictionaries for the simulations. The :mod:`python:multiprocessing` module is used run each simulation with a separate Python process. This allows multi-factor simulations to run in parallel on all available CPU cores. :param dict base_config: Base configuration dictionary to be specialized. :param list factors: List of factors. :param top_type: The model's top-level Component subclass. :param env_type: :class:`SimEnvironment` subclass. :param int jobs: User specified number of concurent processes. :param function config_filter: A function which will be passed a config and returns a bool to filter. :returns: Sequence of result dictionaries for each simulation. """ configs = list(factorial_config(base_config, factors, 'meta.sim.special')) ws = base_config.setdefault('sim.workspace', os.curdir) overwrite = base_config.setdefault('sim.workspace.overwrite', False) for index, config in enumerate(configs): config['meta.sim.index'] = index config['meta.sim.workspace'] = os.path.join(ws, str(index)) if config_filter is not None: configs[:] = filter(config_filter, configs) if overwrite and os.path.relpath(ws) != os.curdir and os.path.isdir(ws): shutil.rmtree(ws) for c in configs: if c['meta.sim.index'] == 0: # return simulate(config=c, top_type=top_type, env_type=env_type) pass # return simulate_many([configs[96],configs[97],configs[79]], top_type, env_type, jobs) return simulate_many(configs, top_type, env_type, jobs)
def _get_interval_period_s(config: ConfigDict) -> Union[int, float]: period_str: str = config.setdefault('sim.progress.update_period', '1 s') return scale_time(parse_time(period_str), (1, 's'))
def simulate( config: ConfigDict, top_type: Type['Component'], env_type: Type[SimEnvironment] = SimEnvironment, reraise: bool = True, progress_manager=standalone_progress_manager, ) -> ResultDict: """Initialize, elaborate, and run a simulation. All exceptions are caught by `simulate()` so they can be logged and captured in the result file. By default, any unhandled exception caught by `simulate()` will be re-raised. Setting `reraise` to False prevents exceptions from propagating to the caller. Instead, the returned result dict will indicate if an exception occurred via the 'sim.exception' item. :param dict config: Configuration dictionary for the simulation. :param top_type: The model's top-level Component subclass. :param env_type: :class:`SimEnvironment` subclass. :param bool reraise: Should unhandled exceptions propogate to the caller. :returns: Dictionary containing the model-specific results of the simulation. """ t0 = timeit.default_timer() result: ResultDict = {} result_file = config.setdefault('sim.result.file') config_file = config.setdefault('sim.config.file') try: with _Workspace(config): env = env_type(config) with closing(env.tracemgr): try: top_type.pre_init(env) env.tracemgr.flush() with progress_manager(env): top = top_type(parent=None, env=env) top.elaborate() env.tracemgr.flush() env.run(until=env.until) env.tracemgr.flush() top.post_simulate() env.tracemgr.flush() top.get_result(result) except BaseException as e: env.tracemgr.trace_exception() result['sim.exception'] = repr(e) raise else: result['sim.exception'] = None finally: env.tracemgr.flush() result['config'] = config result['sim.now'] = env.now result['sim.time'] = env.time() result['sim.runtime'] = timeit.default_timer() - t0 _dump_dict(config_file, config) _dump_dict(result_file, result) except BaseException as e: if reraise: raise result.setdefault('config', config) result.setdefault('sim.runtime', timeit.default_timer() - t0) if result.get('sim.exception') is None: result['sim.exception'] = repr(e) if result.get('sim.exception') is not None: err_file = os.path.join(config['meta.sim.workspace'], 'err.yaml') _dump_dict(err_file, result['sim.exception']) return result