From 840a8af818a5ba3332e1c55f44176e0f3ad55674 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner <inform@tiker.net> Date: Sat, 12 Jan 2008 12:01:56 -0500 Subject: [PATCH] Logging infrastructure: Checkpointing. Constants. Timestep size quantity. --- bin/logtool | 16 ++++++++++- src/log.py | 80 ++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 76 insertions(+), 20 deletions(-) diff --git a/bin/logtool b/bin/logtool index 4836d44..22ae363 100755 --- a/bin/logtool +++ b/bin/logtool @@ -7,7 +7,8 @@ def main(): description = """Operate on data gathered during code runs. FILE is a log saved from a code run. COMMANDS may be one of the -following: "list" to list the available variables, +following: +"list" to list the available variables, "plot expr_x,expr_y" to plot a graph, "datafile outfile expr_x,expr_y" to write out a data file.""" parser = OptionParser(usage="%prog FILE COMMANDS FILE COMMANDS...", @@ -41,6 +42,9 @@ following: "list" to list the available variables, while args: if args[0] == "list": args.pop(0) + print "Time series" + print "-----------" + items = list(logmgr.quantity_buffers.iteritems()) items.sort(lambda a,b: cmp(a[0], b[0])) @@ -48,6 +52,16 @@ following: "list" to list the available variables, for key, qbuf in items: print "%s\t%s" % (key.ljust(col0_len), qbuf.quantity.description) + + print "Constants" + print "---------" + items = list(logmgr.variables.iteritems()) + items.sort(lambda a,b: cmp(a[0], b[0])) + + col0_len = max(len(k) for k, v in items) + 1 + + for key, value in items: + print "%s\t%s" % (key.ljust(col0_len), str(value)) elif args[0] == "plot": args.pop(0) diff --git a/src/log.py b/src/log.py index 9983fba..d96e47f 100644 --- a/src/log.py +++ b/src/log.py @@ -13,20 +13,6 @@ class LogQuantity: def __call__(self): raise NotImplementedError -class PushLogQuantity(LogQuantity): - def __init__(self, name, unit=None, description=None): - LogQuantity.__init__(self, name, unit, description) - self.value = None - - def set(self, value): - if self.value is None: - self.value = value - else: - raise RuntimeError, "Push quantities may only be set once per cycle" - - def __call__(self): - return self.value - class CallableLogQuantityAdapter(LogQuantity): def __init__(self, callable, name, unit=None, description=None): self.callable = callable @@ -83,9 +69,23 @@ def _join_by_first_of_tuple(list_of_iterables): class LogManager: - def __init__(self): + def __init__(self, filename=None): self.quantity_buffers = {} self.tick_count = 0 + self.filename = filename + + self.variables = {} + + if filename is not None: + from os import access, R_OK + if access(self.filename, R_OK): + raise IOError, "cowardly refusing to overwrite '%s'" % self.filename + + from time import time + self.last_checkpoint = time() + + def set_variable(self, name, value): + self.variables[name] = value def tick(self): for qbuf in self.quantity_buffers.itervalues(): @@ -93,6 +93,13 @@ class LogManager: qbuf.buffer.append((self.tick_count, qbuf.quantity())) self.tick_count += 1 + if self.filename is not None: + from time import time + now = time() + if now - self.last_checkpoint > 10: + self.save() + self.last_checkpoint = now + def add_quantity(self, quantity, interval=1): """Add an object derived from L{LogQuantity} to this manager.""" self.quantity_buffers[quantity.name] = _QuantityBuffer(quantity, interval) @@ -117,10 +124,16 @@ class LogManager: for name in deps)) if description is None: description = expression + + def make_eval_context(seq): + ctx = dict(seq) + ctx.update(self.variables) + return ctx + return (description, unit, [(key, evaluate(parsed, - dict((name, value) + make_eval_context((name, value) for name, value in zip(deps, values)) )) @@ -165,7 +178,14 @@ class LogManager: return zipped_dubs - def save(self, filename): + def save(self, filename=None): + if filename is not None: + from os import access, R_OK + if access(filename, R_OK): + raise IOError, "cowardly refusing to overwrite '%s'" % filename + else: + filename = self.filename + save_buffers = dict( (name, _QuantityBuffer( LogQuantity( @@ -178,11 +198,12 @@ class LogManager: for name, qbuf in self.quantity_buffers.iteritems()) from cPickle import dump, HIGHEST_PROTOCOL - dump(save_buffers, open(filename, "w"), protocol=HIGHEST_PROTOCOL) + dump((save_buffers, self.variables), + open(filename, "w"), protocol=HIGHEST_PROTOCOL) def load(self, filename): from cPickle import load - self.quantity_buffers = load(open(filename)) + self.quantity_buffers, self.variables = load(open(filename)) def get_plot_data(self, expr_x, expr_y): """Generate plot-ready data. @@ -341,10 +362,31 @@ class SimulationTime(LogQuantity): +class Timestep(LogQuantity): + def __init__(self, dt, name="dt"): + LogQuantity.__init__(self, name, "s", "Simulation Timestep") + self.dt = dt + + def set_dt(self, dt): + self.dt = dt + + def __call__(self): + return self.dt + + + +def set_dt(mgr, dt): + mgr.quantity_buffers["dt"].quantity.set_dt(dt) + mgr.quantity_buffers["t_sim"].quantity.set_dt(dt) + + + + def add_general_quantities(mgr, dt): mgr.add_quantity(TimestepDuration()) mgr.add_quantity(WallTime()) mgr.add_quantity(SimulationTime(dt)) + mgr.add_quantity(Timestep(dt)) mgr.add_quantity(TimestepCounter()) -- GitLab