/[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 266 by elspeth, Wed Nov 30 00:21:51 2005 UTC revision 952 by gross, Wed Feb 7 23:53:24 2007 UTC
# Line 1  Line 1 
1  # $Id$  # $Id$
2    
3    """
4    Environment for implementing models in escript
5    
6    @var __author__: name of author
7    @var __copyright__: copyrights
8    @var __license__: licence agreement
9    @var __url__: url entry point on documentation
10    @var __version__: version
11    @var __date__: date of the version
12    """
13    
14    __author__="Lutz Gross, l.gross@uq.edu.au"
15    __copyright__="""  Copyright (c) 2006 by ACcESS MNRF
16                        http://www.access.edu.au
17                    Primary Business: Queensland, Australia"""
18    __license__="""Licensed under the Open Software License version 3.0
19                 http://www.opensource.org/licenses/osl-3.0.php"""
20    __url__="http://www.iservo.edu.au/esys"
21    __version__="$Revision$"
22    __date__="$Date$"
23    
24    
25  from types import StringType,IntType,FloatType,BooleanType,ListType,DictType  from types import StringType,IntType,FloatType,BooleanType,ListType,DictType
26  from sys import stdout  from sys import stdout
27    import numarray
28    import operator
29  import itertools  import itertools
 # import modellib  temporarily removed!!!  
30    
31  # 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)
32  try:  try:
# Line 13  except NameError: Line 36  except NameError:
36    
37  from xml.dom import minidom  from xml.dom import minidom
38    
 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  
39    
40  def all(seq):  def all(seq):
41      for x in seq:      for x in seq:
# Line 48  def any(seq): Line 49  def any(seq):
49              return True              return True
50      return False      return False
51    
 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  
   
52  def importName(modulename, name):  def importName(modulename, name):
53      """ 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,
54          which means you should use fully qualified module paths.          which means you should use fully qualified module paths.
           
55          Return None on failure.          Return None on failure.
56    
57          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 88  def importName(modulename, name): Line 63  def importName(modulename, name):
63      except KeyError:      except KeyError:
64          raise ImportError("Could not import %s from %s" % (name, modulename))          raise ImportError("Could not import %s from %s" % (name, modulename))
65    
66  def getComponent(doc):  class ESySXMLParser(object):
     """  
     Used to get components of Simualtions, Models.  
67      """      """
68      for node in doc.childNodes:      parser for ESysXML file
69                """
70          if isinstance(node, minidom.Element):      def __init__(self,xml, debug=False):
71              if node.tagName == 'Simulation':        self.__dom = minidom.parseString(xml)
72                  if node.getAttribute("type") == 'Simulation':        self.__linkable_object_registry= {}
73                      return Simulation.fromDom(node)        self.__link_registry=  []
74              if node.tagName == 'Model':        self.__esys=self.__dom.getElementsByTagName('ESys')[0]
75                  if (node.getAttribute("module")):        self.debug=debug
76                      model_module = node.getAttribute("module")    
77                      model_type = node.getAttribute("type")      def getClassPath(self, node):
78                      return importName(model_module, model_type).fromDom(node)          type = node.getAttribute("type")
79                  else:          if (node.getAttribute("module")):
80                      model_type = node.getAttribute("type")              module = node.getAttribute("module")
81                      model_subclasses = Model.__subclasses__()              return importName(module, type)
82                      for model in model_subclasses:          else:
83                          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")  
           
   
     raise ValueError("No Simulation Found")  
               
84    
85        def setLinks(self):
86            for obj_id, link in self.__link_registry:
87                link.target = self.__linkable_object_registry[obj_id]
88    
89        def parse(self):
90           """
91           parser method for EsysXML and returns the list of generating ParameterSets
92           """
93           found=[]
94           for node in self.__esys.childNodes:
95               if isinstance(node, minidom.Element):
96                   if node.tagName == 'Simulation':
97                            found.append(Simulation.fromDom(self, node))
98                   elif node.tagName == 'Model':
99                            found.append(self.getClassPath(node).fromDom(self, node))
100                   elif node.tagName == 'ParameterSet':
101                            found.append(self.getClassPath(node).fromDom(self, node))
102                   else:
103                      raise "Invalid type, %r" % node.getAttribute("type")
104           self.setLinks()
105           return found
106    
107        def registerLink(self,obj_id, link):
108            self.__link_registry.append((int(obj_id),link))
109    
110        def registerLinkableObject(self,obj, node):
111            id_str=node.getAttribute('id').strip()
112            if len(id_str)>0:
113               id=int(id_str)
114               if self.__linkable_object_registry.has_key(id):
115                   raise ValueError("Object id %s already exists."%id)
116               else:
117                   self.__linkable_object_registry[id]=obj
118    
119        def getComponent(self, node):
120           """
121           returns a single component + rank from a simulation
122           parser method for EsysXML and returns the list of generating ParameterSets
123           """
124           rank  = int(node.getAttribute("rank"))
125           for n in node.childNodes:
126               if isinstance(n, minidom.Element):
127                   if n.tagName == 'Simulation':
128                            return (rank, Simulation.fromDom(self, n))
129                   elif n.tagName == 'Model':
130                            return (rank, self.getClassPath(n).fromDom(self, n))
131                   elif n.tagName == 'ParameterSet':
132                            return (rank, self.getClassPath(n).fromDom(self, n))
133                   else:
134                     raise ValueError("illegal component type %s"%n.tagName)
135           raise ValueError("cannot resolve Component")
136    
137    class ESySXMLCreator(object):
138        """
139        creates an XML Dom representation
140        """
141        def __init__(self):
142           self.__dom=minidom.Document()
143           self.__esys =self.__dom.createElement('ESys')
144           self.__dom.appendChild(self.__esys)
145           self.__linkable_object_registry={}
146           self.__number_sequence = itertools.count(100)
147        def getRoot(self):
148           return self.__esys
149        def createElement(self,name):
150          return self.__dom.createElement(name)
151        def createTextNode(self,name):
152          return self.__dom.createTextNode(name)
153        def getElementById(self,name):
154          return self.__dom.getElementById(name)
155        def createDataNode(self, tagName, data):
156              """
157              C{createDataNode}s are the building blocks of the xml documents constructed in
158              this module.  
159        
160              @param tagName: the associated xml tag
161              @param data: the values in the tag
162              """
163              n = self.createElement(tagName)
164              n.appendChild(self.createTextNode(str(data)))
165              return n
166        def getLinkableObjectId(self, obj):
167            for id, o in self.__linkable_object_registry.items():
168                if o == obj: return id
169            id =self.__number_sequence.next()
170            self.__linkable_object_registry[id]=obj
171            return id
172            
173        def registerLinkableObject(self, obj, node):
174            """
175            returns a unique object id for object obj
176            """
177            id=self.getLinkableObjectId(obj)
178            node.setAttribute('id',str(id))
179            node.setIdAttribute("id")
180    
181        def includeTargets(self):
182            target_written=True
183            while target_written:
184                targetsList =self.__dom.getElementsByTagName('Target')
185                target_written=False
186                for element in targetsList:
187                   targetId = int(element.firstChild.nodeValue.strip())
188                   if self.getElementById(str(targetId)): continue
189                   targetObj = self.__linkable_object_registry[targetId]
190                   targetObj.toDom(self, self.__esys)
191                   target_written=True
192    
193        def toprettyxml(self):
194            self.includeTargets()
195            return self.__dom.toprettyxml()
196    
197  class Link:  class Link:
198      """      """
199      A Link makes an attribute of an object callable::      A Link makes an attribute of an object callable::
# Line 137  class Link: Line 213  class Link:
213          self.target = target          self.target = target
214          self.attribute = None          self.attribute = None
215          self.setAttributeName(attribute)          self.setAttributeName(attribute)
216    
217        def getTarget(self):
218            """
219            returns the target
220            """
221            return self.target
222        def getAttributeName(self):
223            """
224            returns the name of the attribute the link is pointing to
225            """
226            return self.attribute
227            
228      def setAttributeName(self,attribute):      def setAttributeName(self,attribute):
229          """          """
# Line 182  class Link: Line 269  class Link:
269          else:          else:
270              return out              return out
271    
272      def toDom(self, document, node):      def toDom(self, esysxml, node):
273          """          """
274          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
275      current XML document.      current XML esysxml.
276          """          """
277          link = document.createElement('Link')          link = esysxml.createElement('Link')
278          assert (self.target != None), ("Target was none, name was %r" % self.attribute)          assert (self.target != None), ("Target was none, name was %r" % self.attribute)
279          link.appendChild(dataNode(document, 'Target', self.target.id))          link.appendChild(esysxml.createDataNode('Target', esysxml.getLinkableObjectId(self.target)))
280          # 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
281          # target from the xml later. I need a better unique identifier.          # target from the xml later. I need a better unique identifier.
282          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"
283          link.appendChild(dataNode(document, 'Attribute', self.attribute))          link.appendChild(esysxml.createDataNode('Attribute', self.attribute))
284          node.appendChild(link)          node.appendChild(link)
285    
286      def fromDom(cls, doc):      def fromDom(cls, esysxml, node):
287          targetid = doc.getElementsByTagName("Target")[0].firstChild.nodeValue.strip()          targetid = int(node.getElementsByTagName("Target")[0].firstChild.nodeValue.strip())
288          attribute = doc.getElementsByTagName("Attribute")[0].firstChild.nodeValue.strip()          attribute =str(node.getElementsByTagName("Attribute")[0].firstChild.nodeValue.strip())
289          l = cls(None, attribute)          l = cls(None, attribute)
290          registerLink(targetid, l)          esysxml.registerLink(targetid, l)
291          return l          return l
292    
293      fromDom = classmethod(fromDom)      fromDom = classmethod(fromDom)
294            
     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())  
   
295  class LinkableObject(object):  class LinkableObject(object):
296      """      """
297      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 235  class LinkableObject(object): Line 310  class LinkableObject(object):
310      the return value of the call.      the return value of the call.
311      """      """
312        
     number_sequence = itertools.count(100)  
313            
314      def __init__(self, debug=False):      def __init__(self, id = None, debug=False):
315          """          """
316      Initializes LinkableObject so that we can operate on Links      Initializes LinkableObject so that we can operate on Links
317      """      """
318          self.debug = debug          self.debug = debug
319          self.__linked_attributes={}          self.__linked_attributes={}
320          self.id = self.number_sequence.next()          
         registerLinkableObject(self.id, self)  
   
321      def trace(self, msg):      def trace(self, msg):
322          """          """
323      If debugging is on, print the message, otherwise do nothing      If debugging is on, print the message, otherwise do nothing
# Line 342  class ParameterSet(LinkableObject): Line 414  class ParameterSet(LinkableObject):
414       - a ParameterSet object       - a ParameterSet object
415       - a Simulation object       - a Simulation object
416       - a Model object       - a Model object
417       - any other object (not considered by writeESySXML and writeXML)       - a numarray object
418             - a list of booleans
419            - any other object (not considered by writeESySXML and writeXML)
420            
421      Example how to create an ESySParameters object::      Example how to create an ESySParameters object::
422            
# Line 371  class ParameterSet(LinkableObject): Line 445  class ParameterSet(LinkableObject):
445          self.declareParameters(parameters)          self.declareParameters(parameters)
446    
447      def __repr__(self):      def __repr__(self):
448          return "<%s %r>" % (self.__class__.__name__,          return "<%s %d>"%(self.__class__.__name__,id(self))
                             [(p, getattr(self, p, None)) for p in self.parameters])  
449            
450      def declareParameter(self,**parameters):      def declareParameter(self,**parameters):
451          """          """
# Line 403  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 435  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))  
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                        if isinstance(i, int) and not isinstance(i, bool):
547                            elem_type = max(elem_type,1)
548                        if 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):              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, Link):              elif isinstance(value, numarray.NumArray):
564                  value.toDom(document, val)                  shape = value.getshape()
565                    if isinstance(shape, tuple):
566                        size = reduce(operator.mul, shape)
567                        shape = ' '.join(map(str, shape))
568                    else:
569                        size = shape
570                        shape = str(shape)
571    
572                    arraytype = value.type()
573                    if isinstance(arraytype, numarray.BooleanType):
574                          arraytype_str="Bool"
575                    elif isinstance(arraytype, numarray.IntegralType):
576                          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)])))
588                    val.appendChild(numarrayElement)
589                  param.appendChild(val)                  param.appendChild(val)
590              elif isinstance(value,StringType):              elif isinstance(value, list):
591                  param.appendChild(dataNode(document, 'Value', value))                  param.appendChild(esysxml.createDataNode('Value', ' '.join([str(x) for x in value]) ))
592                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              """              """
614              Remove the empty nodes from the children of this node.              Remove the empty nodes from the children of this node.
615              """              """
616              return [x for x in node.childNodes              ret = []
617                      if not isinstance(x, minidom.Text) or x.nodeValue.strip()]              for x in node.childNodes:
618                    if isinstance(x, minidom.Text):
619                        if x.nodeValue.strip():
620                            ret.append(x)
621                    else:
622                        ret.append(x)
623                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 bool(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(esysxml, node):
641                for node in _children(node):
642                    if node.tagName == 'ArrayType':
643                        arraytype = node.firstChild.nodeValue.strip()
644                    if node.tagName == 'Shape':
645                        shape = node.firstChild.nodeValue.strip()
646                        shape = [int(x) for x in shape.split()]
647                    if node.tagName == 'Data':
648                        data = node.firstChild.nodeValue.strip()
649                        data = [float(x) for x in data.split()]
650                return numarray.reshape(numarray.array(data, type=getattr(numarray, arraytype)),
651                                        shape)
652          
653            def _listfromValue(esysxml, node):
654                return [x for x in node.nodeValue.split()]
655    
656            def _boolfromstring(s):
657                if s == 'True':
658                    return True
659                else:
660                    return False
661          # Mapping from text types in the xml to methods used to process trees of that type          # Mapping from text types in the xml to methods used to process trees of that type
662          ptypemap = {"Simulation": Simulation.fromDom,          ptypemap = {"Simulation": Simulation.fromDom,
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,
670                      "bool":_boolfromValue                      "bool":_boolfromValue,
671                        "list":_listfromValue,
672                        "NumArray":_numarrayfromValue,
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                      pvalue = ptypemap[ptype](nodes[0])                      pvalue = ptypemap[ptype](esysxml, 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 562  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    
     def toDom(self, document, node):  
         """  
     C{toDom} method of Model class  
     """  
         pset = document.createElement('Model')  
         pset.setAttribute('type', self.__class__.__name__)  
         if not self.__class__.__module__.startswith('esys.escript'):  
             pset.setAttribute('module', self.__class__.__module__)  
         node.appendChild(pset)  
         self._parametersToDom(document, pset)  
746    
747      def doInitialization(self):      def doInitialization(self):
748          """          """
# Line 591  class Model(ParameterSet): Line 751  class Model(ParameterSet):
751      This function may be overwritten.      This function may be overwritten.
752      """      """
753          pass          pass
754        def doInitialStep(self):
755            """
756        performs an iteration step in the initialization phase
757    
758        This function may be overwritten.
759        """
760            pass
761    
762        def terminateInitialIteration(self):
763            """
764        Returns True if iteration at the inital phase is terminated.
765        """
766            return True
767    
768        def doInitialPostprocessing(self):
769            """
770        finalises the initialization iteration process
771    
772        This function may be overwritten.
773        """
774            pass
775            
776      def getSafeTimeStepSize(self,dt):      def getSafeTimeStepSize(self,dt):
777          """          """
# Line 641  class Model(ParameterSet): Line 822  class Model(ParameterSet):
822      Returns True if iteration on a time step is terminated.      Returns True if iteration on a time step is terminated.
823      """      """
824          return True          return True
825    
826                
827      def doStepPostprocessing(self,dt):      def doStepPostprocessing(self,dt):
828          """          """
829      Finalalizes the time step.      finalises the time step.
830    
831          dt is the currently used time step size.          dt is the currently used time step size.
832    
833          This function may be overwritten.          This function may be overwritten.
834      """      """
835          pass          pass
       
     def writeXML(self, ostream=stdout):  
         document, node = esysDoc()  
         self.toDom(document, node)  
         ostream.write(document.toprettyxml())  
       
836    
837        def toDom(self, esysxml, node):
838            """
839        C{toDom} method of Model class
840        """
841            pset = esysxml.createElement('Model')
842            pset.setAttribute('type', self.__class__.__name__)
843            pset.setAttribute('module', self.__class__.__module__)
844            esysxml.registerLinkableObject(self, pset)
845            node.appendChild(pset)
846            self._parametersToDom(esysxml, pset)
847        
848  class Simulation(Model):  class Simulation(Model):
849      """      """
850      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 670  class Simulation(Model): Line 857  class Simulation(Model):
857            
858      FAILED_TIME_STEPS_MAX=20      FAILED_TIME_STEPS_MAX=20
859      MAX_ITER_STEPS=50      MAX_ITER_STEPS=50
860        MAX_CHANGE_OF_DT=2.
861            
862      def __init__(self, models=[], **kwargs):      def __init__(self, models=[], **kwargs):
863          """          """
864      Initiates a simulation from a list of models.      Initiates a simulation from a list of models.
865      """      """
866          Model.__init__(self, **kwargs)          super(Simulation, self).__init__(**kwargs)
867            for m in models:
868                if not isinstance(m, Model):
869                     raise TypeError("%s is not a subclass of Model."%m)
870          self.__models=[]          self.__models=[]
           
871          for i in range(len(models)):          for i in range(len(models)):
872              self[i] = models[i]              self[i] = models[i]
873                            
# Line 711  class Simulation(Model): Line 901  class Simulation(Model):
901      Sets the i-th model.      Sets the i-th model.
902      """      """
903          if not isinstance(value,Model):          if not isinstance(value,Model):
904              raise ValueError("assigned value is not a Model")              raise ValueError,"assigned value is not a Model but instance of %s"%(value.__class__.__name__,)
905          for j in range(max(i-len(self.__models)+1,0)):          for j in range(max(i-len(self.__models)+1,0)):
906              self.__models.append(None)              self.__models.append(None)
907          self.__models[i]=value          self.__models[i]=value
# Line 722  class Simulation(Model): Line 912  class Simulation(Model):
912      """      """
913          return len(self.__models)          return len(self.__models)
914    
915      def toDom(self, document, node):      def getAllModels(self):
916          """          """
917      C{toDom} method of Simulation class.          returns a list of all models used in the Simulation including subsimulations
918      """          """
919          simulation = document.createElement('Simulation')          out=[]
920          simulation.setAttribute('type', self.__class__.__name__)          for m in self.iterModels():
921                if isinstance(m, Simulation):
922          for rank, sim in enumerate(self.iterModels()):                 out+=m.getAllModels()
923              component = document.createElement('Component')              else:
924              component.setAttribute('rank', str(rank))                 out.append(m)
925            return list(set(out))
             sim.toDom(document, component)  
   
             simulation.appendChild(component)  
   
         node.appendChild(simulation)  
926    
927      def writeXML(self,ostream=stdout):      def checkModels(self, models, hash):
928          """          """
929      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
930      """          is linking to the target_model which is not in list of models.
931          document, rootnode = esysDoc()          """
932          self.toDom(document, rootnode)          out=self.checkLinkTargets(models, hash + [self])
933          targetsList = document.getElementsByTagName('Target')          for m in self.iterModels():
934          for i in targetsList:              if isinstance(m, Simulation):
935              targetId = int(i.firstChild.nodeValue.strip())                   out|=m.checkModels(models, hash)
936              targetObj = LinkableObjectRegistry[targetId]              else:
937              targetObj.toDom(document, rootnode)                   out|=m.checkLinkTargets(models, hash + [self])
938          ostream.write(document.toprettyxml())          return set( [ (str(self)+"."+f[0],f[1]) for f in out ] )
939    
940            
941      def getSafeTimeStepSize(self,dt):      def getSafeTimeStepSize(self,dt):
942          """          """
# Line 759  class Simulation(Model): Line 945  class Simulation(Model):
945          This is the minimum over the time step sizes of all models.          This is the minimum over the time step sizes of all models.
946      """      """
947          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)  
948          return out          return out
949            
950      def doInitialization(self):      def doInitialization(self):
# Line 769  class Simulation(Model): Line 954  class Simulation(Model):
954          self.n=0          self.n=0
955          self.tn=0.          self.tn=0.
956          for o in self.iterModels():          for o in self.iterModels():
957              o.doInitialization()               o.doInitialization()
958            def doInitialStep(self):
959            """
960        performs an iteration step in the initialization step for all models
961        """
962            iter=0
963            while not self.terminateInitialIteration():
964                if iter==0: self.trace("iteration for initialization starts")
965                iter+=1
966                self.trace("iteration step %d"%(iter))
967                for o in self.iterModels():
968                     o.doInitialStep()
969                if iter>self.MAX_ITER_STEPS:
970                     raise IterationDivergenceError("initial iteration did not converge after %s steps."%iter)
971            self.trace("Initialization finalized after %s iteration steps."%iter)
972    
973        def doInitialPostprocessing(self):
974            """
975        finalises the initialization iteration process for all models.
976        """
977            for o in self.iterModels():
978                o.doInitialPostprocessing()
979      def finalize(self):      def finalize(self):
980          """          """
981      Returns True if any of the models is to be finalized.      Returns True if any of the models is to be finalized.
# Line 779  class Simulation(Model): Line 984  class Simulation(Model):
984                
985      def doFinalization(self):      def doFinalization(self):
986          """          """
987      Finalalizes the time stepping for all models.      finalises the time stepping for all models.
988      """      """
989          for i in self.iterModels(): i.doFinalization()          for i in self.iterModels(): i.doFinalization()
990          self.trace("end of time integation.")          self.trace("end of time integation.")
# Line 797  class Simulation(Model): Line 1002  class Simulation(Model):
1002      """      """
1003          out=all([o.terminateIteration() for o in self.iterModels()])          out=all([o.terminateIteration() for o in self.iterModels()])
1004          return out          return out
1005    
1006        def terminateInitialIteration(self):
1007            """
1008        Returns True if all initial iterations for all models are terminated.
1009        """
1010            out=all([o.terminateInitialIteration() for o in self.iterModels()])
1011            return out
1012                
1013      def doStepPostprocessing(self,dt):      def doStepPostprocessing(self,dt):
1014          """          """
1015      Finalalizes the iteration process for all models.      finalises the iteration process for all models.
1016      """      """
1017          for o in self.iterModels():          for o in self.iterModels():
1018              o.doStepPostprocessing(dt)              o.doStepPostprocessing(dt)
# Line 831  class Simulation(Model): Line 1043  class Simulation(Model):
1043      Run the simulation by performing essentially::      Run the simulation by performing essentially::
1044            
1045          self.doInitialization()          self.doInitialization()
1046                while not self.terminateInitialIteration(): self.doInitialStep()
1047                self.doInitialPostprocessing()
1048          while not self.finalize():          while not self.finalize():
1049              dt=self.getSafeTimeStepSize()              dt=self.getSafeTimeStepSize()
1050              self.doStep(dt)              self.doStep(dt)
# Line 848  class Simulation(Model): Line 1062  class Simulation(Model):
1062          In both cases the time integration is given up after          In both cases the time integration is given up after
1063      C{Simulation.FAILED_TIME_STEPS_MAX} attempts.      C{Simulation.FAILED_TIME_STEPS_MAX} attempts.
1064          """          """
1065          dt=self.UNDEF_DT          # check the completness of the models:
1066            # first a list of all the models involved in the simulation including subsimulations:
1067            #
1068            missing=self.checkModels(self.getAllModels(), [])
1069            if len(missing)>0:
1070                msg=""
1071                for l in missing:
1072                     msg+="\n\t"+str(l[1])+" at "+l[0]
1073                raise MissingLink("link targets missing in the Simulation: %s"%msg)
1074            #==============================
1075          self.doInitialization()          self.doInitialization()
1076            self.doInitialStep()
1077            self.doInitialPostprocessing()
1078            dt=self.UNDEF_DT
1079          while not self.finalize():          while not self.finalize():
1080              step_fail_counter=0              step_fail_counter=0
1081              iteration_fail_counter=0              iteration_fail_counter=0
1082              dt_new=self.getSafeTimeStepSize(dt)              if self.n==0:
1083                    dt_new=self.getSafeTimeStepSize(dt)
1084                else:
1085                    dt_new=min(max(self.getSafeTimeStepSize(dt),dt/self.MAX_CHANGE_OF_DT),dt*self.MAX_CHANGE_OF_DT)
1086              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.n+1,self.tn+dt_new,dt_new))
1087              end_of_step=False              end_of_step=False
1088              while not end_of_step:              while not end_of_step:
1089                 end_of_step=True                 end_of_step=True
1090                 if not dt_new>0:                 if not dt_new>0:
1091                    raise NonPositiveStepSizeError("non-positive step size in step %d",self.n+1)                    raise NonPositiveStepSizeError("non-positive step size in step %d"%(self.n+1))
1092                 try:                 try:
1093                    self.doStepPreprocessing(dt_new)                    self.doStepPreprocessing(dt_new)
1094                    self.doStep(dt_new)                    self.doStep(dt_new)
# Line 869  class Simulation(Model): Line 1098  class Simulation(Model):
1098                    end_of_step=False                    end_of_step=False
1099                    iteration_fail_counter+=1                    iteration_fail_counter+=1
1100                    if iteration_fail_counter>self.FAILED_TIME_STEPS_MAX:                    if iteration_fail_counter>self.FAILED_TIME_STEPS_MAX:
1101                             raise SimulationBreakDownError("reduction of time step to achieve convergence failed.")                             raise SimulationBreakDownError("reduction of time step to achieve convergence failed after %s steps."%self.FAILED_TIME_STEPS_MAX)
1102                    self.trace("iteration fails. time step is repeated with new step size.")                    self.trace("Iteration failed. Time step is repeated with new step size %s."%dt_new)
1103                 except FailedTimeStepError:                 except FailedTimeStepError:
1104                    dt_new=self.getSafeTimeStepSize(dt)                    dt_new=self.getSafeTimeStepSize(dt)
1105                    end_of_step=False                    end_of_step=False
1106                    step_fail_counter+=1                    step_fail_counter+=1
1107                    self.trace("time step is repeated.")                    self.trace("Time step is repeated with new time step size %s."%dt_new)
1108                    if step_fail_counter>self.FAILED_TIME_STEPS_MAX:                    if step_fail_counter>self.FAILED_TIME_STEPS_MAX:
1109                          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)
1110              dt=dt_new              dt=dt_new
1111              if not check_point==None:              if not check_point==None:
1112                  if n%check_point==0:                  if n%check_point==0:
# Line 885  class Simulation(Model): Line 1114  class Simulation(Model):
1114                      self.writeXML()                      self.writeXML()
1115          self.doFinalization()          self.doFinalization()
1116    
     def fromDom(cls, doc):  
         sims = []  
         for node in doc.childNodes:  
             if isinstance(node, minidom.Text):  
                 continue  
1117    
1118              sims.append(getComponent(node))      def toDom(self, esysxml, node):
1119            """
1120        C{toDom} method of Simulation class.
1121        """
1122            simulation = esysxml.createElement('Simulation')
1123            esysxml.registerLinkableObject(self, simulation)
1124            for rank, sim in enumerate(self.iterModels()):
1125                component = esysxml.createElement('Component')
1126                component.setAttribute('rank', str(rank))
1127                sim.toDom(esysxml, component)
1128                simulation.appendChild(component)
1129            node.appendChild(simulation)
1130    
1131          return cls(sims)  
1132        def fromDom(cls, esysxml, node):
1133            sims = []
1134            for n in node.childNodes:
1135                if isinstance(n, minidom.Text):
1136                    continue
1137                sims.append(esysxml.getComponent(n))
1138            sims.sort(cmp=_comp)
1139            sim=cls([s[1] for s in sims], debug=esysxml.debug)
1140            esysxml.registerLinkableObject(sim, node)
1141            return sim
1142    
1143      fromDom = classmethod(fromDom)      fromDom = classmethod(fromDom)
1144    
1145    def _comp(a,b):
1146        if a[0]<a[1]:
1147          return 1
1148        elif a[0]>a[1]:
1149          return -1
1150        else:
1151          return 0
1152    
1153  class IterationDivergenceError(Exception):  class IterationDivergenceError(Exception):
1154      """      """
# Line 927  class NonPositiveStepSizeError(Exception Line 1179  class NonPositiveStepSizeError(Exception
1179      """      """
1180      pass      pass
1181    
1182    class MissingLink(Exception):
1183        """
1184        Exception thrown when a link is missing
1185        """
1186        pass
1187    
1188    class DataSource(object):
1189        """
1190        Class for handling data sources, including local and remote files. This class is under development.
1191        """
1192    
1193        def __init__(self, uri="file.ext", fileformat="unknown"):
1194            self.uri = uri
1195            self.fileformat = fileformat
1196    
1197        def toDom(self, esysxml, node):
1198            """
1199            C{toDom} method of DataSource. Creates a DataSource node and appends it to the
1200        current XML esysxml.
1201            """
1202            ds = esysxml.createElement('DataSource')
1203            ds.appendChild(esysxml.createDataNode('URI', self.uri))
1204            ds.appendChild(esysxml.createDataNode('FileFormat', self.fileformat))
1205            node.appendChild(ds)
1206    
1207        def fromDom(cls, esysxml, node):
1208            uri= str(node.getElementsByTagName("URI")[0].firstChild.nodeValue.strip())
1209            fileformat= str(node.getElementsByTagName("FileFormat")[0].firstChild.nodeValue.strip())
1210            ds = cls(uri, fileformat)
1211            return ds
1212    
1213        def getLocalFileName(self):
1214            return self.uri
1215    
1216        fromDom = classmethod(fromDom)
1217        
1218  # vim: expandtab shiftwidth=4:  # vim: expandtab shiftwidth=4:

Legend:
Removed from v.266  
changed lines
  Added in v.952

  ViewVC Help
Powered by ViewVC 1.1.26