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

Diff of /trunk/esys2/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 122 by jgs, Thu Jun 9 05:38:05 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
   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.    
   
        The parameters of a models are declared at instantion, e.g.  
   
            m=Model({"message" : "none" })  
   
        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:  
   
         class Messenger(Model):  
             def __init__(self):  
                Model.__init__(self,parameters={"message" : "none" })  
   
         m=MyModel()  
   
        There are various ways how model parameters can be changed:  
5    
6         1) use object attributes:  from xml.dom import minidom
7    
8            m.message="Hello World!"  _HEADER_START="<?xml version=\"1.0\"?><ESyS>\n"
9    _HEADER_END="<\ESyS>\n"
10    
11         2) use setParamter method  def dataNode(document, tagName, data):
12                t = document.createTextNode(str(data))
13                  n = document.createElement(tagName)
14            m.setParameters(message="Hello World!")      n.appendChild(t)
15        return n
16    
17    def esysDoc():
18        doc = minidom.Document()
19        esys = doc.createElement('ESys')
20        doc.appendChild(esys)
21        return doc, esys
22    
23         3) or dictonaries  class Link:
24          """
25             d={ message : "Hello World!" }      a Link makes an attribute of an object callable:
26             m.setParameters(**d)            o.object()
27              o.a=8
28              l=Link(o,"a")
29         A model executed buy staring the run method of the model:            assert l()==8
30         """
31            m=Messenger()      
32            m.run()      def __init__(self,target=None,attribute=None):
33            """creates a link to the object target. If attribute is given, the link is
34         The run methods marches through time. It first calls the          establised to this attribute of the target.  Otherwise the attribute is
35         doInitialization() method of the Model to set up the process. In each time step the doStep() method is called          undefined."""
36         to get from the current to the next time step. The step size is defined by calling the getSafeTimeStepSize() method.          self.__target=target
37         The time integration process is terminated when the finalize() methods return true. Final the doFinalization() method          self.setAttributeName(attribute)
38         is called to finalize the process. To implement a particular model a subclass      
39         of the Model class is defined. The subclass overwrites the default methods of Model.      def setAttributeName(self,name):
40            """set a new attribute name to be collected from the target object. The
41         The following class defines a messenger printing in the doStep method what ever the current value of its parameter message is:          target object must have the attribute with name name."""
42            if not name==None:
43         class Messenger(Model):              if not hasattr(self.__target,name):
44              def __init__(self):                  raise AttributeError("%s: target %s has no attribute %s."%(self,self.__target,name))
45                 Model.__init__(self,parameters={"message" : "none" })          self.__attribute=name
46        
47              def doInitialization(self):      def hasDefinedAttributeName(self):
48                 print "I start talking now!"          """returns true if an attribute name is set"""
49            if self.__attribute==None:
50              def doStep(self,t):              return False
51                 print "Message (time %e) : %s "%(t,self.message)          else:
52                return True
53              def doFinalization(self):      
54                 print "I have no more to say!"      def __str__(self):
55                  """returns a string representation of the link"""
56         If a instance of the Messenger class is run, it will print the initialization and finalization message only.          if self.hasDefinedAttributeName():
57         This is because the default method for finalize() does always returns True and therefore the transition is              return "reference to attribute %s of %s"%(self.__attribute,self.__target)
58         terminated startcht away.          else:
59                        return "reference to target %s"%self.__target
60         Following example for solving the ODE using a forward euler scheme:      
61        def __call__(self,name=None):
62                  u(t=0)=u0          """returns the value of the attribute of the target object. If the
63                  u_t=a*u**2       for all 0<t<=ten          atrribute is callable then the return value of the call is returned."""
64            if not name == None:
65        exact solution is given by u(t)=1/(1/u0-a*t)              out=getattr(self.__target, name)
66            else:
67        class  Ode1(Model):              out=getattr(self.__target, self.__attribute)
68           def __init__(self,**args):          if callable(out):
69              Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 1. },name="test",debug=True)              return out()
70            else:
71           def doInitialization(self):              return out
72               self._tn=0  
73        def toDom(self, document, node):
74           def doStep(self,t):          """ toDom method of Link. Creates a Link node and appends it to the current XML
75               self.u=self.u+(t-self._tn)*self.a*self.u**2          document """
76               self._tn=t          link = document.createElement('link')
77            link.appendChild(dataNode(document, 'target', id(self.__target)))
78           def doFinalization(self):          link.appendChild(dataNode(document, 'attribute', self.__attribute))
79               print "all done final error = ",abs(self.u-1./(1./3.-self.a*self._tn))          node.appendChild(link)
80        
81           def getSafeTimeStepSize(self):      def writeXML(self,ostream=stdout):
82               return self.dt          """writes an XML representation of self to the output stream ostream.
83            If ostream is nor present the standart output stream is used.  If
84           def finalize(self):          esysheader==True the esys XML header is written"""
85               return self._tn>=self.tend  
86            document, rootnode = esysDoc()
87         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. `          self.toDom(document, rootnode)
88         In this case the doStep() method is replaced by a sequance of methods which implements this iterative process.  
89         The method then will control the iteration process by initializing the iteration through calling the          ostream.write(document.toprettyxml())
90         doIterationInitialization() method. The iteration is preformed by calling the doIterationStep() method until  
91         the terminate() method returns True. The doIterationFinalization() method is called to end the iteration.  class LinkableObject(object):
92         For a particular model these methods have to overwritten by a suitable subclass without touching the doStep() method.      """an object that allows to link its attributes to attributes of other
93        objects via a Link object. For instance
94         following example is a modification of the example above. Here an implicit euler scheme is used. in each time step the problem            
95                         p=LinkableObject()
96             0= u_{n+1}-u_{n}+a*dt*u_{n+1}**2             p.x=Link(o,"name")
97               print p.x
98         has to be solved for u_{n+1}. The Newton scheme is used to solve this non-linear problem.      
99            links attribute x of p to the attribute name of object o. p.x will print
100            the current value of attribute name of object o.  if the value is
101        class  Ode2(Model):          callable p.x will rturn the return value of the call.
102        """
103        
104        def __init__(self,debug=False):
105            """initiates a model from a list of subsimulations. """
106            self.setDebug(debug)
107            self.__linked_attributes={}
108        #
109        # some basic fuctions:
110        #
111        def debugOn(self):
112            """sets debugging to on"""
113            self.__debug=True
114        def debugOff(self):
115            """sets debugging to off"""
116            self.__debug=False
117        def debug(self):
118            """returns True if debug mode is set to on"""
119            return self.__debug
120        def setDebug(self,flag=False):
121            """sets debugging to flag"""
122            if flag:
123                self.debugOn()
124            else:
125                self.debugOff()
126    
127        def trace(self, msg):
128            if self.__debug:
129                print msg
130        
131        def __getattr__(self,name):
132            """returns the value of attribute name. If the value is a Link object the
133            object is called and the return value is returned."""
134            out=self.getAttributeObject(name)
135            if isinstance(out,Link):
136                return out()
137            else:
138                return out
139        
140        def getAttributeObject(self,name):
141            """return the object stored for attribute name."""
142            if self.__dict__.has_key(name):
143                out=self.__dict__[name]
144            elif self.__linked_attributes.has_key(name):
145                out=self.__linked_attributes[name]
146            else:
147                raise AttributeError,"No attribute %s."%name
148            return out
149        
150        def __setattr__(self,name,value):
151            """sets the value for attribute name. If value is a Link the target
152            attribute is set to name if no attribute has been specified."""
153            if self.__dict__.has_key(name):
154                del self.__dict__[name]
155            if isinstance(value,Link):
156               if not value.hasDefinedAttributeName():
157                   value.setAttributeName(name)
158               self.__linked_attributes[name]=value
159               if self.debug():
160                   print "DEBUG: %s: attribute %s is now linked by %s."%(self,name,value)
161            else:
162               self.__dict__[name]=value
163        
164        def __delattr__(self,name):
165            """removes the attribute name."""
166            if self.__linked_attributes.has_key[name]:
167                del self.__linked_attributes[name]
168            elif self.__dict__.has_key(name):
169                del self.__dict__[name]
170            else:
171                raise AttributeError,"No attribute %s."%name
172    
173    class SimulationFrame(LinkableObject):
174        """A SimulationFrame objects represents a processess marching over time
175        until a finalizing condition is fullfilled.  At each time step an iterative
176        process can be performed and the time step size can be controlled
177        """
178        UNDEF_DT=1.e300
179        MAX_TIME_STEP_REDUCTION=20
180        MAX_ITER_STEPS=50
181        
182        def __init__(self,debug=False):
183            """initiates a simulation"""
184            LinkableObject.__init__(self,debug)
185        
186        def doInitialization(self,t):
187            """initializes the time stepping scheme. This function may be
188            overwritten."""
189            pass
190        
191        def getSafeTimeStepSize(self,dt):
192            """returns a time step size which can savely be used. This function may
193            be overwritten."""
194            return self.UNDEF_DT
195        
196        def finalize(self):
197            """returns True if the time stepping is finalized. This function may be
198            overwritten."""
199            return True
200          
201        def doFinalization(self):
202            """finalizes the time stepping.  This function may be overwritten."""
203            pass
204        
205        def doIterationInitialization(self,dt):
206            """initializes the iteration at time step t. This function may be
207            overwritten. (only called if doStep is not overwritten)"""
208            pass
209        
210        def doIterationStep(self,dt):
211            """executes the iteration step. This function may be overwritten. (only
212            called if doStep is not overwritten)"""
213            pass
214        
215        def terminate(self):
216            """returns True if iteration on a time step is terminated. (only called
217            if doStep is not overwritten)"""
218            return True
219          
220        def doIterationFinalization(self,dt):
221            """finalalizes the iteration process. (only called if doStep is not
222            overwritten)"""
223            pass
224        
225        def run(self,check_point=None):
226            """run the simulation by performing essentially
227        
228                self.doInitialization()
229                while not self.finalize():
230                   dt=self.getSafeTimeStepSize()
231                   self.doStep(dt)
232                   if n%check_point==0: self.writeXML()
233                self.doFinalization()
234        
235            """
236            self.__tn=0.
237            self.__n=0
238            self.__dt=None
239            self.doInitialization(self.__tn)
240            while not self.finalize():
241                self.__n+=1
242                self.__dt=self.getSafeTimeStepSize(self.__dt)
243                if self.__dt==None: self.__dt=self.UNDEF_DT
244                if not self.__dt>0:
245                     raise NonPositiveStepSizeError("non-positive step size in step %d",self.__n)
246                if self.debug(): print "%s: %d. time step %e (step size %e.)"%(self,self.__n,self.__tn+self.__dt,self.__dt)
247                endoftimestep=False
248                failcounter=0
249                while not endoftimestep:
250                    endoftimestep=True
251                    try:
252                        self.doStep(self.__dt)
253                    except FailedTimeStepError:
254                        self.__dt=self.getSafeTimeStepSize(self.__dt)
255                        if self.__dt==None: self.__dt=self.UNDEF_DT
256                        endoftimestep=False
257                        if self.debug(): print "%s: time step is repeated with new step size %e."%(self,self.__dt)
258                    except IterationDivergenceError:
259                        self.__dt*=0.5
260                        endoftimestep=False
261                        failcounter+=1
262                        if failcounter>self.MAX_TIME_STEP_REDUCTION:
263                            raise IterationBreakDownError("reduction of time step to achieve convergence failed.")
264    
265                        self.trace("%s: iteration failes. time step is repeated with new step size %e."
266                            % (self,self.__dt))
267                self.__tn+=self.__dt
268                if not check_point==None:
269                    if self.__n%check_point==0:
270                        self.trace("%s: check point is created."%self)
271                        self.writeXML()
272            self.doFinalization()
273    
274        def writeXML(self):
275            raise RuntimeError, "Not implemented"
276        
277        def doStep(self,dt):
278            """executes a time step by iteration. This function may be overwritten.
279              
280               basicly it performs :
281        
282                self.doIterationInitialization(dt)
283                while not self.terminate(): self.doIterationStep(dt)
284                self.doIterationFinalization(dt)
285        
286            """
287            self.doIterationInitialization(dt)
288            self.__iter=0
289            while not self.terminate():
290                if self.debug(): print "%s: iteration step %d"%(self,self.__iter)
291                self.doIterationStep(dt)
292                self.__iter+=1
293                if self.__iter>self.MAX_ITER_STEPS:
294                    raise IterationDivergenceError("%s: divergence in step %d"%(self,self.__iter))
295            self.doIterationFinalization(dt)
296    
297    class Simulation(SimulationFrame):
298        """A Simulation object is comprised by SimulationFrame(s) called subsimulations."""
299        
300        def __init__(self,subsimulations=[],debug=False):
301            """initiates a simulation from a list of subsimulations. """
302            SimulationFrame.__init__(self,debug)
303            self.__subsimulations=[]
304            for i in range(len(subsimulations)): self[i]=subsimulations[i]
305        
306        def iterSubsimulations(self):
307            """returns an iterator over the subsimulations"""
308            return self.__subsimulations
309        
310        def __getitem__(self,i):
311            """returns the i-th subsimulation"""
312            return self.__subsimulations[i]
313        
314        def __setitem__(self,i,value):
315            """sets the i-th subsimulation"""
316            if not isinstance(value,SimulationFrame):
317                raise ValueError("assigned value is not a Simulation")
318            for j in range(max(i-len(self.__subsimulations)+1,0)): self.__subsimulations.append(None)
319            self.__subsimulations[i]=value
320        
321        def __len__(self):
322            """returns the number of subsimulations"""
323            return len(self.__subsimulations)
324    
325        def toDom(self, document, node):
326            """ toDom method of Simualtion class """
327            simulation = document.createElement('Simulation')
328            simulation.setAttribute('type', self.__class__.__name__)
329    
330            for rank, sim in enumerate(self.iterSubsimulations()):
331                component = document.createElement('Component')
332                component.setAttribute('rank', str(rank))
333    
334                sim.toDom(document, component)
335    
336                simulation.appendChild(component)
337    
338            node.appendChild(simulation)
339    
340        def writeXML(self,ostream=stdout):
341            """writes the object as an XML object into an output stream"""
342            document, rootnode = esysDoc()
343            self.toDom(document, rootnode)
344            ostream.write(document.toprettyxml())
345        
346        def getSafeTimeStepSize(self,dt):
347            """returns a time step size which can savely be used by all subsimulations"""
348            out=self.UNDEF_DT
349            for i in self.iterSubsimulations():
350                dt_new=i.getSafeTimeStepSize(dt)
351                if dt_new!=None: out=min(out,dt_new)
352            return out
353        
354        def doInitialization(self,dt):
355            """initializes all subsimulations """
356            for i in self.iterSubsimulations(): i.doInitialization(dt)
357        
358        def finalize(self):
359            """returns True if all subsimulations are finalized"""
360            out=True
361            for i in self.iterSubsimulations(): out = out and i.finalize()
362            return out
363          
364        def doFinalization(self):
365            """finalalizes the time stepping for all subsimulations."""
366            for i in self.iterSubsimulations(): i.doFinalization()
367        
368        def doIterationInitialization(self,dt):
369            """initializes the iteration at time t for all subsimulations."""
370            self.__iter=0
371            if self.debug(): print "%s: iteration starts"%self
372            for i in self.iterSubsimulations(): i.doIterationInitialization(dt)
373        
374        def terminate(self):
375            """returns True if all iterations for all subsimulations are terminated."""
376            out=True
377            for i in self.iterSubsimulations(): out = out and i.terminate()
378            return out
379          
380        def doIterationFinalization(self,dt):
381            """finalalizes the iteration process for each of the subsimulations."""
382            for i in self.iterSubsimulations(): i.doIterationFinalization(dt)
383            if self.debug(): print "%s: iteration finalized after %s steps"%(self,self.__iter+1)
384        
385        def doIterationStep(self,dt):
386            """executes the iteration step at time step for each subsimulation"""
387            self.__iter+=1
388            if self.debug(): print "%s: iteration step %d"%(self,self.__iter)
389            for i in self.iterSubsimulations(): i.doIterationStep(dt)
390    
391    class ExplicitSimulation(Simulation):
392        """This is a modified form of the Simulation class. In fact it overwrites
393        the doStep method by executing the doStep method of all subsimulations
394        rather then iterating over all subsimulations."""
395    
396        def doStep(self,dt):
397            """executes the time step for all subsimulation"""
398            for i in self.iterSubsimulations(): i.doStep(dt)
399    
400    class _ParameterIterator:
401        def __init__(self,parameterset):
402            self.__set=parameterset
403            self.__iter=iter(parameterset.getParameterList())
404        def next(self):
405            o=self.__iter.next()
406            return (o,self.__set.getAttributeObject(o))
407        def __iter__(self):
408            return self
409    
410    class ParameterSet(LinkableObject):
411        """a class which allows to emphazise attributes to be written and read to XML
412          
413           Leaves of  an ESySParameters objects can be
414        
415                a real number
416                a integer number
417                a string
418                a boolean value
419                a ParameterSet object
420                a Simulation object
421                a Model object
422                any other object (not considered by writeESySXML and writeXML)
423        
424               Example how to create an ESySParameters object:
425        
426                     p11=ParameterSet(gamma1=1.,gamma2=2.,gamma3=3.)
427                     p1=ParameterSet(dim=2,tol_v=0.001,output_file="/tmp/u.%3.3d.dx",runFlag=True,parm11=p11)
428                     parm=ParameterSet(parm1=p1,parm2=ParameterSet(alpha=Link(p11,"gamma1")))
429        
430               This can be accessed as
431        
432                     parm.parm1.gamma=0.
433                     parm.parm1.dim=2
434                     parm.parm1.tol_v=0.001
435                     parm.parm1.output_file="/tmp/u.%3.3d.dx"
436                     parm.parm1.runFlag=True
437                     parm.parm1.parm11.gamma1=1.
438                     parm.parm1.parm11.gamma2=2.
439                     parm.parm1.parm11.gamma3=3.
440                     parm.parm2.alpha=1. (value of parm.parm1.parm11.gamma1)
441                
442        """
443        def __init__(self,parameters=[]):
444            """creates a ParameterSet with parameters parameters"""
445            LinkableObject.__init__(self,debug=False)
446            self.__parameters=[]
447            self.declareParameters(parameters)
448        
449        def getParameterList(self):
450            """returns the list of parameters"""
451            return self.__parameters
452        
453        def isParameter(self,name):
454            """returns true if name is a parameter"""
455            return name in self.getParameterList()
456        
457        def declareParameter(self,**parameters):
458            """declares a new parameter(s) and its (their) inital value."""
459            self.declareParameters(parameters)
460        
461        def declareParameters(self,parameters):
462            """declares a set of parameters. parameters can be a list, a dictonary or a ParameterSet."""
463            if isinstance(parameters,ListType):
464                for prm in parameters:
465                    setattr(self,prm,None)
466                    if not self.isParameter(prm): self.getParameterList().append(prm)
467                    if self.debug(): print "%s: parameter %s has been declared."%(self,prm)
468            elif isinstance(parameters,DictType):
469                for prm,value in parameters.iteritems():
470                    setattr(self,prm,value)
471                    if not self.isParameter(prm): self.getParameterList().append(prm)  
472                    if self.debug(): print "%s: parameter %s has been declared."%(self,prm)
473            else:
474                for prm,value in parameters:
475                    setattr(self,prm,value)
476                    if not self.isParameter(prm): self.getParameterList().append(prm)  
477                    if self.debug(): print "%s: parameter %s has been declared."%(self,prm)
478        
479        def releaseParameters(self,name):
480            """removes parameter name from the paramameters"""
481            if self.isParameter(name):
482                self.getParameterList().remove(name)
483                if self.debug(): print "%s: parameter %s has been removed."%(self,prm)
484        
485        def __iter__(self):
486            """creates an iterator over the parameter and their values"""
487            return _ParameterIterator(self)
488        
489        def showParameters(self):
490            """returns a descrition of the parameters"""        
491            out="{"
492            notfirst=False
493            for i,v in self:
494                if notfirst: out=out+","
495                notfirst=True
496                if isinstance(v,ParameterSet):
497                    out="%s\"%s\" : %s"%(out,i,v.showParameters())
498                else:
499                    out="%s\"%s\" : %s"%(out,i,v)
500            return out+"}"
501        
502        def __delattr__(self,name):
503            """removes the attribute name."""
504            LinkableObject.__delattr__(self,name)
505            try:
506                self.releaseParameter(name)
507            except:
508                pass
509    
510        def toDom(self, document, node):
511            """ toDom method of ParameterSet class """
512            pset = document.createElement('ParameterSet')
513            node.appendChild(pset)
514            self._parametersToDom(document, pset)
515    
516        def _parametersToDom(self, document, node):
517            for name,value in self:
518                param = document.createElement('Parameter')
519                param.setAttribute('type', value.__class__.__name__)
520    
521                param.appendChild(dataNode(document, 'Name', name))
522    
523                val = document.createElement('Value')
524    
525                if isinstance(value,ParameterSet):
526                    value.toDom(document, val)
527                elif isinstance(value, Link):
528                    value.toDom(document, val)
529                    param.appendChild(val)
530                elif isinstance(value,StringType):
531                    param.appendChild(dataNode(document, 'Value', value))
532                else:
533                    param.appendChild(dataNode(document, 'Value', str(value)))
534    
535                node.appendChild(param)
536        
537        def writeXML(self,ostream=stdout):
538            """writes the object as an XML object into an output stream"""
539            # ParameterSet(d) with d[Name]=Value
540            document, node = esysDoc()
541            self.toDom(document, node)
542            ostream.write(document.toprettyxml())
543    
544    class Model(ParameterSet,SimulationFrame):
545        """a Model is a SimulationFrame which is also a ParameterSet."""
546    
547        def __init__(self,debug=False):
548            """creates a model"""
549            ParameterSet.__init__(self)
550            SimulationFrame.__init__(self,debug=debug)
551    
552        def writeXML(self,ostream=stdout,esysheader=True,modelheader=True):
553            """writes the object as an XML object into an output stream"""
554            # x=type() with x.Name=Value where type is a Model from the model library.
555            if esysheader: ostream.write(_HEADER_START)    
556            ostream.write("<Model type=\"%s\" module=\"%s\">\n"%(self.__class__.__name__,self.__class__.__module__))
557            self. writeParameterXML(ostream)      
558            ostream.write("</Model>\n")
559            if esysheader: ostream.write(_HEADER_END)
560    
561         def __init__(self,**args):  class IterationDivergenceError(Exception):
562             Model.__init__(self,{"tend" : 1., "dt" : 0.1 ,"a" : 10. ,"u" : 1. , "tol " : 1.e-8},"test","bla",None,True)      """excpetion which should be thrown if there is no convergence of the iteration process at a time step but there is a chance taht a smaller step could help
563           to reach convergence."""
564        pass
565    
566    class IterationBreakDownError(Exception):
567        """excpetion which should be thrown if there is no conevregence and there is no chance that a time step reduction would help"""
568        pass
569    
570         def doInitialization(self):  class FailedTimeStepError(Exception):
571             self.__tn=0      """excpetion which should be thrown if the time step fails because of a step size that have been choosen to be to large"""
572        pass
573    
574         def doIterationInitialization(self,t):  class NonPositiveStepSizeError(Exception):
575              self.__iter=0      """excpetion which is thrown if the step size is not positive"""
576              self.u_last=self.u                  pass
             self.current_dt=t-self.tn  
             self.__tn=t  
577    
578         def doIterationStep(self):  #
579            self.__iter+=1  #   ignore this text:
580            self.u_old=self.u  #
581            self.u=(self.current_dt*self.a*self.u**2-self.u_last)/(2*self.current_dt*self.a*self.u-1.)  """ the Model class provides a framework to run a time-dependent simulation. A
582    Model has a set of parameter which may be fixed or altered by the Model itself
583    or other Models over time.  
584    
585         def terminate(self):         The parameters of a models are declared at instantion, e.g.
            return abs(self.u_old-self.u)<self.tol*abs(self.u)  
586    
587         def doIterationFinalization(self)             m=Model({"message" : "none" })
            print "all done"  
588    
589         def getSafeTimeStepSize(self):         creates a Model with parameters p1 and p2 with inital values 1 and 2.
590             return self.dt         Typically a particular model is defined as a subclass of Model:
591    
592         def finalize(self):          class Messenger(Model):
593              return self.__tn>self.tend              def __init__(self):
594                   Model.__init__(self,parameters={"message" : "none" })
595    
596         A model can be composed from submodels. Submodels are treated as model parameters. If a model parameter is set or a value of          m=MyModel()
        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.  
597    
598         Here we are creating a model which groups ab instantiation of the Ode2 and the Messenger Model         There are various ways how model parameters can be changed:
599    
600         o=Ode2()         1) use object attributes:
        m=Messenger()  
        om=Model(submodels=[o,m],debug=True)  
        om.dt=0.01  
        om.u=1.  
        m.message="it's me!"  
        om.run()  
601    
602         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            m.message="Hello World!"
        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.  
603    
604         A parameter of a Model can be linked to an attribute of onother object, typically an parameter of another Model object.             2) use setParamter method
605                  
606                    
607         which is comprised by a set of submodels.            m.setParameters(message="Hello World!")
        The simulation is run through its run method which in the simplest case has the form:  
608    
609            s=Model()         3) or dictonaries
610            s.run()    
611               d={ message : "Hello World!" }
612               m.setParameters(**d)
613    
        The run has an initializion and finalization phase. The latter is called if all submodels are to be finalized. The  
        simulation is processing in time through calling the stepForward methods which updates the observables of each submodel.  
        A time steps size which is save for all submodel is choosen.  
614    
615         At given time step an iterative process may be performed to make sure that all observables are consistent across all submodels.         A model executed buy staring the run method of the model:
616         In this case, similar the time dependence, an initialization and finalization of the iteration is performed.  
617              m=Messenger()
618              m.run()
619    
620         A Model has input and output parameters where each input parameter can be constant, time dependent or may depend on an         The run methods marches through time. It first calls the
621         output parameter of another model or the model itself. To create a parameter name of a model and to         doInitialization() method of the Model to set up the process. In each
622         assign a value to it one can use the statement         time step the doStep() method is called to get from the current to the
623           next time step. The step size is defined by calling the
624           getSafeTimeStepSize() method.  the time integration process is
625           terminated when the finalize() methods return true. Final the
626           doFinalization() method is called to finalize the process. To implement
627           a particular model a subclass of the Model class is defined. The
628           subclass overwrites the default methods of Model.
629    
630           The following class defines a messenger printing in the doStep method
631           what ever the current value of its parameter message is:
632    
633           class Messenger(Model):
634                def __init__(self):
635                   Model.__init__(self,parameters={"message" : "none" })
636    
637                def doInitialization(self):
638                   print "I start talking now!"
639    
640                def doStep(self,t):
641                   print "Message (time %e) : %s "%(t,self.message)
642    
643                def doFinalization(self):
644                   print "I have no more to say!"
645          
646           If a instance of the Messenger class is run, it will print the
647           initialization and finalization message only.  This is because the
648           default method for finalize() does always returns True and therefore the
649           transition is terminated startcht away.
650            
651           Following example for solving the ODE using a forward euler scheme:
652    
653                    u(t=0)=u0
654                    u_t=a*u**2       for all 0<t<=ten
655    
656          exact solution is given by u(t)=1/(1/u0-a*t)
657    
658          class  Ode1(Model):
659             def __init__(self,**args):
660                Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 1. },name="test",debug=True)
661    
662             def doInitialization(self):
663                 self._tn=0
664    
665             def doStep(self,t):
666                 self.u=self.u+(t-self._tn)*self.a*self.u**2
667                 self._tn=t
668    
669             def doFinalization(self):
670                 print "all done final error = ",abs(self.u-1./(1./3.-self.a*self._tn))
671    
672             def getSafeTimeStepSize(self):
673                 return self.dt
674    
675             def finalize(self):
676                 return self._tn>=self.tend
677    
678           In some cases at a given time step an iteration process has to be
679           performed to get the state of the Model for the next time step. ` In
680           this case the doStep() method is replaced by a sequance of methods which
681           implements this iterative process.  The method then will control the
682           iteration process by initializing the iteration through calling the
683           doIterationInitialization() method. The iteration is preformed by
684           calling the doIterationStep() method until the terminate() method
685           returns True. The doIterationFinalization() method is called to end the
686           iteration.
687           For a particular model these methods have to overwritten by a suitable
688           subclass without touching the doStep() method.
689    
690           following example is a modification of the example above. Here an
691           implicit euler scheme is used. in each time step the problem
692              
693               0= u_{n+1}-u_{n}+a*dt*u_{n+1}**2
694    
695             model.name=object         has to be solved for u_{n+1}. The Newton scheme is used to solve this non-linear problem.
696    
697    
698          class  Ode2(Model):
699    
700         At any time the current value of the parameter name can be obtained by         def __init__(self,**args):
701               Model.__init__(self,{"tend" : 1., "dt" : 0.1 ,"a" : 10. ,"u" : 1. , "tol " : 1.e-8},"test","bla",None,True)
702    
703                 value=model.name         def doInitialization(self):
704               self.__tn=0
705    
706         If the object that has been assigned to the paramter/attribute name has the attribute/parameter name isself the current value of this         def doIterationInitialization(self,t):
707         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              self.__iter=0
708         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              self.u_last=self.u            
709                self.current_dt=t-self.tn
710                self.__tn=t
711    
712           def doIterationStep(self):
713              self.__iter+=1
714              self.u_old=self.u
715              self.u=(self.current_dt*self.a*self.u**2-self.u_last)/(2*self.current_dt*self.a*self.u-1.)
716    
717           def terminate(self):
718               return abs(self.u_old-self.u)<self.tol*abs(self.u)
719    
720           def doIterationFinalization(self)
721               print "all done"
722    
723           def getSafeTimeStepSize(self):
724               return self.dt
725    
726           def finalize(self):
727                return self.__tn>self.tend
728    
729           A model can be composed from subsimulations. Subsimulations are treated
730           as model parameters. If a model parameter is set or a value of a model
731           parameter is requested, the model will search for this parameter its
732           subsimulations in the case the model does not have this parameter
733           itself. The order in which the subsimulations are searched is critical.
734           By default a Model initializes all its subsimulations, is finalized when
735           all its subsimulations are finalized and finalizes all its
736           subsimulations. In the case an iterative process is applied on a
737           particular time step the iteration is initialized for all
738           subsimulations, then the iteration step is performed for each
739           subsimulation until all subsimulations indicate termination. Then the
740           iteration is finalized for all subsimulations. Finally teh doStop()
741           method for all submethods is called.
742    
743           Here we are creating a model which groups ab instantiation of the Ode2 and the Messenger Model
744    
745           o=Ode2()
746           m=Messenger()
747           om=Model(subsimulations=[o,m],debug=True)
748           om.dt=0.01
749           om.u=1.
750           m.message="it's me!"
751           om.run()
752    
753           Notice that dt and u are parameters of class Ode2 and message is a
754           parameter of the Messenger class. The Model formed from these models
755           automatically hand the assignment of new values down to the
756           subsimulation. om.run() starts this combined model where now the
757           soStep() method of the Messenger object printing the value of its
758           parameter message together with a time stamp is executed in each time
759           step introduced by the Ode2 model.
760    
761           A parameter of a Model can be linked to an attribute of onother object,
762           typically an parameter of another Model object.    
763          
764          
765           which is comprised by a set of subsimulations.
766           The simulation is run through its run method which in the simplest case has the form:
767    
768              s=Model()
769              s.run()
770    
771           The run has an initializion and finalization phase. The latter is called
772           if all subsimulations are to be finalized. The simulation is processing
773           in time through calling the stepForward methods which updates the
774           observables of each subsimulation.  A time steps size which is save for
775           all subsimulation is choosen.
776    
777           At given time step an iterative process may be performed to make sure
778           that all observables are consistent across all subsimulations.  In this
779           case, similar the time dependence, an initialization and finalization of
780           the iteration is performed.
781    
782           A Model has input and output parameters where each input parameter can
783           be constant, time dependent or may depend on an output parameter of
784           another model or the model itself. To create a parameter name of a model
785           and to assign a value to it one can use the statement
786    
787               model.name=object
788    
789    
790           At any time the current value of the parameter name can be obtained by
791    
792                   value=model.name
793    
794           If the object that has been assigned to the paramter/attribute name has
795           the attribute/parameter name isself the current value of this attribute
796           of the object is returned (e.g. for model.name=object where object has
797           an attribute name, the statement value=model.name whould assign the
798           value object.name to value.). If the name of the parameters of a model
799           and an object don't match the setParameter method of model can be used.
800           So
801    
802             model.setParameter(name,object,name_for_object)             model.setParameter(name,object,name_for_object)
803    
804         links the parameter name of model with the parameter name_for_object of object.         links the parameter name of model with the parameter name_for_object of
805           object.
806    
807         The run method initiates checkpointing (it is not clear how to do this yet)         The run method initiates checkpointing (it is not clear how to do this
808           yet)
809     =====     =====
810                            
811     """     """
    # step size used in case of an undefined value for the step size  
    UNDEF_DT=1.e300  
812    
    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+")"  
   
    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()  
813    
 class IterationDivergenceError(Exception):  
     """excpetion which should be thrown if an iteration at a time step fails"""  
     pass  
814    
815  class FailedTimeStepError(Exception):  if __name__=="__main__":
816      """excpetion which should be thrown if the time step fails because of a step size that have been choosen to be to large"""      import math
817      pass      #
818        # test for parameter set
819        #
820        p11=ParameterSet()
821        p11.declareParameter(gamma1=1.,gamma2=2.,gamma3=3.)
822        p1=ParameterSet()
823        p1.declareParameter(dim=2,tol_v=0.001,output_file="/tmp/u.%3.3d.dx",runFlag=True,parm11=p11)
824        parm=ParameterSet({ "parm1" : p1 , "parm2" : ParameterSet(["alpha"])})
825        parm.parm2.alpha=Link(p11,"gamma1")
826        parm.x="that should not be here!"
827        print parm.showParameters()
828        # should be something like: {"parm2" : {"alpha" : reference to attribute
829        # gamma1 of <__main__.ParameterSet instance at 0xf6db51cc>},"parm1" : {"dim"
830        # : 2,"runFlag" : True,"tol_v": 0.001,"parm11" : {"gamma3" : 3.0,"gamma2" :
831        # 2.0,"gamma1" : 1.0},"output_file" : /tmp/u.%3.3d.dx}}
832        assert parm.parm2.alpha==1.
833        parm.writeXML()
834        
835        #=======================
836        class Messenger(Model):
837            def __init__(self):
838                Model.__init__(self)
839                self.declareParameter(message="none")
840    
841            def doInitialization(self,t):
842                self.__t=t
843                print "I start talking now!"
844    
845            def doStep(self,dt):
846                self.__t+=dt
847                print "Message (time %e) : %s "%(self.__t,self.message)
848    
849  class IllegalParameterError(Exception):          def doFinalization(self):
850      """excpetion which is thrown if model has not the desired parameter"""              print "I have no more to say!"
851      pass    
852        class ODETEST(Model):
853            """ implements a solver for the ODE
854    
855                  du/dt=a*u+f(t)
856    
857  if __name__=="__main__":             we use a implicit euler scheme :
    class Messenger(Model):  
       def __init__(self):  
          Model.__init__(self,parameters={"message" : "none" },name="messenger")  
858    
859        def doInitialization(self):                u_n-u_{n-1}= dt*a u_n + st*f(t_n)
          print "I start talking now!"  
860    
861        def doStep(self,t):             to get u_n we run an iterative process
862           print "Message (time %e) : %s "%(t,self.message)  
863                   u_{n.k}=u_{n-1}+dt*(a u_{n.i-1} + f(t_n))
864    
865        def doFinalization(self):  
866           print "I have no more to say!"             input for this model are step size dt, end time tend and a value for
867                 a, f and initial value for u. we need also a tolerance tol for a
868     # explicit scheme             stopping criterion.
869     class  Ode1(Model):  
870        def __init__(self,**args):          """
871             Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 1. , "message" : "none" },name="Ode1",debug=True)  
872            def __init__(self):
873        def doInitialization(self):              Model.__init__(self,debug=True)
874             self._tn=0              self.declareParameter(tend=1.,dt=0.1,a=0.9,u=10.,f=0.,message="",tol=1.e-8)
875    
876        def doStep(self,t):          def doInitialization(self,t):
877             self.u=self.u+(t-self._tn)*self.a*self.u**2              self.__tn=t
878             self._tn=t              self.__iter=0
879              
880        def doFinalization(self):          def doIterationInitialization(self,dt):
881             self.message="current error = %e"%abs(self.u-1./(1./3.-self.a*self._tn))              self.__iter=0
882             print self.message              self.__u_last=self.u            
883    
884        def getSafeTimeStepSize(self):          def doIterationStep(self,dt):
885             return self.dt              self.__iter+=1
886                self.__u_old=self.u
887        def finalize(self):              self.u=self.__u_last+dt*(self.a*self.__u_old+self.f)
888             return self._tn>=self.tend          
889     # explicit scheme          def terminate(self):
890     class  Ode2(Model):              if self.__iter<1:
891                    return False
892         def __init__(self,**args):              else:
893             Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 10000. },name="Ode2",debug=True)                  return abs(self.__u_old-self.u)<self.tol*abs(self.u)
894             self.declareParameter(tol=1.e-8,message="none")  
895                      def doIterationFinalization(self,dt):
896                self.__tn+=dt
897         def doInitialization(self):              self.message="current error = %e"%abs(self.u-10.*math.exp((self.a-1.)*self.__tn))
898             self._tn=0  
899             self._iter=0          def getSafeTimeStepSize(self,dt):
900                return min(self.dt,1./(abs(self.a)+1.))
901         def doIterationInitialization(self,t):  
902              self._iter=0          def finalize(self):
903              self._u_last=self.u                          return self.__tn>=self.tend
904              self._dt=t-self._tn  
905              self._tn=t      #
906        #   s solves the coupled ODE:
907         def doIterationStep(self):      #
908            self._iter+=1      #     du/dt=a*u+  v
909            self._u_old=self.u      #     dv/dt=  u+a*v
910            self.u=(self._dt*self.a*self.u**2-self._u_last)/(2*self._dt*self.a*self.u-1.)      #  
911        #   each equation is treated through the ODETEST class. The equations are
912         def terminate(self):      #   linked and iteration over each time step is performed.  the current
913            if self._iter<1:      #   error of v is reported by the Messenger class.
914                return False      #
915            else:      o1=ODETEST()
916               return abs(self._u_old-self.u)<self.tol*abs(self.u)      o1.u=10
917        o2=ODETEST()
918         def doIterationFinalization(self):      o2.u=-10.
919             self.message="current error = %e"%abs(self.u-1./(1-self.a*self._tn))      o1.f=Link(o2,"u")
920             print self.message      o2.f=Link(o1,"u")
921        m=Messenger()
922         def getSafeTimeStepSize(self):      o1.dt=0.01
923             return self.dt      m.message=Link(o1)
924        s=ExplicitSimulation([Simulation([o1,o2],debug=True),m],debug=True)
925         def finalize(self):      s.run()
926              return self._tn>=self.tend      s.writeXML()
   
    # 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.122

  ViewVC Help
Powered by ViewVC 1.1.26