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

  ViewVC Help
Powered by ViewVC 1.1.26