/[escript]/trunk/escript/py_src/modelframe.py
ViewVC logotype

Diff of /trunk/escript/py_src/modelframe.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 874 by elspeth, Tue Oct 17 12:06:11 2006 UTC revision 980 by gross, Mon Feb 19 05:12:38 2007 UTC
# Line 27  from sys import stdout Line 27  from sys import stdout
27  import numarray  import numarray
28  import operator  import operator
29  import itertools  import itertools
30  # import modellib  temporarily removed!!!  import time
31    import os
32    
33  # import the 'set' module if it's not defined (python2.3/2.4 difference)  # import the 'set' module if it's not defined (python2.3/2.4 difference)
34  try:  try:
# Line 37  except NameError: Line 38  except NameError:
38    
39  from xml.dom import minidom  from xml.dom import minidom
40    
 def dataNode(document, tagName, data):  
     """  
     C{dataNode}s are the building blocks of the xml documents constructed in  
     this module.    
       
     @param document: the current xml document  
     @param tagName: the associated xml tag  
     @param data: the values in the tag  
     """  
     t = document.createTextNode(str(data))  
     n = document.createElement(tagName)  
     n.appendChild(t)  
     return n  
   
 def esysDoc():  
     """  
     Global method for creating an instance of an EsysXML document.  
     """  
     doc = minidom.Document()  
     esys = doc.createElement('ESys')  
     doc.appendChild(esys)  
     return doc, esys  
41    
42  def all(seq):  def all(seq):
43      for x in seq:      for x in seq:
# Line 72  def any(seq): Line 51  def any(seq):
51              return True              return True
52      return False      return False
53    
 LinkableObjectRegistry = {}  
   
 def registerLinkableObject(obj_id, o):  
     LinkableObjectRegistry[obj_id] = o  
   
 LinkRegistry = []  
   
 def registerLink(obj_id, l):  
     LinkRegistry.append((obj_id,l))  
   
 def parse(xml):  
     """  
     Generic parse method for EsysXML.  Without this, Links don't work.  
     """  
     global LinkRegistry, LinkableObjectRegistry  
     LinkRegistry = []  
     LinkableObjectRegistry = {}  
   
     doc = minidom.parseString(xml)  
     sim = getComponent(doc.firstChild)  
     for obj_id, link in LinkRegistry:  
         link.target = LinkableObjectRegistry[obj_id]  
   
     return sim  
   
54  def importName(modulename, name):  def importName(modulename, name):
55      """ Import a named object from a module in the context of this function,      """ Import a named object from a module in the context of this function,
56          which means you should use fully qualified module paths.          which means you should use fully qualified module paths.
           
57          Return None on failure.          Return None on failure.
58    
59          This function from: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52241          This function from: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52241
# Line 112  def importName(modulename, name): Line 65  def importName(modulename, name):
65      except KeyError:      except KeyError:
66          raise ImportError("Could not import %s from %s" % (name, modulename))          raise ImportError("Could not import %s from %s" % (name, modulename))
67    
68  def getComponent(doc):  class ESySXMLParser(object):
     """  
     Used to get components of Simualtions, Models.  
69      """      """
70      for node in doc.childNodes:      parser for ESysXML file
71                """
72          if isinstance(node, minidom.Element):      def __init__(self,xml, debug=False):
73              if node.tagName == 'Simulation':        self.__dom = minidom.parseString(xml)
74                  if node.getAttribute("type") == 'Simulation':        self.__linkable_object_registry= {}
75                      return Simulation.fromDom(node)        self.__link_registry=  []
76              if node.tagName == 'Model':        self.__esys=self.__dom.getElementsByTagName('ESys')[0]
77                  if (node.getAttribute("module")):        self.debug=debug
78                      model_module = node.getAttribute("module")    
79                      model_type = node.getAttribute("type")      def getClassPath(self, node):
80                      return importName(model_module, model_type).fromDom(node)          type = node.getAttribute("type")
81                  else:          if (node.getAttribute("module")):
82                      model_type = node.getAttribute("type")              module = node.getAttribute("module")
83                      model_subclasses = Model.__subclasses__()              return importName(module, type)
84                      for model in model_subclasses:          else:
85                          if model_type == model.__name__:              return importName("__main__", type)
                             return Model.fromDom(node)  
             if node.tagName == 'ParameterSet':  
                 parameter_type = node.getAttribute("type")  
                 return ParameterSet.fromDom(node)  
             raise "Invalid simulation type, %r" % node.getAttribute("type")  
           
86    
87      raise ValueError("No Simulation Found")      def setLinks(self):
88                        for obj_id, link in self.__link_registry:
89                link.target = self.__linkable_object_registry[obj_id]
90    
91        def parse(self):
92           """
93           parser method for EsysXML and returns the list of generating ParameterSets
94           """
95           found=[]
96           for node in self.__esys.childNodes:
97               if isinstance(node, minidom.Element):
98                   if node.tagName == 'Simulation':
99                            found.append(Simulation.fromDom(self, node))
100                   elif node.tagName == 'Model':
101                            found.append(self.getClassPath(node).fromDom(self, node))
102                   elif node.tagName == 'ParameterSet':
103                            found.append(self.getClassPath(node).fromDom(self, node))
104                   else:
105                      raise "Invalid type, %r" % node.getAttribute("type")
106           self.setLinks()
107           return found
108    
109        def registerLink(self,obj_id, link):
110            self.__link_registry.append((int(obj_id),link))
111    
112        def registerLinkableObject(self,obj, node):
113            id_str=node.getAttribute('id').strip()
114            if len(id_str)>0:
115               id=int(id_str)
116               if self.__linkable_object_registry.has_key(id):
117                   raise ValueError("Object id %s already exists."%id)
118               else:
119                   self.__linkable_object_registry[id]=obj
120    
121        def getComponent(self, node):
122           """
123           returns a single component + rank from a simulation
124           parser method for EsysXML and returns the list of generating ParameterSets
125           """
126           rank  = int(node.getAttribute("rank"))
127           for n in node.childNodes:
128               if isinstance(n, minidom.Element):
129                   if n.tagName == 'Simulation':
130                            return (rank, Simulation.fromDom(self, n))
131                   elif n.tagName == 'Model':
132                            return (rank, self.getClassPath(n).fromDom(self, n))
133                   elif n.tagName == 'ParameterSet':
134                            return (rank, self.getClassPath(n).fromDom(self, n))
135                   else:
136                     raise ValueError("illegal component type %s"%n.tagName)
137           raise ValueError("cannot resolve Component")
138    
139    class ESySXMLCreator(object):
140        """
141        creates an XML Dom representation
142        """
143        def __init__(self):
144           self.__dom=minidom.Document()
145           self.__esys =self.__dom.createElement('ESys')
146           self.__dom.appendChild(self.__esys)
147           self.__linkable_object_registry={}
148           self.__number_sequence = itertools.count(100)
149        def getRoot(self):
150           return self.__esys
151        def createElement(self,name):
152          return self.__dom.createElement(name)
153        def createTextNode(self,name):
154          return self.__dom.createTextNode(name)
155        def getElementById(self,name):
156          return self.__dom.getElementById(name)
157        def createDataNode(self, tagName, data):
158              """
159              C{createDataNode}s are the building blocks of the xml documents constructed in
160              this module.  
161        
162              @param tagName: the associated xml tag
163              @param data: the values in the tag
164              """
165              n = self.createElement(tagName)
166              n.appendChild(self.createTextNode(str(data)))
167              return n
168        def getLinkableObjectId(self, obj):
169            for id, o in self.__linkable_object_registry.items():
170                if o == obj: return id
171            id =self.__number_sequence.next()
172            self.__linkable_object_registry[id]=obj
173            return id
174            
175        def registerLinkableObject(self, obj, node):
176            """
177            returns a unique object id for object obj
178            """
179            id=self.getLinkableObjectId(obj)
180            node.setAttribute('id',str(id))
181            node.setIdAttribute("id")
182    
183        def includeTargets(self):
184            target_written=True
185            while target_written:
186                targetsList =self.__dom.getElementsByTagName('Target')
187                target_written=False
188                for element in targetsList:
189                   targetId = int(element.firstChild.nodeValue.strip())
190                   if self.getElementById(str(targetId)): continue
191                   targetObj = self.__linkable_object_registry[targetId]
192                   targetObj.toDom(self, self.__esys)
193                   target_written=True
194    
195        def toprettyxml(self):
196            self.includeTargets()
197            return self.__dom.toprettyxml()
198    
199  class Link:  class Link:
200      """      """
201      A Link makes an attribute of an object callable::      A Link makes an attribute of an object callable::
# Line 161  class Link: Line 215  class Link:
215          self.target = target          self.target = target
216          self.attribute = None          self.attribute = None
217          self.setAttributeName(attribute)          self.setAttributeName(attribute)
218    
219        def getTarget(self):
220            """
221            returns the target
222            """
223            return self.target
224        def getAttributeName(self):
225            """
226            returns the name of the attribute the link is pointing to
227            """
228            return self.attribute
229            
230      def setAttributeName(self,attribute):      def setAttributeName(self,attribute):
231          """          """
# Line 206  class Link: Line 271  class Link:
271          else:          else:
272              return out              return out
273    
274      def toDom(self, document, node):      def toDom(self, esysxml, node):
275          """          """
276          C{toDom} method of Link. Creates a Link node and appends it to the          C{toDom} method of Link. Creates a Link node and appends it to the
277      current XML document.      current XML esysxml.
278          """          """
279          link = document.createElement('Link')          link = esysxml.createElement('Link')
280          assert (self.target != None), ("Target was none, name was %r" % self.attribute)          assert (self.target != None), ("Target was none, name was %r" % self.attribute)
281          link.appendChild(dataNode(document, 'Target', self.target.id))          link.appendChild(esysxml.createDataNode('Target', esysxml.getLinkableObjectId(self.target)))
282          # this use of id will not work for purposes of being able to retrieve the intended          # this use of id will not work for purposes of being able to retrieve the intended
283          # target from the xml later. I need a better unique identifier.          # target from the xml later. I need a better unique identifier.
284          assert self.attribute, "You can't xmlify a Link without a target attribute"          assert self.attribute, "You can't xmlify a Link without a target attribute"
285          link.appendChild(dataNode(document, 'Attribute', self.attribute))          link.appendChild(esysxml.createDataNode('Attribute', self.attribute))
286          node.appendChild(link)          node.appendChild(link)
287    
288      def fromDom(cls, doc):      def fromDom(cls, esysxml, node):
289          targetid = doc.getElementsByTagName("Target")[0].firstChild.nodeValue.strip()          targetid = int(node.getElementsByTagName("Target")[0].firstChild.nodeValue.strip())
290          attribute = doc.getElementsByTagName("Attribute")[0].firstChild.nodeValue.strip()          attribute =str(node.getElementsByTagName("Attribute")[0].firstChild.nodeValue.strip())
291          l = cls(None, attribute)          l = cls(None, attribute)
292          registerLink(targetid, l)          esysxml.registerLink(targetid, l)
293          return l          return l
294    
295      fromDom = classmethod(fromDom)      fromDom = classmethod(fromDom)
296            
     def writeXML(self,ostream=stdout):  
         """  
         Writes an XML representation of self to the output stream ostream.  
         If ostream is nor present the standart output stream is used.  If  
         esysheader==True the esys XML header is written  
         """  
         print 'I got to the Link writeXML method'  
         document, rootnode = esysDoc()  
         self.toDom(document, rootnode)  
   
         ostream.write(document.toprettyxml())  
   
297  class LinkableObject(object):  class LinkableObject(object):
298      """      """
299      An object that allows to link its attributes to attributes of other objects      An object that allows to link its attributes to attributes of other objects
# Line 259  class LinkableObject(object): Line 312  class LinkableObject(object):
312      the return value of the call.      the return value of the call.
313      """      """
314        
     number_sequence = itertools.count(100)  
315            
316      def __init__(self, debug=False):      def __init__(self, id = None, debug=False):
317          """          """
318      Initializes LinkableObject so that we can operate on Links      Initializes LinkableObject so that we can operate on Links
319      """      """
320          self.debug = debug          self.debug = debug
321          self.__linked_attributes={}          self.__linked_attributes={}
322          self.id = self.number_sequence.next()          
         registerLinkableObject(self.id, self)  
   
323      def trace(self, msg):      def trace(self, msg):
324          """          """
325      If debugging is on, print the message, otherwise do nothing      If debugging is on, print the message, otherwise do nothing
# Line 397  class ParameterSet(LinkableObject): Line 447  class ParameterSet(LinkableObject):
447          self.declareParameters(parameters)          self.declareParameters(parameters)
448    
449      def __repr__(self):      def __repr__(self):
450          return "<%s %r>" % (self.__class__.__name__,          return "<%s %d>"%(self.__class__.__name__,id(self))
                             [(p, getattr(self, p, None)) for p in self.parameters])  
451            
452      def declareParameter(self,**parameters):      def declareParameter(self,**parameters):
453          """          """
# Line 420  class ParameterSet(LinkableObject): Line 469  class ParameterSet(LinkableObject):
469              setattr(self,prm,value)              setattr(self,prm,value)
470              self.parameters.add(prm)              self.parameters.add(prm)
471    
             self.trace("parameter %s has been declared."%prm)  
   
472      def releaseParameters(self,name):      def releaseParameters(self,name):
473          """          """
474      Removes parameter name from the paramameters.      Removes parameter name from the paramameters.
# Line 429  class ParameterSet(LinkableObject): Line 476  class ParameterSet(LinkableObject):
476          if self.isParameter(name):          if self.isParameter(name):
477              self.parameters.remove(name)              self.parameters.remove(name)
478              self.trace("parameter %s has been removed."%name)              self.trace("parameter %s has been removed."%name)
479    
480        def checkLinkTargets(self, models, hash):
481            """
482            returns a set of tuples ("<self>(<name>)", <target model>) if the parameter <name> is linked to model <target model>
483            but <target model> is not in the list models. If the a parameter is linked to another parameter set which is not in the hash list
484            the parameter set is checked for its models. hash gives the call history.
485            """
486            out=set()
487            for name, value in self:
488                if isinstance(value, Link):
489                   m=value.getTarget()
490                   if isinstance(m, Model):
491                       if not m in models: out.add( (str(self)+"("+name+")",m) )
492                   elif isinstance(m, ParameterSet) and not m in hash:
493                         out|=set( [ (str(self)+"("+name+")."+f[0],f[1]) for f in m.checkLinkTargets(models, hash+[ self ] ) ] )
494            return out
495            
496      def __iter__(self):      def __iter__(self):
497          """          """
# Line 461  class ParameterSet(LinkableObject): Line 524  class ParameterSet(LinkableObject):
524          except:          except:
525              pass              pass
526    
527      def toDom(self, document, node):      def toDom(self, esysxml, node):
528          """          """
529      C{toDom} method of ParameterSet class.      C{toDom} method of Model class
530      """      """
531          pset = document.createElement('ParameterSet')          pset = esysxml.createElement('ParameterSet')
532            pset.setAttribute('type', self.__class__.__name__)
533            pset.setAttribute('module', self.__class__.__module__)
534            esysxml.registerLinkableObject(self, pset)
535            self._parametersToDom(esysxml, pset)
536          node.appendChild(pset)          node.appendChild(pset)
         self._parametersToDom(document, pset)  
537    
538      def _parametersToDom(self, document, node):      def _parametersToDom(self, esysxml, node):
         node.setAttribute('id', str(self.id))  
         node.setIdAttribute("id")  
539          for name,value in self:          for name,value in self:
540              param = document.createElement('Parameter')              # convert list to numarray when possible:
541              param.setAttribute('type', value.__class__.__name__)              if isinstance (value, list):
542                    elem_type=-1
543                    for i in value:
544                        if isinstance(i, bool):
545                            elem_type = max(elem_type,0)
546                        elif isinstance(i, int):
547                            elem_type = max(elem_type,1)
548                        elif isinstance(i, float):
549                            elem_type = max(elem_type,2)
550                    if elem_type == 0: value = numarray.array(value,numarray.Bool)
551                    if elem_type == 1: value = numarray.array(value,numarray.Int)
552                    if elem_type == 2: value = numarray.array(value,numarray.Float)
553    
554              param.appendChild(dataNode(document, 'Name', name))              param = esysxml.createElement('Parameter')
555                param.setAttribute('type', value.__class__.__name__)
556    
557              val = document.createElement('Value')              param.appendChild(esysxml.createDataNode('Name', name))
558    
559              if isinstance(value,(ParameterSet,Link)):              val = esysxml.createElement('Value')
560                  value.toDom(document, val)              if isinstance(value,(ParameterSet,Link,DataSource)):
561                    value.toDom(esysxml, val)
562                  param.appendChild(val)                  param.appendChild(val)
563              elif isinstance(value, numarray.NumArray):              elif isinstance(value, numarray.NumArray):
564                  shape = value.getshape()                  shape = value.getshape()
# Line 493  class ParameterSet(LinkableObject): Line 570  class ParameterSet(LinkableObject):
570                      shape = str(shape)                      shape = str(shape)
571    
572                  arraytype = value.type()                  arraytype = value.type()
573                  numarrayElement = document.createElement('NumArray')                  if isinstance(arraytype, numarray.BooleanType):
574                  numarrayElement.appendChild(dataNode(document, 'ArrayType', str(arraytype)))                        arraytype_str="Bool"
575                  numarrayElement.appendChild(dataNode(document, 'Shape', shape))                  elif isinstance(arraytype, numarray.IntegralType):
576                  numarrayElement.appendChild(dataNode(document, 'Data', ' '.join(                        arraytype_str="Int"
577                    elif isinstance(arraytype, numarray.FloatingType):
578                          arraytype_str="Float"
579                    elif isinstance(arraytype, numarray.ComplexType):
580                          arraytype_str="Complex"
581                    else:
582                          arraytype_str=str(arraytype)
583                    numarrayElement = esysxml.createElement('NumArray')
584                    numarrayElement.appendChild(esysxml.createDataNode('ArrayType', arraytype_str))
585                    numarrayElement.appendChild(esysxml.createDataNode('Shape', shape))
586                    numarrayElement.appendChild(esysxml.createDataNode('Data', ' '.join(
587                      [str(x) for x in numarray.reshape(value, size)])))                      [str(x) for x in numarray.reshape(value, size)])))
588                  val.appendChild(numarrayElement)                  val.appendChild(numarrayElement)
589                  param.appendChild(val)                  param.appendChild(val)
590              elif isinstance (value, list):              elif isinstance(value, list):
591                  param.appendChild(dataNode(document, 'Value', ' '.join(                  param.appendChild(esysxml.createDataNode('Value', ' '.join([str(x) for x in value]) ))
592                      [str(x) for x in value])              elif isinstance(value, (str, bool, int, float, type(None))):
593                  ))                  param.appendChild(esysxml.createDataNode('Value', str(value)))
594                elif isinstance(value, dict):
595                     dic = esysxml.createElement('dictionary')
596                     if len(value.keys())>0:
597                         dic.setAttribute('key_type', value.keys()[0].__class__.__name__)
598                         dic.setAttribute('value_type', value[value.keys()[0]].__class__.__name__)
599                     for k,v in value.items():
600                        i=esysxml.createElement('item')
601                        i.appendChild(esysxml.createDataNode('key', k))
602                        i.appendChild(esysxml.createDataNode('value', v))
603                        dic.appendChild(i)
604                     param.appendChild(dic)
605              else:              else:
606                  param.appendChild(dataNode(document, 'Value', str(value)))                  raise ValueError("cannot serialize %s type to XML."%str(value.__class__))
607    
608              node.appendChild(param)              node.appendChild(param)
609    
610      def fromDom(cls, doc):      def fromDom(cls, esysxml, node):
   
611          # Define a host of helper functions to assist us.          # Define a host of helper functions to assist us.
612          def _children(node):          def _children(node):
613              """              """
# Line 525  class ParameterSet(LinkableObject): Line 622  class ParameterSet(LinkableObject):
622                      ret.append(x)                      ret.append(x)
623              return ret              return ret
624    
625          def _floatfromValue(doc):          def _floatfromValue(esysxml, node):
626              return float(doc.nodeValue.strip())              return float(node.nodeValue.strip())
627    
628          def _stringfromValue(doc):          def _stringfromValue(esysxml, node):
629              return str(doc.nodeValue.strip())              return str(node.nodeValue.strip())
630                
631          def _intfromValue(doc):          def _intfromValue(esysxml, node):
632              return int(doc.nodeValue.strip())              return int(node.nodeValue.strip())
633    
634          def _boolfromValue(doc):          def _boolfromValue(esysxml, node):
635              return _boolfromstring(doc.nodeValue.strip())              return _boolfromstring(node.nodeValue.strip())
636    
637          def _nonefromValue(doc):          def _nonefromValue(esysxml, node):
638              return None              return None
639    
640          def _numarrayfromValue(doc):          def _numarrayfromValue(esysxml, node):
641              for node in _children(doc):              for node in _children(node):
642                  if node.tagName == 'ArrayType':                  if node.tagName == 'ArrayType':
643                      arraytype = node.firstChild.nodeValue.strip()                      arraytype = node.firstChild.nodeValue.strip()
644                  if node.tagName == 'Shape':                  if node.tagName == 'Shape':
# Line 553  class ParameterSet(LinkableObject): Line 650  class ParameterSet(LinkableObject):
650              return numarray.reshape(numarray.array(data, type=getattr(numarray, arraytype)),              return numarray.reshape(numarray.array(data, type=getattr(numarray, arraytype)),
651                                      shape)                                      shape)
652                
653          def _listfromValue(doc):          def _listfromValue(esysxml, node):
654              return [_boolfromstring(x) for x in doc.nodeValue.split()]              return [x for x in node.nodeValue.split()]
   
655    
656          def _boolfromstring(s):          def _boolfromstring(s):
657              if s == 'True':              if s == 'True':
# Line 567  class ParameterSet(LinkableObject): Line 663  class ParameterSet(LinkableObject):
663                      "Model":Model.fromDom,                      "Model":Model.fromDom,
664                      "ParameterSet":ParameterSet.fromDom,                      "ParameterSet":ParameterSet.fromDom,
665                      "Link":Link.fromDom,                      "Link":Link.fromDom,
666                        "DataSource":DataSource.fromDom,
667                      "float":_floatfromValue,                      "float":_floatfromValue,
668                      "int":_intfromValue,                      "int":_intfromValue,
669                      "str":_stringfromValue,                      "str":_stringfromValue,
# Line 576  class ParameterSet(LinkableObject): Line 673  class ParameterSet(LinkableObject):
673                      "NoneType":_nonefromValue,                      "NoneType":_nonefromValue,
674                      }                      }
675    
 #        print doc.toxml()  
   
676          parameters = {}          parameters = {}
677          for node in _children(doc):          for n in _children(node):
678              ptype = node.getAttribute("type")              ptype = n.getAttribute("type")
679                if not ptypemap.has_key(ptype):
680                   raise KeyError("cannot handle parameter type %s."%ptype)
681    
682              pname = pvalue = None              pname = pvalue = None
683              for childnode in _children(node):              for childnode in _children(n):
   
684                  if childnode.tagName == "Name":                  if childnode.tagName == "Name":
685                      pname = childnode.firstChild.nodeValue.strip()                      pname = childnode.firstChild.nodeValue.strip()
686    
687                  if childnode.tagName == "Value":                  if childnode.tagName == "Value":
688                      nodes = _children(childnode)                      nodes = _children(childnode)
689                  #    if ptype == 'NumArray':                      pvalue = ptypemap[ptype](esysxml, nodes[0])
                  #       pvalue = _numarrayfromValue(nodes)  
                  #   else:  
                     pvalue = ptypemap[ptype](nodes[0])  
690    
691              parameters[pname] = pvalue              parameters[pname] = pvalue
692    
693          # Create the instance of ParameterSet          # Create the instance of ParameterSet
694          o = cls()          o = cls(debug=esysxml.debug)
695          o.declareParameters(parameters)          o.declareParameters(parameters)
696          registerLinkableObject(doc.getAttribute("id"), o)          esysxml.registerLinkableObject(o, node)
697          return o          return o
698            
699      fromDom = classmethod(fromDom)      fromDom = classmethod(fromDom)
700        
701      def writeXML(self,ostream=stdout):      def writeXML(self,ostream=stdout):
702          """          """
703      Writes the object as an XML object into an output stream.      Writes the object as an XML object into an output stream.
704      """      """
705          # ParameterSet(d) with d[Name]=Value          esysxml=ESySXMLCreator()
706          document, node = esysDoc()          self.toDom(esysxml, esysxml.getRoot())
707          self.toDom(document, node)          ostream.write(esysxml.toprettyxml())
708          ostream.write(document.toprettyxml())      
   
709  class Model(ParameterSet):  class Model(ParameterSet):
710      """      """
711      A Model object represents a processess marching over time until a      A Model object represents a processess marching over time until a
712      finalizing condition is fullfilled. At each time step an iterative      finalizing condition is fullfilled. At each time step an iterative
713      process can be performed and the time step size can be controlled. A      process can be performed and the time step size can be controlled. A
714      Model has the following work flow::      Model has the following work flow::
715              
716            doInitialization()            doInitialization()
717              while not terminateInitialIteration(): doInitializationiStep()
718              doInitialPostprocessing()
719            while not finalize():            while not finalize():
720                 dt=getSafeTimeStepSize(dt)                 dt=getSafeTimeStepSize(dt)
721                 doStepPreprocessing(dt)                 doStepPreprocessing(dt)
# Line 638  class Model(ParameterSet): Line 732  class Model(ParameterSet):
732    
733      UNDEF_DT=1.e300      UNDEF_DT=1.e300
734    
735      def __init__(self,parameters=[],**kwarg):      def __init__(self,parameters=[],**kwargs):
736          """          """
737      Creates a model.      Creates a model.
738    
739          Just calls the parent constructor.          Just calls the parent constructor.
740          """          """
741          ParameterSet.__init__(self, parameters=parameters,**kwarg)          ParameterSet.__init__(self, parameters=parameters,**kwargs)
742    
743      def __str__(self):      def __str__(self):
744         return "<%s %d>"%(self.__class__,id(self))         return "<%s %d>"%(self.__class__.__name__,id(self))
745    
746    
747      def toDom(self, document, node):      def setUp(self):
748          """          """
749      C{toDom} method of Model class          Sets up the model.
750      """  
751          pset = document.createElement('Model')          This function may be overwritten.
752          pset.setAttribute('type', self.__class__.__name__)          """
753          if not self.__class__.__module__.startswith('esys.escript'):          pass
             pset.setAttribute('module', self.__class__.__module__)  
         node.appendChild(pset)  
         self._parametersToDom(document, pset)  
754    
755      def doInitialization(self):      def doInitialization(self):
756          """          """
757      Initializes the time stepping scheme.        Initializes the time stepping scheme. This method is not called in case of a restart.
758            
759      This function may be overwritten.      This function may be overwritten.
760      """      """
761          pass          pass
762        def doInitialStep(self):
763            """
764        performs an iteration step in the initialization phase. This method is not called in case of a restart.
765    
766        This function may be overwritten.
767        """
768            pass
769    
770        def terminateInitialIteration(self):
771            """
772        Returns True if iteration at the inital phase is terminated.
773        """
774            return True
775    
776        def doInitialPostprocessing(self):
777            """
778        finalises the initialization iteration process. This method is not called in case of a restart.
779    
780        This function may be overwritten.
781        """
782            pass
783            
784      def getSafeTimeStepSize(self,dt):      def getSafeTimeStepSize(self,dt):
785          """          """
# Line 717  class Model(ParameterSet): Line 830  class Model(ParameterSet):
830      Returns True if iteration on a time step is terminated.      Returns True if iteration on a time step is terminated.
831      """      """
832          return True          return True
833    
834                
835      def doStepPostprocessing(self,dt):      def doStepPostprocessing(self,dt):
836          """          """
837      Finalalizes the time step.      finalises the time step.
838    
839          dt is the currently used time step size.          dt is the currently used time step size.
840    
841          This function may be overwritten.          This function may be overwritten.
842      """      """
843          pass          pass
       
     def writeXML(self, ostream=stdout):  
         document, node = esysDoc()  
         self.toDom(document, node)  
         ostream.write(document.toprettyxml())  
       
844    
845        def toDom(self, esysxml, node):
846            """
847        C{toDom} method of Model class
848        """
849            pset = esysxml.createElement('Model')
850            pset.setAttribute('type', self.__class__.__name__)
851            pset.setAttribute('module', self.__class__.__module__)
852            esysxml.registerLinkableObject(self, pset)
853            node.appendChild(pset)
854            self._parametersToDom(esysxml, pset)
855        
856  class Simulation(Model):  class Simulation(Model):
857      """      """
858      A Simulation object is special Model which runs a sequence of Models.      A Simulation object is special Model which runs a sequence of Models.
# Line 752  class Simulation(Model): Line 871  class Simulation(Model):
871          """          """
872      Initiates a simulation from a list of models.      Initiates a simulation from a list of models.
873      """      """
874          Model.__init__(self, **kwargs)          super(Simulation, self).__init__(**kwargs)
875            self.declareParameter(time=0.,
876                                  time_step=0,
877                                  dt = self.UNDEF_DT)
878            for m in models:
879                if not isinstance(m, Model):
880                     raise TypeError("%s is not a subclass of Model."%m)
881          self.__models=[]          self.__models=[]
           
882          for i in range(len(models)):          for i in range(len(models)):
883              self[i] = models[i]              self[i] = models[i]
884                            
# Line 799  class Simulation(Model): Line 923  class Simulation(Model):
923      """      """
924          return len(self.__models)          return len(self.__models)
925    
926      def toDom(self, document, node):      def getAllModels(self):
927          """          """
928      C{toDom} method of Simulation class.          returns a list of all models used in the Simulation including subsimulations
929      """          """
930          simulation = document.createElement('Simulation')          out=[]
931          simulation.setAttribute('type', self.__class__.__name__)          for m in self.iterModels():
932                if isinstance(m, Simulation):
933          for rank, sim in enumerate(self.iterModels()):                 out+=m.getAllModels()
934              component = document.createElement('Component')              else:
935              component.setAttribute('rank', str(rank))                 out.append(m)
936            return list(set(out))
             sim.toDom(document, component)  
   
             simulation.appendChild(component)  
   
         node.appendChild(simulation)  
937    
938      def writeXML(self,ostream=stdout):      def checkModels(self, models, hash):
939          """          """
940      Writes the object as an XML object into an output stream.          returns a list of (model,parameter, target model ) if the the parameter of model
941      """          is linking to the target_model which is not in list of models.
942          document, rootnode = esysDoc()          """
943          self.toDom(document, rootnode)          out=self.checkLinkTargets(models, hash + [self])
944          targetsList = document.getElementsByTagName('Target')          for m in self.iterModels():
945                        if isinstance(m, Simulation):
946          for element in targetsList:                   out|=m.checkModels(models, hash)
947              targetId = int(element.firstChild.nodeValue.strip())              else:
948              if document.getElementById(str(targetId)):                   out|=m.checkLinkTargets(models, hash + [self])
949                  continue          return set( [ (str(self)+"."+f[0],f[1]) for f in out ] )
950              targetObj = LinkableObjectRegistry[targetId]  
             targetObj.toDom(document, rootnode)  
         ostream.write(document.toprettyxml())  
951            
952      def getSafeTimeStepSize(self,dt):      def getSafeTimeStepSize(self,dt):
953          """          """
# Line 839  class Simulation(Model): Line 956  class Simulation(Model):
956          This is the minimum over the time step sizes of all models.          This is the minimum over the time step sizes of all models.
957      """      """
958          out=min([o.getSafeTimeStepSize(dt) for o in self.iterModels()])          out=min([o.getSafeTimeStepSize(dt) for o in self.iterModels()])
         #print "%s: safe step size is %e."%(str(self),out)  
959          return out          return out
960    
961        def setUp(self):
962            """
963            performs the setup for all models
964            """
965            for o in self.iterModels():
966                 o.setUp()
967            
968      def doInitialization(self):      def doInitialization(self):
969          """          """
970      Initializes all models.      Initializes all models.
971      """      """
         self.n=0  
         self.tn=0.  
972          for o in self.iterModels():          for o in self.iterModels():
973              o.doInitialization()               o.doInitialization()
974            def doInitialStep(self):
975            """
976        performs an iteration step in the initialization step for all models
977        """
978            iter=0
979            while not self.terminateInitialIteration():
980                if iter==0: self.trace("iteration for initialization starts")
981                iter+=1
982                self.trace("iteration step %d"%(iter))
983                for o in self.iterModels():
984                     o.doInitialStep()
985                if iter>self.MAX_ITER_STEPS:
986                     raise IterationDivergenceError("initial iteration did not converge after %s steps."%iter)
987            self.trace("Initialization finalized after %s iteration steps."%iter)
988    
989        def doInitialPostprocessing(self):
990            """
991        finalises the initialization iteration process for all models.
992        """
993            for o in self.iterModels():
994                o.doInitialPostprocessing()
995      def finalize(self):      def finalize(self):
996          """          """
997      Returns True if any of the models is to be finalized.      Returns True if any of the models is to be finalized.
# Line 859  class Simulation(Model): Line 1000  class Simulation(Model):
1000                
1001      def doFinalization(self):      def doFinalization(self):
1002          """          """
1003      Finalalizes the time stepping for all models.      finalises the time stepping for all models.
1004      """      """
1005          for i in self.iterModels(): i.doFinalization()          for i in self.iterModels(): i.doFinalization()
1006          self.trace("end of time integation.")          self.trace("end of time integation.")
# Line 877  class Simulation(Model): Line 1018  class Simulation(Model):
1018      """      """
1019          out=all([o.terminateIteration() for o in self.iterModels()])          out=all([o.terminateIteration() for o in self.iterModels()])
1020          return out          return out
1021    
1022        def terminateInitialIteration(self):
1023            """
1024        Returns True if all initial iterations for all models are terminated.
1025        """
1026            out=all([o.terminateInitialIteration() for o in self.iterModels()])
1027            return out
1028                
1029      def doStepPostprocessing(self,dt):      def doStepPostprocessing(self,dt):
1030          """          """
1031      Finalalizes the iteration process for all models.      finalises the iteration process for all models.
1032      """      """
1033          for o in self.iterModels():          for o in self.iterModels():
1034              o.doStepPostprocessing(dt)              o.doStepPostprocessing(dt)
1035          self.n+=1          self.time_step+=1
1036          self.tn+=dt          self.time+=dt
1037            self.dt=dt
1038            
1039      def doStep(self,dt):      def doStep(self,dt):
1040          """          """
# Line 899  class Simulation(Model): Line 1048  class Simulation(Model):
1048          """          """
1049          self.iter=0          self.iter=0
1050          while not self.terminateIteration():          while not self.terminateIteration():
1051              if self.iter==0: self.trace("iteration at %d-th time step %e starts"%(self.n+1,self.tn+dt))              if self.iter==0: self.trace("iteration at %d-th time step %e starts"%(self.time_step+1,self.time+dt))
1052              self.iter+=1              self.iter+=1
1053              self.trace("iteration step %d"%(self.iter))              self.trace("iteration step %d"%(self.iter))
1054              for o in self.iterModels():              for o in self.iterModels():
1055                    o.doStep(dt)                    o.doStep(dt)
1056          if self.iter>0: self.trace("iteration at %d-th time step %e finalized."%(self.n+1,self.tn+dt))          if self.iter>0: self.trace("iteration at %d-th time step %e finalized."%(self.time_step+1,self.time+dt))
1057    
1058      def run(self,check_point=None):      def run(self,check_pointing=None):
1059          """          """
1060      Run the simulation by performing essentially::      Run the simulation by performing essentially::
1061            
1062          self.doInitialization()              self.setUp()
1063                if not restart:
1064                self.doInitialization()
1065                    while not self.terminateInitialIteration(): self.doInitialStep()
1066                    self.doInitialPostprocessing()
1067          while not self.finalize():          while not self.finalize():
1068              dt=self.getSafeTimeStepSize()              dt=self.getSafeTimeStepSize()
1069              self.doStep(dt)                  self.doStepPreprocessing(dt_new)
1070              if n%check_point==0:                  self.doStep(dt_new)
1071              self.writeXML()                  self.doStepPostprocessing(dt_new)
1072          self.doFinalization()          self.doFinalization()
1073    
1074          If one of the models in throws a C{FailedTimeStepError} exception a          If one of the models in throws a C{FailedTimeStepError} exception a
# Line 928  class Simulation(Model): Line 1081  class Simulation(Model):
1081          In both cases the time integration is given up after          In both cases the time integration is given up after
1082      C{Simulation.FAILED_TIME_STEPS_MAX} attempts.      C{Simulation.FAILED_TIME_STEPS_MAX} attempts.
1083          """          """
1084          dt=self.UNDEF_DT          # check the completness of the models:
1085          self.doInitialization()          # first a list of all the models involved in the simulation including subsimulations:
1086            #
1087            missing=self.checkModels(self.getAllModels(), [])
1088            if len(missing)>0:
1089                msg=""
1090                for l in missing:
1091                     msg+="\n\t"+str(l[1])+" at "+l[0]
1092                raise MissingLink("link targets missing in the Simulation: %s"%msg)
1093            #==============================
1094            self.setUp()
1095            if self.time_step < 1:
1096               self.doInitialization()
1097               self.doInitialStep()
1098               self.doInitialPostprocessing()
1099          while not self.finalize():          while not self.finalize():
1100              step_fail_counter=0              step_fail_counter=0
1101              iteration_fail_counter=0              iteration_fail_counter=0
1102              if self.n==0:              if self.time_step==0:
1103                  dt_new=self.getSafeTimeStepSize(dt)                  dt_new=self.getSafeTimeStepSize(self.dt)
1104              else:              else:
1105                  dt_new=min(max(self.getSafeTimeStepSize(dt),dt/self.MAX_CHANGE_OF_DT),dt*self.MAX_CHANGE_OF_DT)                  dt_new=min(max(self.getSafeTimeStepSize(self.dt),self.dt/self.MAX_CHANGE_OF_DT),self.dt*self.MAX_CHANGE_OF_DT)
1106              self.trace("%d. time step %e (step size %e.)" % (self.n+1,self.tn+dt_new,dt_new))              self.trace("%d. time step %e (step size %e.)" % (self.time_step+1,self.time+dt_new,dt_new))
1107              end_of_step=False              end_of_step=False
1108              while not end_of_step:              while not end_of_step:
1109                 end_of_step=True                 end_of_step=True
1110                 if not dt_new>0:                 if not dt_new>0:
1111                    raise NonPositiveStepSizeError("non-positive step size in step %d"%(self.n+1))                    raise NonPositiveStepSizeError("non-positive step size in step %d"%(self.time_step+1))
1112                 try:                 try:
1113                    self.doStepPreprocessing(dt_new)                    self.doStepPreprocessing(dt_new)
1114                    self.doStep(dt_new)                    self.doStep(dt_new)
# Line 955  class Simulation(Model): Line 1121  class Simulation(Model):
1121                             raise SimulationBreakDownError("reduction of time step to achieve convergence failed after %s steps."%self.FAILED_TIME_STEPS_MAX)                             raise SimulationBreakDownError("reduction of time step to achieve convergence failed after %s steps."%self.FAILED_TIME_STEPS_MAX)
1122                    self.trace("Iteration failed. Time step is repeated with new step size %s."%dt_new)                    self.trace("Iteration failed. Time step is repeated with new step size %s."%dt_new)
1123                 except FailedTimeStepError:                 except FailedTimeStepError:
1124                    dt_new=self.getSafeTimeStepSize(dt)                    dt_new=self.getSafeTimeStepSize(self.dt)
1125                    end_of_step=False                    end_of_step=False
1126                    step_fail_counter+=1                    step_fail_counter+=1
1127                    self.trace("Time step is repeated with new time step size %s."%dt_new)                    self.trace("Time step is repeated with new time step size %s."%dt_new)
1128                    if step_fail_counter>self.FAILED_TIME_STEPS_MAX:                    if step_fail_counter>self.FAILED_TIME_STEPS_MAX:
1129                          raise SimulationBreakDownError("Time integration is given up after %d attempts."%step_fail_counter)                          raise SimulationBreakDownError("Time integration is given up after %d attempts."%step_fail_counter)
1130              dt=dt_new              if not check_pointing==None:
1131              if not check_point==None:                 if check_pointing.doDump():
                 if n%check_point==0:  
1132                      self.trace("check point is created.")                      self.trace("check point is created.")
1133                      self.writeXML()                      self.writeXML()
1134          self.doFinalization()          self.doFinalization()
1135    
     def fromDom(cls, doc):  
         sims = []  
         for node in doc.childNodes:  
             if isinstance(node, minidom.Text):  
                 continue  
1136    
1137              sims.append(getComponent(node))      def toDom(self, esysxml, node):
1138            """
1139        C{toDom} method of Simulation class.
1140        """
1141            simulation = esysxml.createElement('Simulation')
1142            esysxml.registerLinkableObject(self, simulation)
1143            for rank, sim in enumerate(self.iterModels()):
1144                component = esysxml.createElement('Component')
1145                component.setAttribute('rank', str(rank))
1146                sim.toDom(esysxml, component)
1147                simulation.appendChild(component)
1148            node.appendChild(simulation)
1149    
1150          return cls(sims)  
1151        def fromDom(cls, esysxml, node):
1152            sims = []
1153            for n in node.childNodes:
1154                if isinstance(n, minidom.Text):
1155                    continue
1156                sims.append(esysxml.getComponent(n))
1157            sims.sort(cmp=_comp)
1158            sim=cls([s[1] for s in sims], debug=esysxml.debug)
1159            esysxml.registerLinkableObject(sim, node)
1160            return sim
1161    
1162      fromDom = classmethod(fromDom)      fromDom = classmethod(fromDom)
1163    
1164    def _comp(a,b):
1165        if a[0]<a[1]:
1166          return 1
1167        elif a[0]>a[1]:
1168          return -1
1169        else:
1170          return 0
1171    
1172  class IterationDivergenceError(Exception):  class IterationDivergenceError(Exception):
1173      """      """
# Line 1010  class NonPositiveStepSizeError(Exception Line 1198  class NonPositiveStepSizeError(Exception
1198      """      """
1199      pass      pass
1200    
1201    class MissingLink(Exception):
1202        """
1203        Exception thrown when a link is missing
1204        """
1205        pass
1206    
1207    class DataSource(object):
1208        """
1209        Class for handling data sources, including local and remote files. This class is under development.
1210        """
1211    
1212        def __init__(self, uri="file.ext", fileformat="unknown"):
1213            self.uri = uri
1214            self.fileformat = fileformat
1215    
1216        def toDom(self, esysxml, node):
1217            """
1218            C{toDom} method of DataSource. Creates a DataSource node and appends it to the
1219        current XML esysxml.
1220            """
1221            ds = esysxml.createElement('DataSource')
1222            ds.appendChild(esysxml.createDataNode('URI', self.uri))
1223            ds.appendChild(esysxml.createDataNode('FileFormat', self.fileformat))
1224            node.appendChild(ds)
1225    
1226        def fromDom(cls, esysxml, node):
1227            uri= str(node.getElementsByTagName("URI")[0].firstChild.nodeValue.strip())
1228            fileformat= str(node.getElementsByTagName("FileFormat")[0].firstChild.nodeValue.strip())
1229            ds = cls(uri, fileformat)
1230            return ds
1231    
1232        def getLocalFileName(self):
1233            return self.uri
1234    
1235        fromDom = classmethod(fromDom)
1236    
1237    class RestartManager(object):
1238         """
1239         A restart manager which does two things: it decides when restart files have created (when doDump returns true) and
1240         manages directories for restart files. The method getNewDumper creates a new directory and returns its name.
1241        
1242         This restart manager will decide to dump restart files if every dump_step calls of doDump or
1243         if more than dump_time since the last dump has elapsed. The restart manager controls two directories for dumping restart data, namely
1244         for the current and previous dump. This way the previous dump can be used for restart in the case the current dump failed.
1245    
1246         @cvar SEC: unit of seconds, for instance for 5*RestartManager.SEC to define 5 seconds.
1247         @cvar MIN: unit of minutes, for instance for 5*RestartManager.MIN to define 5 minutes.
1248         @cvar H: unit of hours, for instance for 5*RestartManager.H to define 5 hours.
1249         @cvar D: unit of days, for instance for 5*RestartManager.D to define 5 days.
1250         """
1251         SEC=1.
1252         MIN=60.
1253         H=360.
1254         D=8640.
1255         def __init__(self,dump_time=1080., dump_step=None, dumper=None):
1256             """
1257             initializes the RestartManager.
1258    
1259             @param dump_time: defines the minimum time interval in SEC between to dumps. If None, time is not used as criterion.
1260             @param dump_step: defines the number of calls of doDump between to dump events. If None, the call counter is not used as criterion.
1261             @param dumper: defines the directory for dumping restart files. Additionally the directories dumper+"_bkp" and dumper+"_bkp2" are used.
1262                            if the directory does not exist it is created. If dumper is not present a unique directory within the current
1263                            working directory is used.
1264             """
1265             self.__dump_step=dump_time
1266             self.__dump_time=dump_step
1267             self.__counter=0
1268             self.__saveMarker()
1269             if dumper == None:
1270                self.__dumper="restart"+str(os.getpid())
1271             else:
1272                self.__dumper=dumper
1273             self.__dumper_bkp=self.__dumper+"_bkp"
1274             self.__dumper_bkp2=self.__dumper+"_bkp2"
1275             self.__current_dumper=None
1276         def __saveMarker(self):
1277             self.__last_restart_time=time.time()
1278             self.__last_restart_counter=self.__counter
1279         def getCurrentDumper(self):
1280             """
1281             returns the name of the currently used dumper
1282             """
1283             return self.__current_dumper
1284         def doDump(self):
1285            """
1286            returns true the restart should be dumped. use C{getNewDumper} to get the directory name to be used.
1287            """
1288            if self.__dump_step == None:
1289               if self.__dump_step == None:
1290                  out = False
1291               else:
1292                  out = (self.__dump_step + self.__last_restart_counter) <= self.__counter
1293            else:
1294               if dump_step == None:
1295                  out = (self.__last_restart_time + self.__dump_time) <= time.time()
1296               else:
1297                  out =    ( (self.__dump_step + self.__last_restart_counter) <= self.__counter)  \
1298                        or ( (self.__last_restart_time + self.__dump_time) <= time.time() )
1299            if out: self.__saveMarker()
1300            self__counter+=1
1301         def getNewDumper(self):
1302           """
1303           creates a new directory to be used for dumping and returns its name.
1304           """
1305           if os.access(self.__dumper_bkp,os.F_OK):
1306              if os.access(self.__dumper_bkp2, os.F_OK):
1307                 raise RunTimeError("please remove %s."%self.__dumper_bkp2)
1308              try:
1309                 os.rename(self.__dumper_bkp, self.__dumper_bkp2)
1310              except:
1311                 self.__current_dumper=self.__dumper
1312                 raise RunTimeError("renaming back-up directory %s failed. Use %s for restart."%(self.__dumper_bkp,self.__dumper))
1313           if os.access(self.__dumper,os.F_OK):
1314              if os.access(self.__dumper_bkp, os.F_OK):
1315                 raise RunTimeError("please remove %s."%self.__dumper_bkp)
1316              try:
1317                 os.rename(self.__dumper, self.__dumper_bkp)
1318              except:
1319                 self.__current_dumper=self.__dumper_bkp2
1320                 raise RunTimeError("moving directory %s to back-up failed. Use %s for restart."%(self.__dumper,self.__dumper_bkp2))
1321           try:
1322              os.mkdir(self.__dumper)
1323           except:
1324              self.__current_dumper=self.__dumper_bkp
1325              raise RunTimeError("creating a new restart directory %s failed. Use %s for restart."%(self.__dumper,self.__dumper_bkp))
1326           if os.access(self.__dumper_bkp2, os.F_OK): os.rmdir(self.__dumper_bkp2)
1327           return self.getCurrentDumper()
1328            
1329        
1330  # vim: expandtab shiftwidth=4:  # vim: expandtab shiftwidth=4:

Legend:
Removed from v.874  
changed lines
  Added in v.980

  ViewVC Help
Powered by ViewVC 1.1.26