diff --git a/desmod/component.py b/desmod/component.py index c42bc1b0..74ed07a8 100644 --- a/desmod/component.py +++ b/desmod/component.py @@ -275,6 +275,23 @@ def elab_hook(self): """ pass + def post_fail(self): + """Recursively run post-fail hooks.""" + for child in self._children: + child.post_fail() + self.post_sim_fail_hook() + + def post_sim_fail_hook(self): + """Hook called after simulation fails. + + Component subclasses may override `post_sim_fail_hook()` to inject + behavior in case the simulation fails. Note that + `post_sim_fail_hook()` will not be called when simulation is + successful. Instead, :meth:`post_sim_hook` method will be called. + + """ + pass + def post_simulate(self): """Recursively run post-simulation hooks.""" for child in self._children: diff --git a/desmod/simulation.py b/desmod/simulation.py index 367a5c26..15101415 100644 --- a/desmod/simulation.py +++ b/desmod/simulation.py @@ -172,6 +172,7 @@ def simulate(config, top_type, env_type=SimEnvironment, reraise=True, top_type.pre_init(env) env.tracemgr.flush() with progress_manager(env): + _dump_dict(config_file, config) top = top_type(parent=None, env=env) top.elaborate() env.tracemgr.flush() @@ -183,6 +184,7 @@ def simulate(config, top_type, env_type=SimEnvironment, reraise=True, except BaseException as e: env.tracemgr.trace_exception() result['sim.exception'] = repr(e) + top.post_fail() raise else: result['sim.exception'] = None @@ -192,7 +194,6 @@ def simulate(config, top_type, env_type=SimEnvironment, reraise=True, 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: