# Copyright (c) 1996, 1997, 1998 The Regents of the University of California. # All rights reserved. See legal notices for full text and disclaimer. """ History package A Tag is a set of history items with a common condition and storage medium """ __version__ = "2.0" import history_item import history_condition import history_medium import history_collector import types NeverSampled = -1000000 # The default standard collector with which each tag is registered when created. collector = history_collector.HistoryCollector () class Tag: "A group of items sampled together." # # Creation # def __init__ (self, name, medium, collect = collector): "Create an empty group of items." self.initialize (name, medium, collect) def initialize (self, name, medium, collect): "Initializer, separated out for convenience of heirs." self.name = name self._items = {} self._itemnames = [] self.medium = medium self.cycle_last_sampled = NeverSampled self.sample_count = 0 self.condition = history_condition.EveryCycle self.logical_condition = None collect.add (self) # # Queries # def includes_cycle_and_time (self): "Are the cycle and time added to the records of this tag?" return self.medium.write_cycle_and_time def itemnames (self): "List of the names of items in this tag." return self._itemnames def get_item (self, name): "The item named name, or None if there isn't one." try: return self._items[name] except KeyError: return None def failing (self): "List of items in this tag which cannot currently be sampled." failed=[] for x in self.itemnames (): it = self._items[x] try: it.value () except: failed.append(it) return failed def history (self, name): "Get the history stored under name." try: return self.medium.history (name) except AttributeError: raise history_error_no_support # # Commands # # # Setting the condition # def set_condition (self, condition=history_condition.EveryCycle): "Set the condition to condition." self.condition = condition def frequency (self, start, stop, freq): "Collect every f time units between start_time and last_time, inclusive." if type(start) == types.IntType and type (stop) == types.IntType and \ type(freq) == types.IntType: self.set_condition (history_condition.Cycles (start, stop, freq)) return self.set_condition(history_condition.Times (start, stop, freq)) def at_times (self, *times): "Collect at the specified time(s)." self.set_condition (history_condition.TimeList (times)) def at_cycles (self, *cycles): "Collect at the specified cycle(s)." self.set_condition (history_condition.CycleList (cycles)) def set_logical_condition (self, condition = None): "Set the logical condition of this tag." self.logical_condition = condition def when (self, expression, context = "__main__"): "Set the logical expression to be the value of the expression in the given context." self.set_logical_condition (history_condition.When (expression, context)) # # Collecting samples # def sample (self, cycle, time): "Sample this tag if it has a true condition." if self.cycle_last_sampled >= cycle: return self.condition.evaluate (cycle, time) if self.logical_condition is None: t = 1 else: w = self.logical_condition w.evaluate (cycle, time) t = w.state if (t and self.condition.state): self._sample_core(cycle, time) def sample_final (self, cycle, time): "Sample this tag if it has a true final condition." if self.cycle_last_sampled >= cycle: return self.condition.evaluate (cycle, time) if self.logical_condition is None: t = 1 else: w = self.logical_condition w.evaluate (cycle, time) t = w.state_final if (t and self.condition.state_final): self._sample_core(cycle, time) def sample_unconditionally (self, cycle, time): "Sample every item in this tag, unconditionally." if self.cycle_last_sampled >= cycle: return # Do the conditions to get their 'clock' right. self.condition.evaluate (cycle, time) if self.logical_condition: self.logical_condition.evaluate (cycle, time) self._sample_core (cycle, time) def _sample_core (self, cycle, time): "Carry out the sampling process for this tag." self.cycle_last_sampled = cycle self.sample_count = self.sample_count + 1 self.medium.begin_record (cycle, time) if self.medium.write_cycle_and_time: self.medium.write ("cycle", cycle) self.medium.write ("time", time) for x in self._itemnames: it = self._items[x] if self.medium.record_number > 1 and it.static: continue self.medium.write (it.name, it.value()) self.medium.end_record () # # Items # def item (self, name, value = None, context="__main__"): """Create an item named name to an item with the given name, value, and context. value is the string to be evaluated, which defaults to name. context is the dictionary in which to evaluate that string. """ if value is None: v = name else: v = value self.add (history_item.Item (name, v, context)) def item_static (self, name, value = None, context="__main__"): """Create an item only collected once per file.""" self.item (name, value, context) self._items [name].static = 1 def add (self, itm): "Set the item whose name is itm.name to itm." if self.cycle_last_sampled != NeverSampled: raise RuntimeError, \ "Cannot add items after tag's sampling has begun." if self._items.has_key (itm.name): raise RuntimeError, \ "Cannot have two items in a tag with the same name." self._itemnames.append (itm.name) self._items [itm.name] = itm # # Conversion # def __repr__ (self): "Print each item" result = "Tag " + self.name + ":\n" result = result + "\tMedium: " + `self.medium` + '\n' result = result + "\tCycle last sampled: " + `self.cycle_last_sampled` + '\n' result = result + "\tSample count: " + `self.sample_count` + '\n' result = result + "\tCondition: " + `self.condition` + '\n' result = result + "\tLogical condition: " + `self.logical_condition` + '\n' result = result + "\tItems:\n" for n in self.itemnames (): it = self.get_item (n) result = result + "\t\t" + `it` + '\n' return result + '\n' __str__ = __repr__ def textfile_tag (tagname, filename = '', col = collector): "textfile_tag (tagname) creates a textfile-based tag named tagname." if filename == '': filename = "history_" + tagname + ".txt" return Tag (tagname, history_medium.TextFile (filename), col) def columnarfile_tag (tagname, filename = '', col = collector): "columnarfile_tag (tagname) creates a columnar-textfile tag named tagname." if filename == '': filename = "history_" + tagname + ".txt" return Tag (tagname, history_medium.ColumnarFile (filename), col) def event_tag (name, action, context = "__main__", col = collector): "event(name, 'foo ()') creates a tag which will execute foo()" t = Tag (name, history_medium.Event (), col) t.item (name, action, context) t.condition.state_final_enabled = 0 return t def memory_tag (name, context = "__main__", col = collector): "memory_tag(name) creates a tag which stores values in an dictionary attribute of the tag" return Tag (name, history_medium.Memory(), col) if __name__ == "__main__": import sys outfile = open("history_out.txt", "w") sys.stdout = outfile print "History package version", __version__ print "History test writes this file plus three tag-specific history files." tag1 = textfile_tag ("tag1") tag1.item ("xx") tag1.item ("yy", "xx * xx") tag1.item_static ("ww") tag1.item_static ("some_label") tag1.frequency (.03, .10, .02) tag2 = textfile_tag ("tag2") tag2.item ("xw", "zzz + xxx") tag2.frequency (0, 10000, 2) tag2.when ("zzz > 0.5") tag3 = columnarfile_tag ("tag3") tag3.item ("xw", "zzz + xxx") tag3.frequency (0, 10000, 2) tag3.when ("zzz > 0.5") tag4 = memory_tag ("tag4") tag4.item ("xw", "zzz + xxx") tag4.frequency (0, 10000, 2) tag4.when ("zzz > 0.5") def do_something (p): print "Event do_something p =", p def yo (): print "Yo!" def ho (): print "Ho!" event1 = event_tag ("Periodic do", "do_something (xx)") event1.frequency (0, 10000, 5) event_tag ("Salute", "yo()").at_cycles(3, 8) # Example of a fancy condition e1 = event_tag ("Double trigger", "ho()") import history_condition c1 = history_condition.CycleList([3, 4, 9]) c2 = history_condition.TimeList([.1]) e1.set_condition (history_condition.Or (c1, c2)) zzz = 0.2 xxx = 1.0 xx = 0. ww = 3.1 some_label = "my label" print "Items currently failing in tag1 (should be empty): ", tag1.failing () for i in range(12): cycle = i time = cycle / 100. xx = i / 2.0 print cycle, time, xx, zzz zzz = zzz + time collector.sample (cycle, time) collector.sample_final (cycle, time) print tag1, tag1.condition.report() print tag2, tag2.condition.report() print tag3, tag3.condition.report() print tag4, tag4.condition.report() print event1, event1.condition.report() print "History of xw in tag 4:" print tag4.history("xw") print collector raise SystemExit