/[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

trunk/esys2/escript/py_src/modelframe.py revision 121 by jgs, Fri May 6 04:26:16 2005 UTC trunk/escript/py_src/modelframe.py revision 885 by gross, Wed Nov 1 09:05:51 2006 UTC
# Line 1  Line 1 
1  # $Id$  # $Id$
 from types import StringType  
2    
3  class Link:  """
4    """ """  Environment for implementing models in escript
   def __init__(self,object,attribute=None):  
      self.__object=object  
      self.setAttributeName(attribute)  
   
   def setAttributeName(self,name):  
      if not name==None:  
         if not hasattr(self.__object,name):  
            raise AttributeError("Link: object %s has no attribute %s."%(self.__object,name))  
      self.__attribute=name  
   
   def hasAttributeName(self):  
       if self.__attribute==None:  
          return False  
       else:  
          return True  
   
   def __str__(self):  
       if self.hasAttributeName():  
           return "reference to %s of %s"%(self.__attribute,self.__object)  
       else:  
           return "reference to object %s"%self.__object  
   
   def getValue(self,name=None):  
       if not self.hasAttributeName():  
          out=getattr(self.__object,name)  
       else:  
          out=getattr(self.__object,self.__attribute)  
       if callable(out):  
           return out()  
       else:  
           return out  
     
 class Model:  
    """ the Model class provides a framework to run a time-dependent simulation. A Model has a set of parameter which  
        may be fixed or altered by the Model itself or other Models over time.    
5    
6         The parameters of a models are declared at instantion, e.g.  @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
26    from sys import stdout
27    import numarray
28    import operator
29    import itertools
30    # import modellib  temporarily removed!!!
31    
32    # import the 'set' module if it's not defined (python2.3/2.4 difference)
33    try:
34        set
35    except NameError:
36        from sets import Set as set
37    
38    from xml.dom import minidom
39    
40    def dataNode(document, tagName, data):
41        """
42        C{dataNode}s are the building blocks of the xml documents constructed in
43        this module.  
44        
45        @param document: the current xml document
46        @param tagName: the associated xml tag
47        @param data: the values in the tag
48        """
49        t = document.createTextNode(str(data))
50        n = document.createElement(tagName)
51        n.appendChild(t)
52        return n
53    
54    def esysDoc():
55        """
56        Global method for creating an instance of an EsysXML document.
57        """
58        doc = minidom.Document()
59        esys = doc.createElement('ESys')
60        doc.appendChild(esys)
61        return doc, esys
62    
63    def all(seq):
64        for x in seq:
65            if not x:
66                return False
67        return True
68    
69    def any(seq):
70        for x in seq:
71            if x:
72                return True
73        return False
74    
75             m=Model({"message" : "none" })  LinkableObjectRegistry = {}
76    
77         creates a Model with parameters p1 and p2 with inital values 1 and 2. Typically a particular model is defined as a subclass of Model:  def registerLinkableObject(obj_id, o):
78        LinkableObjectRegistry[obj_id] = o
79    
80          class Messenger(Model):  LinkRegistry = []
             def __init__(self):  
                Model.__init__(self,parameters={"message" : "none" })  
81    
82          m=MyModel()  def registerLink(obj_id, l):
83        LinkRegistry.append((obj_id,l))
84    
85         There are various ways how model parameters can be changed:  def parse(xml):
86        """
87        Generic parse method for EsysXML.  Without this, Links don't work.
88        """
89        global LinkRegistry, LinkableObjectRegistry
90        LinkRegistry = []
91        LinkableObjectRegistry = {}
92    
93         1) use object attributes:      doc = minidom.parseString(xml)
94        sim = getComponent(doc.firstChild)
95        for obj_id, link in LinkRegistry:
96            link.target = LinkableObjectRegistry[obj_id]
97    
98            m.message="Hello World!"      return sim
99    
100         2) use setParamter method  def importName(modulename, name):
101        """ Import a named object from a module in the context of this function,
102            which means you should use fully qualified module paths.
103                    
104                      Return None on failure.
           m.setParameters(message="Hello World!")  
105    
106         3) or dictonaries          This function from: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52241
107          """
108             d={ message : "Hello World!" }      module = __import__(modulename, globals(), locals(), [name])
109             m.setParameters(**d)          
110        try:
111            return vars(module)[name]
112         A model executed buy staring the run method of the model:      except KeyError:
113            raise ImportError("Could not import %s from %s" % (name, modulename))
114            m=Messenger()  
115            m.run()  def getComponent(doc):
116        """
117         The run methods marches through time. It first calls the      Used to get components of Simualtions, Models.
118         doInitialization() method of the Model to set up the process. In each time step the doStep() method is called      """
119         to get from the current to the next time step. The step size is defined by calling the getSafeTimeStepSize() method.      for node in doc.childNodes:
120         The time integration process is terminated when the finalize() methods return true. Final the doFinalization() method          
121         is called to finalize the process. To implement a particular model a subclass          if isinstance(node, minidom.Element):
122         of the Model class is defined. The subclass overwrites the default methods of Model.              if node.tagName == 'Simulation':
123                    if node.getAttribute("type") == 'Simulation':
124         The following class defines a messenger printing in the doStep method what ever the current value of its parameter message is:                      return Simulation.fromDom(node)
125                if node.tagName == 'Model':
126         class Messenger(Model):                  if (node.getAttribute("module")):
127              def __init__(self):                      model_module = node.getAttribute("module")
128                 Model.__init__(self,parameters={"message" : "none" })                      model_type = node.getAttribute("type")
129                        return importName(model_module, model_type).fromDom(node)
130              def doInitialization(self):                  else:
131                 print "I start talking now!"                      model_type = node.getAttribute("type")
132                        model_subclasses = Model.__subclasses__()
133              def doStep(self,t):                      for model in model_subclasses:
134                 print "Message (time %e) : %s "%(t,self.message)                          if model_type == model.__name__:
135                                return Model.fromDom(node)
136              def doFinalization(self):              if node.tagName == 'ParameterSet':
137                 print "I have no more to say!"                  parameter_type = node.getAttribute("type")
138                          return ParameterSet.fromDom(node)
139         If a instance of the Messenger class is run, it will print the initialization and finalization message only.              raise "Invalid simulation type, %r" % node.getAttribute("type")
        This is because the default method for finalize() does always returns True and therefore the transition is  
        terminated startcht away.  
140                    
        Following example for solving the ODE using a forward euler scheme:  
   
                 u(t=0)=u0  
                 u_t=a*u**2       for all 0<t<=ten  
   
       exact solution is given by u(t)=1/(1/u0-a*t)  
   
       class  Ode1(Model):  
          def __init__(self,**args):  
             Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 1. },name="test",debug=True)  
   
          def doInitialization(self):  
              self._tn=0  
   
          def doStep(self,t):  
              self.u=self.u+(t-self._tn)*self.a*self.u**2  
              self._tn=t  
   
          def doFinalization(self):  
              print "all done final error = ",abs(self.u-1./(1./3.-self.a*self._tn))  
   
          def getSafeTimeStepSize(self):  
              return self.dt  
141    
142           def finalize(self):      raise ValueError("No Simulation Found")
143               return self._tn>=self.tend              
144    
145         In some cases at a given time step an iteration process has to be performed to get the state of the Model for the next time step. `  class Link:
146         In this case the doStep() method is replaced by a sequance of methods which implements this iterative process.      """
147         The method then will control the iteration process by initializing the iteration through calling the      A Link makes an attribute of an object callable::
        doIterationInitialization() method. The iteration is preformed by calling the doIterationStep() method until  
        the terminate() method returns True. The doIterationFinalization() method is called to end the iteration.  
        For a particular model these methods have to overwritten by a suitable subclass without touching the doStep() method.  
148    
149         following example is a modification of the example above. Here an implicit euler scheme is used. in each time step the problem            o.object()
150              o.a=8
151              l=Link(o,"a")
152              assert l()==8
153         """
154        
155        def __init__(self,target,attribute=None):
156            """
157            Creates a link to the object target. If attribute is given, the link is
158            establised to this attribute of the target.  Otherwise the attribute is
159            undefined.
160            """
161            self.target = target
162            self.attribute = None
163            self.setAttributeName(attribute)
164        
165        def setAttributeName(self,attribute):
166            """
167            Set a new attribute name to be collected from the target object. The
168            target object must have the attribute with name attribute.
169            """
170            if attribute and self.target:
171                if isinstance(self.target,LinkableObject):
172                   if not self.target.hasAttribute(attribute):
173                      raise AttributeError("%s: target %s has no attribute %s."%(self, self.target, attribute))
174                else:
175                   if not hasattr(self.target,attribute):
176                      raise AttributeError("%s: target %s has no attribute %s."%(self, self.target, attribute))
177            self.attribute = attribute
178        
179        def hasDefinedAttributeName(self):
180            """
181            Returns true if an attribute name is set.
182            """
183            return self.attribute != None
184        
185        def __repr__(self):
186            """
187            Returns a string representation of the link.
188            """
189            if self.hasDefinedAttributeName():
190                return "<Link to attribute %s of %s>" % (self.attribute, self.target)
191            else:
192                return "<Link to target %s>" % self.target
193        
194        def __call__(self,name=None):
195            """
196            Returns the value of the attribute of the target object. If the
197            atrribute is callable then the return value of the call is returned.
198            """
199            if name:
200                out=getattr(self.target, name)
201            else:
202                out=getattr(self.target, self.attribute)
203    
204            if callable(out):
205                return out()
206            else:
207                return out
208    
209        def toDom(self, document, node):
210            """
211            C{toDom} method of Link. Creates a Link node and appends it to the
212        current XML document.
213            """
214            link = document.createElement('Link')
215            assert (self.target != None), ("Target was none, name was %r" % self.attribute)
216            link.appendChild(dataNode(document, 'Target', self.target.id))
217            # this use of id will not work for purposes of being able to retrieve the intended
218            # target from the xml later. I need a better unique identifier.
219            assert self.attribute, "You can't xmlify a Link without a target attribute"
220            link.appendChild(dataNode(document, 'Attribute', self.attribute))
221            node.appendChild(link)
222    
223        def fromDom(cls, doc):
224            targetid = doc.getElementsByTagName("Target")[0].firstChild.nodeValue.strip()
225            attribute = doc.getElementsByTagName("Attribute")[0].firstChild.nodeValue.strip()
226            l = cls(None, attribute)
227            registerLink(targetid, l)
228            return l
229    
230        fromDom = classmethod(fromDom)
231        
232        def writeXML(self,ostream=stdout):
233            """
234            Writes an XML representation of self to the output stream ostream.
235            If ostream is nor present the standart output stream is used.  If
236            esysheader==True the esys XML header is written
237            """
238            print 'I got to the Link writeXML method'
239            document, rootnode = esysDoc()
240            self.toDom(document, rootnode)
241    
242            ostream.write(document.toprettyxml())
243    
244    class LinkableObject(object):
245        """
246        An object that allows to link its attributes to attributes of other objects
247        via a Link object. For instance::
248                        
249             0= u_{n+1}-u_{n}+a*dt*u_{n+1}**2             p = LinkableObject()
250               p.x = Link(o,"name")
251         has to be solved for u_{n+1}. The Newton scheme is used to solve this non-linear problem.             print p.x
252        
253        links attribute C{x} of C{p} to the attribute name of object C{o}.
254    
255        C{p.x} will contain the current value of attribute C{name} of object
256        C{o}.  
257    
258        If the value of C{getattr(o, "name")} is callable, C{p.x} will return
259        the return value of the call.
260        """
261      
262        number_sequence = itertools.count(100)
263        
264        def __init__(self, debug=False):
265            """
266        Initializes LinkableObject so that we can operate on Links
267        """
268            self.debug = debug
269            self.__linked_attributes={}
270            self.id = self.number_sequence.next()
271            registerLinkableObject(self.id, self)
272    
273        def trace(self, msg):
274            """
275        If debugging is on, print the message, otherwise do nothing
276            """
277            if self.debug:
278                print "%s: %s"%(str(self),msg)
279        
280        def __getattr__(self,name):
281            """
282        Returns the value of attribute name. If the value is a Link object the
283            object is called and the return value is returned.
284        """
285            out = self.getAttributeObject(name)
286            if isinstance(out,Link):
287                return out()
288            else:
289                return out
290        
291        def getAttributeObject(self,name):
292            """
293        Return the object stored for attribute name.
294        """
295    
296            if self.__dict__.has_key(name):
297                return self.__dict__[name]
298    
299            if self.__linked_attributes.has_key(name):
300                return self.__linked_attributes[name]
301    
302            if self.__class__.__dict__.has_key(name):
303                return self.__class.__dict__[name]
304    
305            raise AttributeError,"No attribute %s."%name
306        
307        def hasAttribute(self,name):
308            """
309        Returns True if self as attribute name.
310        """
311            return self.__dict__.has_key(name) or self.__linked_attributes.has_key(name) or  self.__class__.__dict__.has_key(name)
312    
313        def __setattr__(self,name,value):
314            """
315        Sets the value for attribute name. If value is a Link the target
316            attribute is set to name if no attribute has been specified.
317        """
318    
319            if self.__dict__.has_key(name):
320                del self.__dict__[name]
321    
322            if isinstance(value,Link):
323                if not value.hasDefinedAttributeName():
324                    value.setAttributeName(name)
325                self.__linked_attributes[name] = value
326    
327                self.trace("attribute %s is now linked by %s."%(name,value))
328            else:
329                self.__dict__[name] = value
330        
331        def __delattr__(self,name):
332            """
333        Removes the attribute name.
334        """
335    
336            if self.__linked_attributes.has_key[name]:
337                del self.__linked_attributes[name]
338            elif self.__dict__.has_key(name):
339                del self.__dict__[name]
340            else:
341                raise AttributeError,"No attribute %s."%name
342    
343    class _ParameterIterator:
344        def __init__(self,parameterset):
345    
346            self.__set=parameterset
347            self.__iter=iter(parameterset.parameters)
348    
349        def next(self):
350            o=self.__iter.next()
351            return (o,self.__set.getAttributeObject(o))
352    
353        def __iter__(self):
354            return self
355    
356    class ParameterSet(LinkableObject):
357        """
358        A class which allows to emphazise attributes to be written and read to XML
359          
360        Leaves of an ESySParameters object can be:
361        
362         - a real number
363         - a integer number
364         - a string
365         - a boolean value
366         - a ParameterSet object
367         - a Simulation object
368         - a Model object
369         - a numarray object
370             - a list of booleans
371            - any other object (not considered by writeESySXML and writeXML)
372        
373        Example how to create an ESySParameters object::
374        
375            p11=ParameterSet(gamma1=1.,gamma2=2.,gamma3=3.)
376            p1=ParameterSet(dim=2,tol_v=0.001,output_file="/tmp/u.%3.3d.dx",runFlag=True,parm11=p11)
377            parm=ParameterSet(parm1=p1,parm2=ParameterSet(alpha=Link(p11,"gamma1")))
378        
379        This can be accessed as::
380        
381        parm.parm1.gamma=0.
382            parm.parm1.dim=2
383            parm.parm1.tol_v=0.001
384            parm.parm1.output_file="/tmp/u.%3.3d.dx"
385            parm.parm1.runFlag=True
386            parm.parm1.parm11.gamma1=1.
387            parm.parm1.parm11.gamma2=2.
388            parm.parm1.parm11.gamma3=3.
389            parm.parm2.alpha=1. (value of parm.parm1.parm11.gamma1)
390        """
391        def __init__(self, parameters=[], **kwargs):
392            """
393        Creates a ParameterSet with parameters parameters.
394        """
395            LinkableObject.__init__(self, **kwargs)
396            self.parameters = set()
397            self.declareParameters(parameters)
398    
399        def __repr__(self):
400            return "<%s %r>" % (self.__class__.__name__,
401                                [(p, getattr(self, p, None)) for p in self.parameters])
402        
403        def declareParameter(self,**parameters):
404            """
405        Declares a new parameter(s) and its (their) initial value.
406        """
407            self.declareParameters(parameters)
408        
409        def declareParameters(self,parameters):
410            """
411        Declares a set of parameters. parameters can be a list, a dictionary
412        or a ParameterSet.
413        """
414            if isinstance(parameters,ListType):
415                parameters = zip(parameters, itertools.repeat(None))
416            if isinstance(parameters,DictType):
417                parameters = parameters.iteritems()
418    
419            for prm, value in parameters:
420                setattr(self,prm,value)
421                self.parameters.add(prm)
422    
423                self.trace("parameter %s has been declared."%prm)
424    
425        def releaseParameters(self,name):
426            """
427        Removes parameter name from the paramameters.
428        """
429            if self.isParameter(name):
430                self.parameters.remove(name)
431                self.trace("parameter %s has been removed."%name)
432        
433        def __iter__(self):
434            """
435        Creates an iterator over the parameter and their values.
436        """
437            return _ParameterIterator(self)
438        
439        def showParameters(self):
440            """
441        Returns a descrition of the parameters.
442        """        
443            out="{"
444            notfirst=False
445            for i,v in self:
446                if notfirst: out=out+","
447                notfirst=True
448                if isinstance(v,ParameterSet):
449                    out="%s\"%s\" : %s"%(out,i,v.showParameters())
450                else:
451                    out="%s\"%s\" : %s"%(out,i,v)
452            return out+"}"
453        
454        def __delattr__(self,name):
455            """
456        Removes the attribute name.
457        """
458            LinkableObject.__delattr__(self,name)
459            try:
460                self.releaseParameter(name)
461            except:
462                pass
463    
464        def toDom(self, document, node):
465            """
466        C{toDom} method of ParameterSet class.
467        """
468            pset = document.createElement('ParameterSet')
469            node.appendChild(pset)
470            self._parametersToDom(document, pset)
471    
472        def _parametersToDom(self, document, node):
473            node.setAttribute('id', str(self.id))
474            node.setIdAttribute("id")
475            for name,value in self:
476                param = document.createElement('Parameter')
477                param.setAttribute('type', value.__class__.__name__)
478    
479                param.appendChild(dataNode(document, 'Name', name))
480    
481                val = document.createElement('Value')
482    
483                if isinstance(value,(ParameterSet,Link,DataSource)):
484                    value.toDom(document, val)
485                    param.appendChild(val)
486                elif isinstance(value, numarray.NumArray):
487                    shape = value.getshape()
488                    if isinstance(shape, tuple):
489                        size = reduce(operator.mul, shape)
490                        shape = ' '.join(map(str, shape))
491                    else:
492                        size = shape
493                        shape = str(shape)
494    
495                    arraytype = value.type()
496                    numarrayElement = document.createElement('NumArray')
497                    numarrayElement.appendChild(dataNode(document, 'ArrayType', str(arraytype)))
498                    numarrayElement.appendChild(dataNode(document, 'Shape', shape))
499                    numarrayElement.appendChild(dataNode(document, 'Data', ' '.join(
500                        [str(x) for x in numarray.reshape(value, size)])))
501                    val.appendChild(numarrayElement)
502                    param.appendChild(val)
503                elif isinstance (value, list):
504                    param.appendChild(dataNode(document, 'Value', ' '.join(
505                        [str(x) for x in value])
506                    ))
507                else:
508                    param.appendChild(dataNode(document, 'Value', str(value)))
509    
510                node.appendChild(param)
       class  Ode2(Model):  
511    
512         def __init__(self,**args):      def fromDom(cls, doc):
            Model.__init__(self,{"tend" : 1., "dt" : 0.1 ,"a" : 10. ,"u" : 1. , "tol " : 1.e-8},"test","bla",None,True)  
513    
514         def doInitialization(self):          # Define a host of helper functions to assist us.
515             self.__tn=0          def _children(node):
516                """
517                Remove the empty nodes from the children of this node.
518                """
519                ret = []
520                for x in node.childNodes:
521                    if isinstance(x, minidom.Text):
522                        if x.nodeValue.strip():
523                            ret.append(x)
524                    else:
525                        ret.append(x)
526                return ret
527    
528         def doIterationInitialization(self,t):          def _floatfromValue(doc):
529              self.__iter=0              return float(doc.nodeValue.strip())
             self.u_last=self.u              
             self.current_dt=t-self.tn  
             self.__tn=t  
   
        def doIterationStep(self):  
           self.__iter+=1  
           self.u_old=self.u  
           self.u=(self.current_dt*self.a*self.u**2-self.u_last)/(2*self.current_dt*self.a*self.u-1.)  
   
        def terminate(self):  
            return abs(self.u_old-self.u)<self.tol*abs(self.u)  
   
        def doIterationFinalization(self)  
            print "all done"  
   
        def getSafeTimeStepSize(self):  
            return self.dt  
   
        def finalize(self):  
             return self.__tn>self.tend  
   
        A model can be composed from submodels. Submodels are treated as model parameters. If a model parameter is set or a value of  
        a model parameter is requested, the model will search for this parameter its submodels in the case the model does not have this  
        parameter itself. The order in which the submodels are searched is critical. By default a Model initializes all its submodels,  
        is finalized when all its submodels are finalized and finalizes all its submodels. In the case an iterative process is applied  
        on a particular time step the iteration is initialized for all submodels, then the iteration step is performed for each submodel  
        until all submodels indicate termination. Then the iteration is finalized for all submodels. Finally teh doStop() method for all  
        submethods is called.  
   
        Here we are creating a model which groups ab instantiation of the Ode2 and the Messenger Model  
   
        o=Ode2()  
        m=Messenger()  
        om=Model(submodels=[o,m],debug=True)  
        om.dt=0.01  
        om.u=1.  
        m.message="it's me!"  
        om.run()  
   
        Notice that dt and u are parameters of class Ode2 and message is a parameter of the Messenger class. The Model formed from these models  
        automatically hand the assignment of new values down to the submodel. om.run() starts this combined model where now the soStep() method  
        of the Messenger object printing the value of its parameter message together with a time stamp is executed in each time step introduced  
        by the Ode2 model.  
530    
531         A parameter of a Model can be linked to an attribute of onother object, typically an parameter of another Model object.              def _stringfromValue(doc):
532                return str(doc.nodeValue.strip())
533                
534                  def _intfromValue(doc):
535         which is comprised by a set of submodels.              return int(doc.nodeValue.strip())
        The simulation is run through its run method which in the simplest case has the form:  
   
           s=Model()  
           s.run()  
536    
537         The run has an initializion and finalization phase. The latter is called if all submodels are to be finalized. The          def _boolfromValue(doc):
538         simulation is processing in time through calling the stepForward methods which updates the observables of each submodel.              return _boolfromstring(doc.nodeValue.strip())
        A time steps size which is save for all submodel is choosen.  
539    
540         At given time step an iterative process may be performed to make sure that all observables are consistent across all submodels.          def _nonefromValue(doc):
541         In this case, similar the time dependence, an initialization and finalization of the iteration is performed.              return None
542    
543         A Model has input and output parameters where each input parameter can be constant, time dependent or may depend on an          def _numarrayfromValue(doc):
544         output parameter of another model or the model itself. To create a parameter name of a model and to              for node in _children(doc):
545         assign a value to it one can use the statement                  if node.tagName == 'ArrayType':
546                        arraytype = node.firstChild.nodeValue.strip()
547             model.name=object                  if node.tagName == 'Shape':
548                        shape = node.firstChild.nodeValue.strip()
549                        shape = [int(x) for x in shape.split()]
550                    if node.tagName == 'Data':
551                        data = node.firstChild.nodeValue.strip()
552                        data = [float(x) for x in data.split()]
553                return numarray.reshape(numarray.array(data, type=getattr(numarray, arraytype)),
554                                        shape)
555          
556            def _listfromValue(doc):
557                return [_boolfromstring(x) for x in doc.nodeValue.split()]
558    
559    
560         At any time the current value of the parameter name can be obtained by          def _boolfromstring(s):
561                if s == 'True':
562                    return True
563                else:
564                    return False
565            # Mapping from text types in the xml to methods used to process trees of that type
566            ptypemap = {"Simulation": Simulation.fromDom,
567                        "Model":Model.fromDom,
568                        "ParameterSet":ParameterSet.fromDom,
569                        "Link":Link.fromDom,
570                        "DataSource":DataSource.fromDom,
571                        "float":_floatfromValue,
572                        "int":_intfromValue,
573                        "str":_stringfromValue,
574                        "bool":_boolfromValue,
575                        "list":_listfromValue,
576                        "NumArray":_numarrayfromValue,
577                        "NoneType":_nonefromValue,
578                        }
579    
580    #        print doc.toxml()
581    
582            parameters = {}
583            for node in _children(doc):
584                ptype = node.getAttribute("type")
585    
586                pname = pvalue = None
587                for childnode in _children(node):
588    
589                    if childnode.tagName == "Name":
590                        pname = childnode.firstChild.nodeValue.strip()
591    
592                    if childnode.tagName == "Value":
593                        nodes = _children(childnode)
594                    #    if ptype == 'NumArray':
595                     #       pvalue = _numarrayfromValue(nodes)
596                     #   else:
597                        pvalue = ptypemap[ptype](nodes[0])
598    
599                parameters[pname] = pvalue
600    
601            # Create the instance of ParameterSet
602            o = cls()
603            o.declareParameters(parameters)
604            registerLinkableObject(doc.getAttribute("id"), o)
605            return o
606        
607        fromDom = classmethod(fromDom)
608        
609        def writeXML(self,ostream=stdout):
610            """
611        Writes the object as an XML object into an output stream.
612        """
613            # ParameterSet(d) with d[Name]=Value
614            document, node = esysDoc()
615            self.toDom(document, node)
616            ostream.write(document.toprettyxml())
617    
618    class Model(ParameterSet):
619        """
620        A Model object represents a processess marching over time until a
621        finalizing condition is fullfilled. At each time step an iterative
622        process can be performed and the time step size can be controlled. A
623        Model has the following work flow::
624    
625              doInitialization()
626              while not finalize():
627                   dt=getSafeTimeStepSize(dt)
628                   doStepPreprocessing(dt)
629                   while not terminateIteration(): doStep(dt)
630                   doStepPostprocessing(dt)
631              doFinalization()
632    
633        where C{doInitialization}, C{finalize}, C{getSafeTimeStepSize},
634        C{doStepPreprocessing}, C{terminateIteration}, C{doStepPostprocessing},
635        C{doFinalization} are methods of the particular instance of a Model. The
636        default implementations of these methods have to be overwritten by the
637        subclass implementing a Model.
638        """
639    
640        UNDEF_DT=1.e300
641    
642        def __init__(self,parameters=[],**kwarg):
643            """
644        Creates a model.
645    
646            Just calls the parent constructor.
647            """
648            ParameterSet.__init__(self, parameters=parameters,**kwarg)
649    
650        def __str__(self):
651           return "<%s %d>"%(self.__class__,id(self))
652    
653        def toDom(self, document, node):
654            """
655        C{toDom} method of Model class
656        """
657            pset = document.createElement('Model')
658            pset.setAttribute('type', self.__class__.__name__)
659            if not self.__class__.__module__.startswith('esys.escript'):
660                pset.setAttribute('module', self.__class__.__module__)
661            node.appendChild(pset)
662            self._parametersToDom(document, pset)
663    
664        def doInitialization(self):
665            """
666        Initializes the time stepping scheme.  
667        
668        This function may be overwritten.
669        """
670            pass
671        
672        def getSafeTimeStepSize(self,dt):
673            """
674        Returns a time step size which can safely be used.
675    
676            C{dt} gives the previously used step size.
677    
678            This function may be overwritten.
679        """
680            return self.UNDEF_DT
681        
682        def finalize(self):
683            """
684        Returns False if the time stepping is finalized.
685        
686        This function may be overwritten.
687        """
688            return False
689          
690        def doFinalization(self):
691            """
692        Finalizes the time stepping.
693        
694        This function may be overwritten.
695        """
696            pass
697        
698        def doStepPreprocessing(self,dt):
699            """
700        Sets up a time step of step size dt.
701        
702        This function may be overwritten.
703        """
704            pass
705        
706        def doStep(self,dt):
707            """
708        Executes an iteration step at a time step.
709    
710            C{dt} is the currently used time step size.
711    
712            This function may be overwritten.
713        """
714            pass
715        
716        def terminateIteration(self):
717            """
718        Returns True if iteration on a time step is terminated.
719        """
720            return True
721          
722        def doStepPostprocessing(self,dt):
723            """
724        Finalalizes the time step.
725    
726            dt is the currently used time step size.
727    
728            This function may be overwritten.
729        """
730            pass
731        
732        def writeXML(self, ostream=stdout):
733            document, node = esysDoc()
734            self.toDom(document, node)
735            ostream.write(document.toprettyxml())
736        
737    
738    class Simulation(Model):
739        """
740        A Simulation object is special Model which runs a sequence of Models.
741    
742        The methods C{doInitialization}, C{finalize}, C{getSafeTimeStepSize},
743        C{doStepPreprocessing}, C{terminateIteration}, C{doStepPostprocessing},
744        C{doFinalization} are executing the corresponding methods of the models in
745        the simulation.
746        """
747        
748        FAILED_TIME_STEPS_MAX=20
749        MAX_ITER_STEPS=50
750        MAX_CHANGE_OF_DT=2.
751        
752        def __init__(self, models=[], **kwargs):
753            """
754        Initiates a simulation from a list of models.
755        """
756            Model.__init__(self, **kwargs)
757            self.__models=[]
758            
759            for i in range(len(models)):
760                self[i] = models[i]
761                
762    
763                 value=model.name      def __repr__(self):
764            """
765            Returns a string representation of the Simulation.
766            """
767            return "<Simulation %r>" % self.__models
768    
769        def __str__(self):
770            """
771            Returning Simulation as a string.
772            """
773            return "<Simulation %d>"%id(self)
774        
775        def iterModels(self):
776            """
777        Returns an iterator over the models.
778        """
779            return self.__models
780        
781        def __getitem__(self,i):
782            """
783        Returns the i-th model.
784        """
785            return self.__models[i]
786        
787        def __setitem__(self,i,value):
788            """
789        Sets the i-th model.
790        """
791            if not isinstance(value,Model):
792                raise ValueError,"assigned value is not a Model but instance of %s"%(value.__class__.__name__,)
793            for j in range(max(i-len(self.__models)+1,0)):
794                self.__models.append(None)
795            self.__models[i]=value
796        
797        def __len__(self):
798            """
799        Returns the number of models.
800        """
801            return len(self.__models)
802    
803        def toDom(self, document, node):
804            """
805        C{toDom} method of Simulation class.
806        """
807            simulation = document.createElement('Simulation')
808            simulation.setAttribute('type', self.__class__.__name__)
809    
810            for rank, sim in enumerate(self.iterModels()):
811                component = document.createElement('Component')
812                component.setAttribute('rank', str(rank))
813    
814                sim.toDom(document, component)
815    
816                simulation.appendChild(component)
817    
818            node.appendChild(simulation)
819    
820        def writeXML(self,ostream=stdout):
821            """
822        Writes the object as an XML object into an output stream.
823        """
824            document, rootnode = esysDoc()
825            self.toDom(document, rootnode)
826            targetsList = document.getElementsByTagName('Target')
827            
828            for element in targetsList:
829                targetId = int(element.firstChild.nodeValue.strip())
830                if document.getElementById(str(targetId)):
831                    continue
832                targetObj = LinkableObjectRegistry[targetId]
833                targetObj.toDom(document, rootnode)
834            ostream.write(document.toprettyxml())
835        
836        def getSafeTimeStepSize(self,dt):
837            """
838        Returns a time step size which can safely be used by all models.
839    
840            This is the minimum over the time step sizes of all models.
841        """
842            out=min([o.getSafeTimeStepSize(dt) for o in self.iterModels()])
843            #print "%s: safe step size is %e."%(str(self),out)
844            return out
845        
846        def doInitialization(self):
847            """
848        Initializes all models.
849        """
850            self.n=0
851            self.tn=0.
852            for o in self.iterModels():
853                o.doInitialization()
854        
855        def finalize(self):
856            """
857        Returns True if any of the models is to be finalized.
858        """
859            return any([o.finalize() for o in self.iterModels()])
860          
861        def doFinalization(self):
862            """
863        Finalalizes the time stepping for all models.
864        """
865            for i in self.iterModels(): i.doFinalization()
866            self.trace("end of time integation.")
867        
868        def doStepPreprocessing(self,dt):
869            """
870        Initializes the time step for all models.
871        """
872            for o in self.iterModels():
873                o.doStepPreprocessing(dt)
874        
875        def terminateIteration(self):
876            """
877        Returns True if all iterations for all models are terminated.
878        """
879            out=all([o.terminateIteration() for o in self.iterModels()])
880            return out
881          
882        def doStepPostprocessing(self,dt):
883            """
884        Finalalizes the iteration process for all models.
885        """
886            for o in self.iterModels():
887                o.doStepPostprocessing(dt)
888            self.n+=1
889            self.tn+=dt
890        
891        def doStep(self,dt):
892            """
893        Executes the iteration step at a time step for all model::
894    
895                self.doStepPreprocessing(dt)
896                while not self.terminateIteration():
897                for all models:
898                self.doStep(dt)
899                    self.doStepPostprocessing(dt)
900            """
901            self.iter=0
902            while not self.terminateIteration():
903                if self.iter==0: self.trace("iteration at %d-th time step %e starts"%(self.n+1,self.tn+dt))
904                self.iter+=1
905                self.trace("iteration step %d"%(self.iter))
906                for o in self.iterModels():
907                      o.doStep(dt)
908            if self.iter>0: self.trace("iteration at %d-th time step %e finalized."%(self.n+1,self.tn+dt))
909    
910        def run(self,check_point=None):
911            """
912        Run the simulation by performing essentially::
913        
914            self.doInitialization()
915            while not self.finalize():
916                dt=self.getSafeTimeStepSize()
917                self.doStep(dt)
918                if n%check_point==0:
919                self.writeXML()
920            self.doFinalization()
921    
922            If one of the models in throws a C{FailedTimeStepError} exception a
923        new time step size is computed through getSafeTimeStepSize() and the
924        time step is repeated.
925      
926            If one of the models in throws a C{IterationDivergenceError}
927        exception the time step size is halved and the time step is repeated.
928    
929         If the object that has been assigned to the paramter/attribute name has the attribute/parameter name isself the current value of this          In both cases the time integration is given up after
930         attribute of the object is returned (e.g. for model.name=object where object has an attribute name, the statement value=model.name whould assign      C{Simulation.FAILED_TIME_STEPS_MAX} attempts.
931         the value object.name to value.). If the name of the parameters of a model and an object don't match the setParameter method of model can be used. So          """
932            dt=self.UNDEF_DT
933            self.doInitialization()
934            while not self.finalize():
935                step_fail_counter=0
936                iteration_fail_counter=0
937                if self.n==0:
938                    dt_new=self.getSafeTimeStepSize(dt)
939                else:
940                    dt_new=min(max(self.getSafeTimeStepSize(dt),dt/self.MAX_CHANGE_OF_DT),dt*self.MAX_CHANGE_OF_DT)
941                self.trace("%d. time step %e (step size %e.)" % (self.n+1,self.tn+dt_new,dt_new))
942                end_of_step=False
943                while not end_of_step:
944                   end_of_step=True
945                   if not dt_new>0:
946                      raise NonPositiveStepSizeError("non-positive step size in step %d"%(self.n+1))
947                   try:
948                      self.doStepPreprocessing(dt_new)
949                      self.doStep(dt_new)
950                      self.doStepPostprocessing(dt_new)
951                   except IterationDivergenceError:
952                      dt_new*=0.5
953                      end_of_step=False
954                      iteration_fail_counter+=1
955                      if iteration_fail_counter>self.FAILED_TIME_STEPS_MAX:
956                               raise SimulationBreakDownError("reduction of time step to achieve convergence failed after %s steps."%self.FAILED_TIME_STEPS_MAX)
957                      self.trace("Iteration failed. Time step is repeated with new step size %s."%dt_new)
958                   except FailedTimeStepError:
959                      dt_new=self.getSafeTimeStepSize(dt)
960                      end_of_step=False
961                      step_fail_counter+=1
962                      self.trace("Time step is repeated with new time step size %s."%dt_new)
963                      if step_fail_counter>self.FAILED_TIME_STEPS_MAX:
964                            raise SimulationBreakDownError("Time integration is given up after %d attempts."%step_fail_counter)
965                dt=dt_new
966                if not check_point==None:
967                    if n%check_point==0:
968                        self.trace("check point is created.")
969                        self.writeXML()
970            self.doFinalization()
971    
972        def fromDom(cls, doc):
973            sims = []
974            for node in doc.childNodes:
975                if isinstance(node, minidom.Text):
976                    continue
977    
978             model.setParameter(name,object,name_for_object)              sims.append(getComponent(node))
979    
980         links the parameter name of model with the parameter name_for_object of object.          return cls(sims)
981    
982         The run method initiates checkpointing (it is not clear how to do this yet)      fromDom = classmethod(fromDom)
    =====  
               
    """  
    # step size used in case of an undefined value for the step size  
    UNDEF_DT=1.e300  
   
    def __init__(self,submodels=[],parameters={},name="model",description="none",check_pointing=None,debug=False):  
       """initiates a model from a list of submodels. """  
       self.setDebug(debug)  
       self.__check_pointing=check_pointing  
       self.__parameters={}  
       self.setName(name)  
       self.setDescription(description)  
       self.declareParameter(**parameters)  
       # get the models defined in parameters:  
       self.__submodels=[]  
       # submodels==None means no submodels used:  
       if submodels==None:  
          pass  
       # no submodel list given means all submodels are used as defined by the parameters dictionary:  
       elif len(submodels)==0:  
             for i in parameters.keys():  
                 if isinstance(parameters[i],Model): self.__submodels.append(i)  
       # submodel list of strings and Models is given, submodels defines the order in which the  
       # submodels are processed. if new models are found in the list they are added to the parameter dictionary.  
       else:  
          c=0  
          for i in submodels:  
             if isinstance(i,StringType):  
               m=self.getParameter(i)  
               if not isinstance(m,Model):  
                  raise ValueError,"submodel %s is not a model."%i  
             else:  
                if not isinstance(i,Model):  
                  raise ValueError,"submodel list does contain item which is not a Model class object."  
                m=i  
                i="__submodel%d__"%c  
                self.declareParameter(**{i : m})  
                c+=1  
             self.__submodels.append(i)  
             if self.debug(): print "%s: model %s is added as parameter %s."%(self,m,i)  
       if len(self.__submodels)>0 and self.debug(): print "%s: model ordering is %s"%(self,self.__submodels)  
    def setSubmodelOrder(submodels=[]):  
       """sets a new ordering for submodels"""  
         
       
    #  
    # some basic fuctions:  
    #  
    def debugOn(self):  
       """sets debugging to on"""  
       self.__debug=True  
    def debugOff(self):  
       """sets debugging to off"""  
       self.__debug=False  
    def debug(self):  
       """returns True if debug mode is set to on"""  
       return self.__debug  
    def setDebug(self,flag=False):  
       """sets debugging to flag"""  
       if flag:  
          self.debugOn()  
       else:  
          self.debugOff()  
    def setDebug(self,flag=False):  
       """sets debugging to flag"""  
       if flag:  
          self.debugOn()  
       else:  
          self.debugOff()  
    # name and description handling  
    def __str__(self):  
        """returns the name of the model"""  
        return self.getName()  
   
    def getName(self):  
        """returns the name of the model"""  
        return self.__name  
   
    def getFullName(self):  
        """returns the full name of the model including all the names of the submodels"""  
        out=str(self)+"("  
        notfirst=False  
        for i in self.__submodels:  
             if notfirst: out=out+","  
             out=out+i.getFullName()  
             notfirst=True  
        return out+")"  
983    
    def setName(self,name):  
        """sets the name of the model"""  
        self.__name=name  
   
    def setDescription(self,description="none"):  
        """sets new description"""  
        self.__description=description  
        if self.debug(): print "%s: description is set to %s."%(self,description)  
    def getDescription(self):  
        """returns the description of the model"""  
        return self.__description  
    #  
    #    parameter/attribute handling:  
    #  
    def declareParameter(self,**parameters):  
       """declares a new parameter and its inital value."""  
       for prm in parameters.keys():  
          if prm in self.__dict__.keys():  
              raise ValueError,"object attribute %s of %s cannot be used as a model parameter."%(prm,self)  
          self.__parameters[prm]=parameters[prm]  
          if self.debug(): print "%s: parameter %s has been declared."%(self,prm)  
   
   
   
    def showParameters(self):  
       """returns a descrition of the parameters"""  
       out=""  
       notfirst=False  
       for i in self.__parameters:  
           if notfirst: out=out+","  
           notfirst=True  
           out="%s%s=%s"%(out,i,self.__parameters[i])  
       return out  
   
   
    def deleteParameter(self,name):  
       """removes parameter name from the model"""  
       raise IllegalParameterError("Cannot delete parameter %s."%name)  
   
    def getParameter(self,name):  
       """returns the value of parameter name. If the parameter is not declared in self, the submodels are searched.  
          if the parameter is a Link, the current value of the obejective is returned."""  
       if self.__parameters.has_key(name):  
           if isinstance(self.__parameters[name],Link):  
              out=self.__parameters[name].getValue(name)  
           else:  
              out=self.__parameters[name]  
       else:  
           out=None  
           for i in self.__submodels:  
              try:  
                 out=self.__parameters[i].getParameter(name)  
              except IllegalParameterError:  
                 pass  
           if out==None: raise IllegalParameterError("Cannot find parameter %s."%name)  
       return out  
   
    def setParameter(self,**parameters):  
       """sets parameter name to value. If the initial value for the parameter is a Model, the new value has to be a Model."""  
       for name in parameters.keys():  
          if self.__parameters.has_key(name):  
             if not isinstance(parameters[name],Model) and isinstance(self.__parameters[name],Model):  
                 raise ValueError,"%s: parameter %s can assigned to a Model object only."%(self,name)  
             if isinstance(parameters[name],Model) and not isinstance(self.__parameters[name],Model):  
                 raise ValueError,"%s: parameter %s is not declared as a Model."%(self,name)  
             self.__parameters[name]=parameters[name]  
             if isinstance(self.__parameters[name],Link):  
                  if not self.__parameters[name].hasAttributeName(): self.__parameters[name].setAttributeName(name)  
             if self.debug(): print "%s: parameter %s has now value %s"%(self,name,self.__parameters[name])  
          else:  
             set=False  
             for i in self.__submodels:  
                 try:  
                    self.__parameters[i].setParameter(**{name : parameters[name]})  
                    set=True  
                 except IllegalParameterError:  
                     pass  
             if not set: raise IllegalParameterError("%s: Attempt to set undeclared parameter %s."%(self,name))  
   
    def hasParameter(self,name):  
       """returns True if self or one of the submodels has parameter name"""  
       if self.__parameters.has_key(name):  
          out=True  
       else:  
          out=False  
          for i in self.__submodels: out= out or self.__parameters[i].hasParameter(name)  
       return out  
   
    def checkParameter(self,name):  
       """checks if self has the parameter name. Otherewise ParameterError is thrown."""  
       if not self.hasParameter(name):  
            raise ParameterError("%s has no parameter %s."%(str(self),name))  
     
    def __getattr__(self,name):  
       """returns the value for attribute name. If name is in the Link list, the corresponding attribute is returned."""  
       if self.__dict__.has_key(name):  
          return self.__dict__[name]  
       elif self.__dict__.has_key("_Model__parameters") and self.__dict__.has_key("_Model__submodels"):  
          return self.getParameter(name)  
       else:  
          raise AttributeError,"No attribute %s."%name  
   
    def __setattr__(self,name,value):  
       """returns the value for attribute name."""  
       if self.__dict__.has_key("_Model__parameters") and self.__dict__.has_key("_Model__submodels"):  
          if self.hasParameter(name):  
             self.setParameter(**{ name : value })  
          else:  
             self.__dict__[name]=value  
       else:  
          self.__dict__[name]=value  
   
    def __delattr__(self,name):  
       """removes the attribute name."""  
       if self.__dict__.has_key(name):  
          del self.__dict__[name]  
       elif self.__dict__.has_key("_Model__parameters"):  
          self.deleteParameter(name)  
       else:  
          raise AttributeError,"No attribute %s."%name  
   
    #  
    #    submodel handeling:  
    #  
    def doInitializationOfSubmodels(self):  
       """initializes the time stepping for all submodels."""  
       for i in self.__submodels: self.getParameter(i).doInitialization()  
   
    def getSafeTimeStepSizeFromSubmodels(self):  
       """returns a time step size which can savely be used by all submodels. To avoid a big increase in the step size,  
          the new step size is restricted to the double of the precious step size."""  
       out=None  
       for i in self.__submodels:  
           dt=self.getParameter(i).getSafeTimeStepSize()  
           if not dt==None:  
               if out==None:  
                  out=dt  
               else:  
                  out=min(out,dt)  
       return out  
   
    def doStepOfSubmodels(self,t):  
       """executes the time step for each submodel"""  
       for i in self.__submodels: self.getParameter(i).doStep(t)  
   
    def finalizeAllSubmodels(self):  
       """returns True if all submodels can be finalized"""  
       out=True  
       for i in self.__submodels: out = out and self.getParameter(i).finalize()  
       return out  
         
    def doFinalizationOfSubmodels(self):  
       """finalalizes the time stepping for each of the submodels."""  
       for i in self.__submodels: self.getParameter(i).doFinalization()  
   
    def doIterationInitializationOfSubmodels(self,t):  
       """initializes the iteration for each of the submodels."""  
       for i in self.__submodels: self.getParameter(i).doIterationInitialization(t)  
   
    def doIterationStepOfSubmodels(self):  
       """executes the iteration step at time step for each submodel"""  
       for i in self.__submodels: self.getParameter(i).doIterationStep()  
   
    def terminateAllSubmodels(self):  
       """returns True if all iterations for all submodels are terminated."""  
       out=True  
       for i in self.__submodels: out = out and self.getParameter(i).terminate()  
       return out  
         
    def doIterationFinalizationOfSubmodels(self):  
       """finalalizes the iteration process for each of the submodels."""  
       for i in self.__submodels: self.getParameter(i).doIterationFinalization()  
   
    def checkPointSubmodels(self):  
       """performs check pointing for each submodel"""  
       for i in self.__submodels: self.getParameter(i).checkPoint()  
   
    #  
    #   these methods control the time stepping  
    #    
    def doInitialization(self):  
       """initializes the time stepping"""  
       self.doInitializationOfSubmodels()  
   
    def getSafeTimeStepSize(self):  
       """returns a time step size which can savely be used"""  
       return self.getSafeTimeStepSizeFromSubmodels()  
   
    def doStep(self,t):  
       """executes the time step by first iterating over time step t and then step forward"""  
       # run iteration on simulation until terminated:  
       self.doIterationInitialization(t)  
       while not self.terminate(): self.doIterationStep()  
       self.doIterationFinalization()  
       self.doStepOfSubmodels(t)  
   
    def finalize(self):  
       """returns True if all submodels are to be finalized"""  
       return self.finalizeAllSubmodels()  
         
    def doFinalization(self):  
       """finalizes the time stepping."""  
       self.doFinalizationOfSubmodels()  
    #  
    #   methods deal with iterations:  
    #  
    def doIterationInitialization(self,t):  
       """initializes the iteration on a time step"""  
       self.__iter=0  
       if self.debug(): print "%s: iteration starts"%self  
       self.doIterationInitializationOfSubmodels(t)  
   
    def doIterationStep(self):  
       """executes the iteration step"""  
       self.__iter+=1  
       if self.debug(): print "%s: iteration step %d"%(self,self.__iter)  
       try:  
          self.doIterationStepOfSubmodels()  
       except IterationDivergenceError,e:  
          raise IterationDivergenceError("divergence at time step %s in iteration step %s by reason: \n%s."%(self.__n,self.__iter,e.value))  
   
    def terminate(self):  
       """returns True if time steping is terminated"""  
       return self.terminateAllSubmodels()  
         
    def doIterationFinalization(self):  
       """finalalizes the iteration process."""  
       self.doIterationFinalizationOfSubmodels()  
       if self.debug(): print "%s: iteration finalized after %s step"%(self,self.__iter)  
    #  
    #   sum other method:  
    #  
    def checkPoint(self):  
       """performs check pointing for each submodel"""  
       if not self.__check_pointing==None:  
          if self.__n%self.__check_pointing==0: self.checkPointsSubmodels()  
   
    def run(self):  
       """After check_pointing time steps the model will start to create checkpoint files for each of the submodels"""  
       self.__tn=0.  
       self.__n=0  
       self.__dt=None  
       self.doInitialization()  
       while not self.finalize():  
          self.__n+=1  
          self.__dt=self.getSafeTimeStepSize()  
          if self.__dt==None: self.__dt=self.UNDEF_DT  
          if self.debug(): print "%s: %d. time step %e (step size %e.)"%(self,self.__n,self.__tn+self.__dt,self.__dt)  
          endoftimestep=False  
          while not endoftimestep:  
               endoftimestep=True  
               try:  
                  self.doStep(self.__tn+self.__dt)  
               except FailedTimeStepError:  
                  self.__dt=self.getSafeTimeStepSize()  
                  if self.__dt==None: self.__dt=self.UNDEF_DT  
                  endoftimestep=False  
                  if self.debug(): print "%s: time step is repeated with new step size %e."%(self,self.__dt)  
               except IterationDivergenceError:  
                  self.__dt*=0.5  
                  endoftimestep=False  
                  if self.debug(): print "%s: iteration failes. time step is repeated with new step size %e."%(self,self.__dt)  
          self.checkPoint()  
          self.__tn+=self.__dt  
       self.doFinalization()  
984    
985  class IterationDivergenceError(Exception):  class IterationDivergenceError(Exception):
986      """excpetion which should be thrown if an iteration at a time step fails"""      """
987        Exception which is thrown if there is no convergence of the iteration
988        process at a time step.
989    
990        But there is a chance that a smaller step could help to reach convergence.
991        """
992      pass      pass
993    
994  class FailedTimeStepError(Exception):  class FailedTimeStepError(Exception):
995      """excpetion which should be thrown if the time step fails because of a step size that have been choosen to be to large"""      """
996        Exception which is thrown if the time step fails because of a step
997        size that have been choosen to be too large.
998        """
999      pass      pass
1000    
1001  class IllegalParameterError(Exception):  class SimulationBreakDownError(Exception):
1002      """excpetion which is thrown if model has not the desired parameter"""      """
1003        Exception which is thrown if the simulation does not manage to
1004        progress in time.
1005        """
1006      pass      pass
1007    
1008    class NonPositiveStepSizeError(Exception):
1009        """
1010        Exception which is thrown if the step size is not positive.
1011        """
1012        pass
1013    
1014  if __name__=="__main__":  class DataSource(object):
1015     class Messenger(Model):      """
1016        def __init__(self):      Class for handling data sources, including local and remote files. This class is under development.
1017           Model.__init__(self,parameters={"message" : "none" },name="messenger")      """
1018    
1019        def doInitialization(self):      def __init__(self, uri="file.ext", fileformat="unknown"):
1020           print "I start talking now!"          self.uri = uri
1021            self.fileformat = fileformat
1022        def doStep(self,t):  
1023           print "Message (time %e) : %s "%(t,self.message)      def toDom(self, document, node):
1024            """
1025        def doFinalization(self):          C{toDom} method of DataSource. Creates a DataSource node and appends it to the
1026           print "I have no more to say!"      current XML document.
1027              """
1028     # explicit scheme          ds = document.createElement('DataSource')
1029     class  Ode1(Model):          ds.appendChild(dataNode(document, 'URI', self.uri))
1030        def __init__(self,**args):          ds.appendChild(dataNode(document, 'FileFormat', self.fileformat))
1031             Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 1. , "message" : "none" },name="Ode1",debug=True)          node.appendChild(ds)
1032    
1033        def doInitialization(self):      def fromDom(cls, doc):
1034             self._tn=0          uri= doc.getElementsByTagName("URI")[0].firstChild.nodeValue.strip()
1035            fileformat= doc.getElementsByTagName("FileFormat")[0].firstChild.nodeValue.strip()
1036        def doStep(self,t):          ds = cls(uri, fileformat)
1037             self.u=self.u+(t-self._tn)*self.a*self.u**2          return ds
1038             self._tn=t  
1039        def getLocalFileName(self):
1040        def doFinalization(self):          return self.uri
1041             self.message="current error = %e"%abs(self.u-1./(1./3.-self.a*self._tn))  
1042             print self.message      fromDom = classmethod(fromDom)
1043        
1044        def getSafeTimeStepSize(self):  # vim: expandtab shiftwidth=4:
            return self.dt  
   
       def finalize(self):  
            return self._tn>=self.tend  
    # explicit scheme  
    class  Ode2(Model):  
   
        def __init__(self,**args):  
            Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 10000. },name="Ode2",debug=True)  
            self.declareParameter(tol=1.e-8,message="none")  
             
   
        def doInitialization(self):  
            self._tn=0  
            self._iter=0  
   
        def doIterationInitialization(self,t):  
             self._iter=0  
             self._u_last=self.u              
             self._dt=t-self._tn  
             self._tn=t  
   
        def doIterationStep(self):  
           self._iter+=1  
           self._u_old=self.u  
           self.u=(self._dt*self.a*self.u**2-self._u_last)/(2*self._dt*self.a*self.u-1.)  
   
        def terminate(self):  
           if self._iter<1:  
               return False  
           else:  
              return abs(self._u_old-self.u)<self.tol*abs(self.u)  
   
        def doIterationFinalization(self):  
            self.message="current error = %e"%abs(self.u-1./(1-self.a*self._tn))  
            print self.message  
   
        def getSafeTimeStepSize(self):  
            return self.dt  
   
        def finalize(self):  
             return self._tn>=self.tend  
   
    # a simple model with paramemter tend, dt, p1, p2, and p3  
    class Test1(Model):  
   
        def __init__(self,**args):  
            Model.__init__(self,{"tend" : 1., "dt" : 0.1 ,"p1" : 0 ,"p2" : 0 ,"p3" : 0 },"test","bla",None,True)  
            self.setParameters(args)  
   
        def doInitialization(self):  
            self.__tn=0  
            self.__n=0  
   
        def doStep(self,t):  
            self.p3=self.p1+t*self.p2  
            self.__tn=t  
            print "test1 set the value out1 to ",self.p3  
   
        def doFinalization(self):  
            pass  
   
        def getSafeTimeStepSize(self):  
            return self.dt  
   
        def finalize(self):  
             return self._tn>self.tend  
   
   
    class Test2(Model):  
   
        def __init__(self):  
            Model.__init__(self,{"q1": None},"test2","",None,True)  
   
   
        def doInitialization(self):  
            print "the whole thing starts"  
   
        def doStep(self,t):  
            print "test2 things that out1 is now ",self.out1  
   
        def doFinalization(self):  
            print "all done"  
   
        def finalize(self):  
             return True  
   
    class Test12(Model):  
      """model build from two models in a transperent way"""  
      def __init__(self):  
          Model.__init__(self,{"sm1": None, a : 0, "sm2": None},"test2","",None,True)  
          self.setExecutionOrder(["sm2","sm1"])  
   
    # test messenger  
    m=Messenger()  
    m.run()  
    # ode1        
    o=Ode1()  
    o.dt=0.001  
    o.u=3.  
    o.run()  
    # ode1  
    o=Ode2()  
    o.dt=0.01  
    o.a=0.1  
    o.u=1.  
    o.run()  
    # and they are linked together:  
    o=Ode2()  
    m=Messenger()  
    om=Model(submodels=[o,m],debug=True)  
    om.dt=0.01  
    om.u=1.  
    m.message=Link(o)  
    om.run()  
    print om.showParameters()  
    1/0  
   
    t=Test1()  
    t.tend=1.  
    t.dt=0.25  
    t.in1=1.  
    t.in2=3.  
    t.run()  
    # and a coupled problem:  
    t2=Test2()  
    t2.out1=Link(t)  
    Model([t,t2],debug=True).run()  

Legend:
Removed from v.121  
changed lines
  Added in v.885

  ViewVC Help
Powered by ViewVC 1.1.26