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

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

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

trunk/esys2/escript/py_src/modelframe.py revision 142 by jgs, Mon Jul 25 05:28:20 2005 UTC trunk/escript/py_src/modelframe.py revision 155 by jgs, Wed Nov 9 02:02:19 2005 UTC
# Line 15  from xml.dom import minidom Line 15  from xml.dom import minidom
15    
16  def dataNode(document, tagName, data):  def dataNode(document, tagName, data):
17      """      """
18      dataNodes are the building blocks of the xml documents constructed in      C{dataNode}s are the building blocks of the xml documents constructed in
19      this module. document is the current xml document, tagName is the      this module.  
20      associated xml tag, and data is the values in the tag.      
21        @param document: the current xml document
22        @param tagName: the associated xml tag
23        @param data: the values in the tag
24      """      """
25      t = document.createTextNode(str(data))      t = document.createTextNode(str(data))
26      n = document.createElement(tagName)      n = document.createElement(tagName)
# Line 39  def all(seq): Line 42  def all(seq):
42              return False              return False
43      return True      return True
44    
45    def any(seq):
46        for x in seq:
47            if x:
48                return True
49        return False
50    
51  LinkableObjectRegistry = {}  LinkableObjectRegistry = {}
52    
53  def registerLinkableObject(obj_id, o):  def registerLinkableObject(obj_id, o):
# Line 50  def registerLink(obj_id, l): Line 59  def registerLink(obj_id, l):
59      LinkRegistry.append((obj_id,l))      LinkRegistry.append((obj_id,l))
60    
61  def parse(xml):  def parse(xml):
62        """
63        Generic parse method for EsysXML.  Without this, Links don't work.
64        """
65      global LinkRegistry, LinkableObjectRegistry      global LinkRegistry, LinkableObjectRegistry
66      LinkRegistry = []      LinkRegistry = []
67      LinkableObjectRegistry = {}      LinkableObjectRegistry = {}
68    
69      doc = minidom.parseString(xml)      doc = minidom.parseString(xml)
   
70      sim = getComponent(doc.firstChild)      sim = getComponent(doc.firstChild)
71      for obj_id, link in LinkRegistry:      for obj_id, link in LinkRegistry:
72          link.target = LinkableObjectRegistry[obj_id]          link.target = LinkableObjectRegistry[obj_id]
73    
74      return sim      return sim
75    
76    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.
81    
82            This function from: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52241
83        """
84        module = __import__(modulename, globals(), locals(), [name])
85            
86        try:
87            return vars(module)[name]
88        except KeyError:
89            raise ImportError("Could not import %s from %s" % (name, modulename))
90    
91  def getComponent(doc):  def getComponent(doc):
92        """
93        Used to get components of Simualtions, Models.
94        """
95      for node in doc.childNodes:      for node in doc.childNodes:
96            
97          if isinstance(node, minidom.Element):          if isinstance(node, minidom.Element):
98              if node.tagName == 'Simulation':              if node.tagName == 'Simulation':
99                  if node.getAttribute("type") == 'Simulation':                  if node.getAttribute("type") == 'Simulation':
100                      return Simulation.fromDom(node)                      return Simulation.fromDom(node)
                 elif node.getAttribute("type") == 'ExplicitSimulation':  
                     return ExplicitSimulation.fromDom(node)  
101              if node.tagName == 'Model':              if node.tagName == 'Model':
102                  model_type = node.getAttribute("type")                  if (node.getAttribute("module")):
103                  model_subclasses = Model.__subclasses__()                      model_module = node.getAttribute("module")
104                  for model in model_subclasses:                      model_type = node.getAttribute("type")
105                      if model_type == model.__name__:                      return importName(model_module, model_type).fromDom(node)
106                          return model.fromDom(node)                  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")              raise "Invalid simulation type, %r" % node.getAttribute("type")
116            
117    
118      raise ValueError("No Simulation Found")      raise ValueError("No Simulation Found")
119                            
120    
121  class Link:  class Link:
122      """      """
123      a Link makes an attribute of an object callable:      A Link makes an attribute of an object callable::
124    
125            o.object()            o.object()
126            o.a=8            o.a=8
127            l=Link(o,"a")            l=Link(o,"a")
# Line 93  class Link: Line 130  class Link:
130            
131      def __init__(self,target,attribute=None):      def __init__(self,target,attribute=None):
132          """          """
133          creates a link to the object target. If attribute is given, the link is          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          establised to this attribute of the target.  Otherwise the attribute is
135          undefined.          undefined.
136          """          """
# Line 103  class Link: Line 140  class Link:
140            
141      def setAttributeName(self,attribute):      def setAttributeName(self,attribute):
142          """          """
143          set a new attribute name to be collected from the target object. The          Set a new attribute name to be collected from the target object. The
144          target object must have the attribute with name attribute.          target object must have the attribute with name attribute.
145          """          """
146          if attribute and self.target and not hasattr(self.target, attribute):          if attribute and self.target:
147              raise AttributeError("%s: target %s has no attribute %s."%(self, self.target, attribute))              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          self.attribute = attribute
154            
155      def hasDefinedAttributeName(self):      def hasDefinedAttributeName(self):
156          """          """
157          returns true if an attribute name is set          Returns true if an attribute name is set.
158          """          """
159          return self.attribute != None          return self.attribute != None
160            
161      def __repr__(self):      def __repr__(self):
162          """          """
163          returns a string representation of the link          Returns a string representation of the link.
164          """          """
165          if self.hasDefinedAttributeName():          if self.hasDefinedAttributeName():
166              return "<Link to attribute %s of %s>" % (self.attribute, self.target)              return "<Link to attribute %s of %s>" % (self.attribute, self.target)
# Line 127  class Link: Line 169  class Link:
169            
170      def __call__(self,name=None):      def __call__(self,name=None):
171          """          """
172          returns the value of the attribute of the target object. If the          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.          atrribute is callable then the return value of the call is returned.
174          """          """
175          if name:          if name:
# Line 142  class Link: Line 184  class Link:
184    
185      def toDom(self, document, node):      def toDom(self, document, node):
186          """          """
187          toDom method of Link. Creates a Link node and appends it to the current XML          C{toDom} method of Link. Creates a Link node and appends it to the
188          document      current XML document.
189          """          """
190          link = document.createElement('Link')          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))          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          # 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.          # target from the xml later. I need a better unique identifier.
# Line 164  class Link: Line 207  class Link:
207            
208      def writeXML(self,ostream=stdout):      def writeXML(self,ostream=stdout):
209          """          """
210          writes an XML representation of self to the output stream ostream.          Writes an XML representation of self to the output stream ostream.
211          If ostream is nor present the standart output stream is used.  If          If ostream is nor present the standart output stream is used.  If
212          esysheader==True the esys XML header is written          esysheader==True the esys XML header is written
213          """          """
214            print 'I got to the Link writeXML method'
215          document, rootnode = esysDoc()          document, rootnode = esysDoc()
216          self.toDom(document, rootnode)          self.toDom(document, rootnode)
217    
# Line 177  class Link: Line 220  class Link:
220  class LinkableObject(object):  class LinkableObject(object):
221      """      """
222      An object that allows to link its attributes to attributes of other objects      An object that allows to link its attributes to attributes of other objects
223      via a Link object. For instance      via a Link object. For instance::
224                        
225             p = LinkableObject()             p = LinkableObject()
226             p.x = Link(o,"name")             p.x = Link(o,"name")
227             print p.x             print p.x
228            
229      links attribute x of p to the attribute name of object o.      links attribute C{x} of C{p} to the attribute name of object C{o}.
230    
231      p.x will contain the current value of attribute name of object o.        C{p.x} will contain the current value of attribute C{name} of object
232        C{o}.  
233    
234      If the value of getattr(o, "name") is callable, p.x will rturn the return      If the value of C{getattr(o, "name")} is callable, C{p.x} will return
235      value of the call.      the return value of the call.
236      """      """
237        
238      number_sequence = itertools.count(100)      number_sequence = itertools.count(100)
239            
240      def __init__(self, debug=False):      def __init__(self, debug=False):
241          """ initializes LinkableObject so that we can operate on Links """          """
242        Initializes LinkableObject so that we can operate on Links
243        """
244          self.debug = debug          self.debug = debug
245          self.__linked_attributes={}          self.__linked_attributes={}
246          self.id = self.number_sequence.next()          self.id = self.number_sequence.next()
247            registerLinkableObject(self.id, self)
248    
249      def trace(self, msg):      def trace(self, msg):
250          """ If debugging is on, print the message, otherwise do nothing          """
251        If debugging is on, print the message, otherwise do nothing
252          """          """
253          if self.debug:          if self.debug:
254              print msg              print "%s: %s"%(str(self),msg)
255            
256      def __getattr__(self,name):      def __getattr__(self,name):
257          """returns the value of attribute name. If the value is a Link object the          """
258          object is called and the return value is returned."""      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)          out = self.getAttributeObject(name)
262          if isinstance(out,Link):          if isinstance(out,Link):
263              return out()              return out()
# Line 215  class LinkableObject(object): Line 265  class LinkableObject(object):
265              return out              return out
266            
267      def getAttributeObject(self,name):      def getAttributeObject(self,name):
268          """return the object stored for attribute name."""          """
269        Return the object stored for attribute name.
270        """
271    
272          if self.__dict__.has_key(name):          if self.__dict__.has_key(name):
273              return self.__dict__[name]              return self.__dict__[name]
# Line 223  class LinkableObject(object): Line 275  class LinkableObject(object):
275          if self.__linked_attributes.has_key(name):          if self.__linked_attributes.has_key(name):
276              return self.__linked_attributes[name]              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          raise AttributeError,"No attribute %s."%name
282            
283      def __setattr__(self,name,value):      def hasAttribute(self,name):
284          """sets the value for attribute name. If value is a Link the target          """
285          attribute is set to name if no attribute has been specified."""      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):          if self.__dict__.has_key(name):
296              del self.__dict__[name]              del self.__dict__[name]
# Line 238  class LinkableObject(object): Line 300  class LinkableObject(object):
300                  value.setAttributeName(name)                  value.setAttributeName(name)
301              self.__linked_attributes[name] = value              self.__linked_attributes[name] = value
302    
303              self.trace("DEBUG: %s: attribute %s is now linked by %s."%(self,name,value))              self.trace("attribute %s is now linked by %s."%(name,value))
304          else:          else:
305              self.__dict__[name] = value              self.__dict__[name] = value
306            
307      def __delattr__(self,name):      def __delattr__(self,name):
308          """removes the attribute name."""          """
309        Removes the attribute name.
310        """
311    
312          if self.__linked_attributes.has_key[name]:          if self.__linked_attributes.has_key[name]:
313              del self.__linked_attributes[name]              del self.__linked_attributes[name]
# Line 252  class LinkableObject(object): Line 316  class LinkableObject(object):
316          else:          else:
317              raise AttributeError,"No attribute %s."%name              raise AttributeError,"No attribute %s."%name
318    
 class SimulationFrame(LinkableObject):  
     """A SimulationFrame objects represents a processess marching over time  
     until a finalizing condition is fullfilled.  At each time step an iterative  
     process can be performed and the time step size can be controlled  
     """  
     UNDEF_DT=1.e300  
     MAX_TIME_STEP_REDUCTION=20  
     MAX_ITER_STEPS=50  
       
     def __init__(self,**kwargs):  
         """  
         Initialises a simulation  
           
         Just calls the parent constructor.  
         """  
         LinkableObject.__init__(self,**kwargs)  
       
     def doInitialization(self,t):  
         """initializes the time stepping scheme. This function may be  
         overwritten."""  
         pass  
       
     def getSafeTimeStepSize(self,dt):  
         """returns a time step size which can savely be used. This function may  
         be overwritten."""  
         return self.UNDEF_DT  
       
     def finalize(self):  
         """returns True if the time stepping is finalized. This function may be  
         overwritten."""  
         return True  
         
     def doFinalization(self):  
         """finalizes the time stepping.  This function may be overwritten."""  
         pass  
       
     def doIterationInitialization(self,dt):  
         """initializes the iteration at time step t. This function may be  
         overwritten. (only called if doStep is not overwritten)"""  
         pass  
       
     def doIterationStep(self,dt):  
         """executes the iteration step. This function may be overwritten. (only  
         called if doStep is not overwritten)"""  
         pass  
       
     def terminate(self):  
         """returns True if iteration on a time step is terminated. (only called  
         if doStep is not overwritten)"""  
         return True  
         
     def doIterationFinalization(self,dt):  
         """finalalizes the iteration process. (only called if doStep is not  
         overwritten)"""  
         pass  
       
     def run(self,check_point=None):  
         """run the simulation by performing essentially  
       
             self.doInitialization()  
             while not self.finalize():  
                dt=self.getSafeTimeStepSize()  
                self.doStep(dt)  
                if n%check_point==0: self.writeXML()  
             self.doFinalization()  
       
         """  
         self.__tn=0.  
         self.__n=0  
         self.__dt=None  
         self.doInitialization(self.__tn)  
         while not self.finalize():  
             self.__n+=1  
             self.__dt=self.getSafeTimeStepSize(self.__dt)  
             if self.__dt==None: self.__dt=self.UNDEF_DT  
             if not self.__dt>0:  
                  raise NonPositiveStepSizeError("non-positive step size in step %d",self.__n)  
             self.trace("%s: %d. time step %e (step size %e.)" %  
                           (self,self.__n,self.__tn+self.__dt,self.__dt))  
             endoftimestep=False  
             failcounter=0  
             while not endoftimestep:  
                 endoftimestep=True  
                 try:  
                     self.doStep(self.__dt)  
                 except FailedTimeStepError:  
                     self.__dt=self.getSafeTimeStepSize(self.__dt)  
                     if self.__dt==None: self.__dt=self.UNDEF_DT  
                     endoftimestep=False  
                     self.trace("%s: time step is repeated with new step size %e."%(self,self.__dt))  
                 except IterationDivergenceError:  
                     self.__dt*=0.5  
                     endoftimestep=False  
                     failcounter+=1  
                     if failcounter>self.MAX_TIME_STEP_REDUCTION:  
                         raise IterationBreakDownError("reduction of time step to achieve convergence failed.")  
   
                     self.trace("%s: iteration failes. time step is repeated with new step size %e."  
                         % (self,self.__dt))  
             self.__tn+=self.__dt  
             if not check_point==None:  
                 if self.__n%check_point==0:  
                     self.trace("%s: check point is created."%self)  
                     self.writeXML()  
         self.doFinalization()  
   
     def writeXML(self):  
         raise RuntimeError, "Not implemented"  
       
     def doStep(self,dt):  
         """executes a time step by iteration. This function may be overwritten.  
             
            basicly it performs :  
       
             self.doIterationInitialization(dt)  
             while not self.terminate(): self.doIterationStep(dt)  
             self.doIterationFinalization(dt)  
       
         """  
         self.doIterationInitialization(dt)  
         self.__iter=0  
         while not self.terminate():  
             self.trace("%s: iteration step %d"%(self,self.__iter))  
             self.doIterationStep(dt)  
             self.__iter+=1  
             if self.__iter>self.MAX_ITER_STEPS:  
                 raise IterationDivergenceError("%s: divergence in step %d"%(self,self.__iter))  
         self.doIterationFinalization(dt)  
   
 class Simulation(SimulationFrame):  
     """A Simulation object is comprised by SimulationFrame(s) called subsimulations."""  
       
     def __init__(self, subsimulations=[], **kwargs):  
         """initiates a simulation from a list of subsimulations. """  
         SimulationFrame.__init__(self, **kwargs)  
         self.__subsimulations=[]  
   
         for i in range(len(subsimulations)):  
             self[i] = subsimulations[i]  
       
     def iterSubsimulations(self):  
         """returns an iterator over the subsimulations"""  
         return self.__subsimulations  
       
     def __getitem__(self,i):  
         """returns the i-th subsimulation"""  
         return self.__subsimulations[i]  
       
     def __setitem__(self,i,value):  
         """sets the i-th subsimulation"""  
         if not isinstance(value,SimulationFrame):  
             raise ValueError("assigned value is not a Simulation")  
         for j in range(max(i-len(self.__subsimulations)+1,0)): self.__subsimulations.append(None)  
         self.__subsimulations[i]=value  
       
     def __len__(self):  
         """returns the number of subsimulations"""  
         return len(self.__subsimulations)  
   
     def toDom(self, document, node):  
         """ toDom method of Simulation class """  
         simulation = document.createElement('Simulation')  
         simulation.setAttribute('type', self.__class__.__name__)  
   
         for rank, sim in enumerate(self.iterSubsimulations()):  
             component = document.createElement('Component')  
             component.setAttribute('rank', str(rank))  
   
             sim.toDom(document, component)  
   
             simulation.appendChild(component)  
   
         node.appendChild(simulation)  
   
     def writeXML(self,ostream=stdout):  
         """writes the object as an XML object into an output stream"""  
         document, rootnode = esysDoc()  
         self.toDom(document, rootnode)  
         ostream.write(document.toprettyxml())  
       
     def getSafeTimeStepSize(self,dt):  
         """returns a time step size which can safely be used by all subsimulations"""  
         out=self.UNDEF_DT  
         for o in self.iterSubsimulations():  
             dt_new = o.getSafeTimeStepSize(dt)  
             if dt_new != None:  
                 out = min(out,dt_new)  
   
         return out  
       
     def doInitialization(self,dt):  
         """initializes all subsimulations """  
         for o in self.iterSubsimulations():  
             o.doInitialization(dt)  
       
     def finalize(self):  
         """returns True if all subsimulations are finalized"""  
         return all([o.finalize() for o in self.iterSubsimulations()])  
         
     def doFinalization(self):  
         """finalalizes the time stepping for all subsimulations."""  
         for i in self.iterSubsimulations(): i.doFinalization()  
       
     def doIterationInitialization(self,dt):  
         """initializes the iteration at time t for all subsimulations."""  
         self.__iter=0  
         self.trace("%s: iteration starts"%self)  
   
         for o in self.iterSubsimulations():  
             o.doIterationInitialization(dt)  
       
     def terminate(self):  
         """returns True if all iterations for all subsimulations are terminated."""  
         return all([o.terminate() for o in self.iterSubsimulations()])  
         
     def doIterationFinalization(self,dt):  
         """finalalizes the iteration process for each of the subsimulations."""  
         for o in self.iterSubsimulations():  
             o.doIterationFinalization(dt)  
         self.trace("%s: iteration finalized after %s steps"%(self,self.__iter+1))  
       
     def doIterationStep(self,dt):  
         """executes the iteration step at time step for each subsimulation"""  
         self.__iter+=1  
         self.trace("%s: iteration step %d"%(self,self.__iter))  
         for o in self.iterSubsimulations():  
             o.doIterationStep(dt)  
   
     def fromDom(cls, doc):  
         """  
         Needs to be filled out.  
         """  
         sims = []  
         for node in doc.childNodes:  
             if isinstance(node, minidom.Text):  
                 continue  
   
             sims.append(getComponent(node))  
   
   
         return cls(sims)  
   
   
               
   
   
     fromDom = classmethod(fromDom)  
   
 class ExplicitSimulation(Simulation):  
     """This is a modified form of the Simulation class. In fact it overwrites  
     the doStep method by executing the doStep method of all subsimulations  
     rather then iterating over all subsimulations."""  
   
     def doStep(self,dt):  
         """executes the time step for all subsimulation"""  
         for i in self.iterSubsimulations():  
             i.doStep(dt)  
   
319  class _ParameterIterator:  class _ParameterIterator:
320      def __init__(self,parameterset):      def __init__(self,parameterset):
321    
# Line 524  class _ParameterIterator: Line 330  class _ParameterIterator:
330          return self          return self
331    
332  class ParameterSet(LinkableObject):  class ParameterSet(LinkableObject):
333      """a class which allows to emphazise attributes to be written and read to XML      """
334        A class which allows to emphazise attributes to be written and read to XML
335                
336         Leaves of  an ESySParameters objects can be      Leaves of an ESySParameters object can be:
337            
338              a real number       - a real number
339              a integer number       - a integer number
340              a string       - a string
341              a boolean value       - a boolean value
342              a ParameterSet object       - a ParameterSet object
343              a Simulation object       - a Simulation object
344              a Model object       - a Model object
345              any other object (not considered by writeESySXML and writeXML)       - any other object (not considered by writeESySXML and writeXML)
346            
347             Example how to create an ESySParameters object:      Example how to create an ESySParameters object::
348            
349                   p11=ParameterSet(gamma1=1.,gamma2=2.,gamma3=3.)          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)          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")))          parm=ParameterSet(parm1=p1,parm2=ParameterSet(alpha=Link(p11,"gamma1")))
352            
353             This can be accessed as      This can be accessed as::
354            
355                   parm.parm1.gamma=0.      parm.parm1.gamma=0.
356                   parm.parm1.dim=2          parm.parm1.dim=2
357                   parm.parm1.tol_v=0.001          parm.parm1.tol_v=0.001
358                   parm.parm1.output_file="/tmp/u.%3.3d.dx"          parm.parm1.output_file="/tmp/u.%3.3d.dx"
359                   parm.parm1.runFlag=True          parm.parm1.runFlag=True
360                   parm.parm1.parm11.gamma1=1.          parm.parm1.parm11.gamma1=1.
361                   parm.parm1.parm11.gamma2=2.          parm.parm1.parm11.gamma2=2.
362                   parm.parm1.parm11.gamma3=3.          parm.parm1.parm11.gamma3=3.
363                   parm.parm2.alpha=1. (value of parm.parm1.parm11.gamma1)          parm.parm2.alpha=1. (value of parm.parm1.parm11.gamma1)
               
364      """      """
365      def __init__(self, parameters=[], **kwargs):      def __init__(self, parameters=[], **kwargs):
366          """creates a ParameterSet with parameters parameters"""          """
367        Creates a ParameterSet with parameters parameters.
368        """
369          LinkableObject.__init__(self, **kwargs)          LinkableObject.__init__(self, **kwargs)
370          self.parameters = set()          self.parameters = set()
371          self.declareParameters(parameters)          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):      def declareParameter(self,**parameters):
378          """declares a new parameter(s) and its (their) inital value."""          """
379        Declares a new parameter(s) and its (their) initial value.
380        """
381          self.declareParameters(parameters)          self.declareParameters(parameters)
382            
383      def declareParameters(self,parameters):      def declareParameters(self,parameters):
384          """declares a set of parameters. parameters can be a list, a dictonary or a ParameterSet."""          """
385        Declares a set of parameters. parameters can be a list, a dictionary
386        or a ParameterSet.
387        """
388          if isinstance(parameters,ListType):          if isinstance(parameters,ListType):
389              parameters = zip(parameters, itertools.repeat(None))              parameters = zip(parameters, itertools.repeat(None))
390          if isinstance(parameters,DictType):          if isinstance(parameters,DictType):
# Line 577  class ParameterSet(LinkableObject): Line 394  class ParameterSet(LinkableObject):
394              setattr(self,prm,value)              setattr(self,prm,value)
395              self.parameters.add(prm)              self.parameters.add(prm)
396    
397              self.trace("%s: parameter %s has been declared."%(self,prm))              self.trace("parameter %s has been declared."%prm)
398    
399      def releaseParameters(self,name):      def releaseParameters(self,name):
400          """removes parameter name from the paramameters"""          """
401        Removes parameter name from the paramameters.
402        """
403          if self.isParameter(name):          if self.isParameter(name):
404              self.parameters.remove(name)              self.parameters.remove(name)
405              self.debug("%s: parameter %s has been removed."%(self, name))              self.trace("parameter %s has been removed."%name)
406            
407      def __iter__(self):      def __iter__(self):
408          """creates an iterator over the parameter and their values"""          """
409        Creates an iterator over the parameter and their values.
410        """
411          return _ParameterIterator(self)          return _ParameterIterator(self)
412            
413      def showParameters(self):      def showParameters(self):
414          """returns a descrition of the parameters"""                  """
415        Returns a descrition of the parameters.
416        """        
417          out="{"          out="{"
418          notfirst=False          notfirst=False
419          for i,v in self:          for i,v in self:
# Line 603  class ParameterSet(LinkableObject): Line 426  class ParameterSet(LinkableObject):
426          return out+"}"          return out+"}"
427            
428      def __delattr__(self,name):      def __delattr__(self,name):
429          """removes the attribute name."""          """
430        Removes the attribute name.
431        """
432          LinkableObject.__delattr__(self,name)          LinkableObject.__delattr__(self,name)
433          try:          try:
434              self.releaseParameter(name)              self.releaseParameter(name)
# Line 611  class ParameterSet(LinkableObject): Line 436  class ParameterSet(LinkableObject):
436              pass              pass
437    
438      def toDom(self, document, node):      def toDom(self, document, node):
439          """ toDom method of ParameterSet class """          """
440        C{toDom} method of ParameterSet class.
441        """
442          pset = document.createElement('ParameterSet')          pset = document.createElement('ParameterSet')
443          node.appendChild(pset)          node.appendChild(pset)
444          self._parametersToDom(document, pset)          self._parametersToDom(document, pset)
# Line 639  class ParameterSet(LinkableObject): Line 466  class ParameterSet(LinkableObject):
466    
467              node.appendChild(param)              node.appendChild(param)
468    
     
469      def fromDom(cls, doc):      def fromDom(cls, doc):
470    
471          # Define a host of helper functions to assist us.          # Define a host of helper functions to assist us.
472          def _children(node):          def _children(node):
473              """              """
474              Remove the empty nodes from the children of this node              Remove the empty nodes from the children of this node.
475              """              """
476              return [x for x in node.childNodes              return [x for x in node.childNodes
477                      if not isinstance(x, minidom.Text) or x.nodeValue.strip()]                      if not isinstance(x, minidom.Text) or x.nodeValue.strip()]
# Line 673  class ParameterSet(LinkableObject): Line 499  class ParameterSet(LinkableObject):
499                      "bool":_boolfromValue                      "bool":_boolfromValue
500                      }                      }
501    
502    #        print doc.toxml()
503    
504          parameters = {}          parameters = {}
505          for node in _children(doc):          for node in _children(doc):
506              ptype = node.getAttribute("type")              ptype = node.getAttribute("type")
# Line 698  class ParameterSet(LinkableObject): Line 526  class ParameterSet(LinkableObject):
526      fromDom = classmethod(fromDom)      fromDom = classmethod(fromDom)
527            
528      def writeXML(self,ostream=stdout):      def writeXML(self,ostream=stdout):
529          """writes the object as an XML object into an output stream"""          """
530        Writes the object as an XML object into an output stream.
531        """
532          # ParameterSet(d) with d[Name]=Value          # ParameterSet(d) with d[Name]=Value
533          document, node = esysDoc()          document, node = esysDoc()
534          self.toDom(document, node)          self.toDom(document, node)
535          ostream.write(document.toprettyxml())          ostream.write(document.toprettyxml())
536    
537  class Model(ParameterSet,SimulationFrame):  class Model(ParameterSet):
538      """a Model is a SimulationFrame which is also a ParameterSet."""      """
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=[],**kwargs):      def __init__(self,parameters=[],**kwarg):
562          """creates a model"""          """
563          ParameterSet.__init__(self, parameters=parameters)      Creates a model.
564          SimulationFrame.__init__(self,**kwargs)  
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):      def toDom(self, document, node):
573          """ toDom method of Model class """          """
574        C{toDom} method of Model class
575        """
576          pset = document.createElement('Model')          pset = document.createElement('Model')
577          pset.setAttribute('type', self.__class__.__name__)          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)          node.appendChild(pset)
581          self._parametersToDom(document, pset)          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  class IterationDivergenceError(Exception):          C{dt} gives the previously used step size.
     """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  
        to reach convergence."""  
     pass  
   
 class IterationBreakDownError(Exception):  
     """excpetion which should be thrown if there is no conevregence and there is no chance that a time step reduction would help"""  
     pass  
   
 class FailedTimeStepError(Exception):  
     """excpetion which should be thrown if the time step fails because of a step size that have been choosen to be to large"""  
     pass  
   
 class NonPositiveStepSizeError(Exception):  
     """excpetion which is thrown if the step size is not positive"""  
     pass  
   
 #  
 #   ignore this text:  
 #  
 """  
 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:  
   
        1) use object attributes:  
   
           m.message="Hello World!"  
   
        2) use setParamter method  
           
             
           m.setParameters(message="Hello World!")  
596    
597         3) or dictonaries          This function may be overwritten.
598          """
599             d={ message : "Hello World!" }          return self.UNDEF_DT
600             m.setParameters(**d)      
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        def doFinalization(self):
610            """
611        Finalizes the time stepping.
612        
613        This function may be overwritten.
614        """
615            pass
616        
617        def doStepPreprocessing(self,dt):
618            """
619        Sets up a time step of step size dt.
620        
621        This function may be overwritten.
622        """
623            pass
624        
625        def doStep(self,dt):
626            """
627        Executes an iteration step at a time step.
628    
629            C{dt} is the currently used time step size.
630    
631         A model executed buy staring the run method of the model:          This function may be overwritten.
632        """
633            m=Messenger()          pass
634            m.run()      
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         The run methods marches through time. It first calls the          dt is the currently used time step size.
        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" })  
646    
647              def doInitialization(self):          This function may be overwritten.
648                 print "I start talking now!"      """
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              def doStep(self,t):  class Simulation(Model):
658                 print "Message (time %e) : %s "%(t,self.message)      """
659        A Simulation object is special Model which runs a sequence of Models.
660    
661              def doFinalization(self):      The methods C{doInitialization}, C{finalize}, C{getSafeTimeStepSize},
662                 print "I have no more to say!"      C{doStepPreprocessing}, C{terminateIteration}, C{doStepPostprocessing},
663              C{doFinalization} are executing the corresponding methods of the models in
664         If a instance of the Messenger class is run, it will print the      the simulation.
665         initialization and finalization message only.  This is because the      """
666         default method for finalize() does always returns True and therefore the      
667         transition is terminated startcht away.      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         Following example for solving the ODE using a forward euler scheme:          for i in range(len(models)):
678                self[i] = models[i]
679                  u(t=0)=u0              
                 u_t=a*u**2       for all 0<t<=ten  
680    
681        exact solution is given by u(t)=1/(1/u0-a*t)      def __repr__(self):
682            """
683            Returns a string representation of the Simulation.
684            """
685            return "<Simulation %r>" % self.__models
686    
687        class  Ode1(Model):      def __str__(self):
688           def __init__(self,**args):          """
689              Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 1. },name="test",debug=True)          Returning Simulation as a string.
690            """
691           def doInitialization(self):          return "<Simulation %d>"%id(self)
692               self._tn=0      
693        def iterModels(self):
694           def doStep(self,t):          """
695               self.u=self.u+(t-self._tn)*self.a*self.u**2      Returns an iterator over the models.
696               self._tn=t      """
697            return self.__models
698           def doFinalization(self):      
699               print "all done final error = ",abs(self.u-1./(1./3.-self.a*self._tn))      def __getitem__(self,i):
700            """
701           def getSafeTimeStepSize(self):      Returns the i-th model.
702               return self.dt      """
703            return self.__models[i]
704           def finalize(self):      
705               return self._tn>=self.tend      def __setitem__(self,i,value):
706            """
707         In some cases at a given time step an iteration process has to be      Sets the i-th model.
708         performed to get the state of the Model for the next time step. ` In      """
709         this case the doStep() method is replaced by a sequance of methods which          if not isinstance(value,Model):
710         implements this iterative process.  The method then will control the              raise ValueError("assigned value is not a Model")
711         iteration process by initializing the iteration through calling the          for j in range(max(i-len(self.__models)+1,0)):
712         doIterationInitialization() method. The iteration is preformed by              self.__models.append(None)
713         calling the doIterationStep() method until the terminate() method          self.__models[i]=value
714         returns True. The doIterationFinalization() method is called to end the      
715         iteration.      def __len__(self):
716         For a particular model these methods have to overwritten by a suitable          """
717         subclass without touching the doStep() method.      Returns the number of models.
718        """
719            return len(self.__models)
720    
721         following example is a modification of the example above. Here an      def toDom(self, document, node):
722         implicit euler scheme is used. in each time step the problem          """
723                  C{toDom} method of Simulation class.
724             0= u_{n+1}-u_{n}+a*dt*u_{n+1}**2      """
725            simulation = document.createElement('Simulation')
726            simulation.setAttribute('type', self.__class__.__name__)
727    
728         has to be solved for u_{n+1}. The Newton scheme is used to solve this non-linear problem.          for rank, sim in enumerate(self.iterModels()):
729                component = document.createElement('Component')
730                component.setAttribute('rank', str(rank))
731    
732                sim.toDom(document, component)
       class  Ode2(Model):  
733    
734         def __init__(self,**args):              simulation.appendChild(component)
            Model.__init__(self,{"tend" : 1., "dt" : 0.1 ,"a" : 10. ,"u" : 1. , "tol " : 1.e-8},"test","bla",None,True)  
735    
736         def doInitialization(self):          node.appendChild(simulation)
            self.__tn=0  
737    
738         def doIterationInitialization(self,t):      def writeXML(self,ostream=stdout):
739              self.__iter=0          """
740              self.u_last=self.u                  Writes the object as an XML object into an output stream.
741              self.current_dt=t-self.tn      """
742              self.__tn=t          document, rootnode = esysDoc()
743            self.toDom(document, rootnode)
744         def doIterationStep(self):          targetsList = document.getElementsByTagName('Target')
745            self.__iter+=1          for i in targetsList:
746            self.u_old=self.u              targetId = int(i.firstChild.nodeValue.strip())
747            self.u=(self.current_dt*self.a*self.u**2-self.u_last)/(2*self.current_dt*self.a*self.u-1.)              targetObj = LinkableObjectRegistry[targetId]
748                targetObj.toDom(document, rootnode)
749         def terminate(self):          ostream.write(document.toprettyxml())
750             return abs(self.u_old-self.u)<self.tol*abs(self.u)      
751        def getSafeTimeStepSize(self,dt):
752         def doIterationFinalization(self)          """
753             print "all done"      Returns a time step size which can safely be used by all models.
   
        def getSafeTimeStepSize(self):  
            return self.dt  
   
        def finalize(self):  
             return self.__tn>self.tend  
   
        A model can be composed from subsimulations. Subsimulations 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  
        subsimulations in the case the model does not have this parameter  
        itself. The order in which the subsimulations are searched is critical.  
        By default a Model initializes all its subsimulations, is finalized when  
        all its subsimulations are finalized and finalizes all its  
        subsimulations. In the case an iterative process is applied on a  
        particular time step the iteration is initialized for all  
        subsimulations, then the iteration step is performed for each  
        subsimulation until all subsimulations indicate termination. Then the  
        iteration is finalized for all subsimulations. 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(subsimulations=[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  
        subsimulation. 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.  
754    
755         A parameter of a Model can be linked to an attribute of onother object,          This is the minimum over the time step sizes of all models.
756         typically an parameter of another Model object.          """
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         which is comprised by a set of subsimulations.      def doStepPostprocessing(self,dt):
798         The simulation is run through its run method which in the simplest case has the form:          """
799        Finalalizes the iteration process for all models.
800            s=Model()      """
801            s.run()          for o in self.iterModels():
802                o.doStepPostprocessing(dt)
803         The run has an initializion and finalization phase. The latter is called          self.n+=1
804         if all subsimulations are to be finalized. The simulation is processing          self.tn+=dt
805         in time through calling the stepForward methods which updates the      
806         observables of each subsimulation.  A time steps size which is save for      def doStep(self,dt):
807         all subsimulation is choosen.          """
808        Executes the iteration step at a time step for all model::
809         At given time step an iterative process may be performed to make sure  
810         that all observables are consistent across all subsimulations.  In this              self.doStepPreprocessing(dt)
811         case, similar the time dependence, an initialization and finalization of              while not self.terminateIteration():
812         the iteration is performed.              for all models:
813                self.doStep(dt)
814         A Model has input and output parameters where each input parameter can                  self.doStepPostprocessing(dt)
815         be constant, time dependent or may depend on an output parameter of          """
816         another model or the model itself. To create a parameter name of a model          self.iter=0
817         and to assign a value to it one can use the statement          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             model.name=object              self.iter+=1
820                self.trace("iteration step %d"%(self.iter))
821                for o in self.iterModels():
822         At any time the current value of the parameter name can be obtained by                    o.doStep(dt)
823            if self.iter>0: self.trace("iteration at %d-th time step %e finalized."%(self.n+1,self.tn+dt))
                value=model.name  
   
        If the object that has been assigned to the paramter/attribute name has  
        the attribute/parameter name isself the current value of this 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 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  
   
            model.setParameter(name,object,name_for_object)  
   
        links the parameter name of model with the parameter name_for_object of  
        object.  
   
        The run method initiates checkpointing (it is not clear how to do this  
        yet)  
    =====  
               
    """  
   
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 __name__=="__main__":          In both cases the time integration is given up after
845      import math      C{Simulation.FAILED_TIME_STEPS_MAX} attempts.
846      #          """
847      # test for parameter set          dt=self.UNDEF_DT
848      #          self.doInitialization()
849      p11=ParameterSet()          while not self.finalize():
850      p11.declareParameter(gamma1=1.,gamma2=2.,gamma3=3.)              step_fail_counter=0
851      p1=ParameterSet()              iteration_fail_counter=0
852      p1.declareParameter(dim=2,tol_v=0.001,output_file="/tmp/u.%3.3d.dx",runFlag=True,parm11=p11)              dt_new=self.getSafeTimeStepSize(dt)
853      parm=ParameterSet({ "parm1" : p1 , "parm2" : ParameterSet(["alpha"])})              self.trace("%d. time step %e (step size %e.)" % (self.n+1,self.tn+dt_new,dt_new))
854      parm.parm2.alpha=Link(p11,"gamma1")              end_of_step=False
855      parm.x="that should not be here!"              while not end_of_step:
856      print parm.showParameters()                 end_of_step=True
857      # should be something like: {"parm2" : {"alpha" : reference to attribute                 if not dt_new>0:
858      # gamma1 of <__main__.ParameterSet instance at 0xf6db51cc>},"parm1" : {"dim"                    raise NonPositiveStepSizeError("non-positive step size in step %d",self.n+1)
859      # : 2,"runFlag" : True,"tol_v": 0.001,"parm11" : {"gamma3" : 3.0,"gamma2" :                 try:
860      # 2.0,"gamma1" : 1.0},"output_file" : /tmp/u.%3.3d.dx}}                    self.doStepPreprocessing(dt_new)
861      assert parm.parm2.alpha==1.                    self.doStep(dt_new)
862      parm.writeXML()                    self.doStepPostprocessing(dt_new)
863                       except IterationDivergenceError:
864      #=======================                    dt_new*=0.5
865      class Messenger(Model):                    end_of_step=False
866          def __init__(self):                    iteration_fail_counter+=1
867              Model.__init__(self)                    if iteration_fail_counter>self.FAILED_TIME_STEPS_MAX:
868              self.declareParameter(message="none")                             raise SimulationBreakDownError("reduction of time step to achieve convergence failed.")
869                      self.trace("iteration fails. time step is repeated with new step size.")
870          def doInitialization(self,t):                 except FailedTimeStepError:
871              self.__t=t                    dt_new=self.getSafeTimeStepSize(dt)
872              print "I start talking now!"                    end_of_step=False
873                      step_fail_counter+=1
874          def doStep(self,dt):                    self.trace("time step is repeated.")
875              self.__t+=dt                    if step_fail_counter>self.FAILED_TIME_STEPS_MAX:
876              print "Message (time %e) : %s "%(self.__t,self.message)                          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 doFinalization(self):      def fromDom(cls, doc):
885              print "I have no more to say!"          sims = []
886              for node in doc.childNodes:
887      class ODETEST(Model):              if isinstance(node, minidom.Text):
888          """ implements a solver for the ODE                  continue
889    
890                du/dt=a*u+f(t)              sims.append(getComponent(node))
891    
892             we use a implicit euler scheme :          return cls(sims)
893    
894                u_n-u_{n-1}= dt*a u_n + st*f(t_n)      fromDom = classmethod(fromDom)
895    
            to get u_n we run an iterative process  
   
                u_{n.k}=u_{n-1}+dt*(a u_{n.i-1} + f(t_n))  
896    
897    class IterationDivergenceError(Exception):
898        """
899        Exception which is thrown if there is no convergence of the iteration
900        process at a time step.
901    
902             input for this model are step size dt, end time tend and a value for      But there is a chance that a smaller step could help to reach convergence.
903             a, f and initial value for u. we need also a tolerance tol for a      """
904             stopping criterion.      pass
905    
906          """  class FailedTimeStepError(Exception):
907        """
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
912    
913          def __init__(self):  class SimulationBreakDownError(Exception):
914              Model.__init__(self,debug=True)      """
915              self.declareParameter(tend=1.,dt=0.1,a=0.9,u=10.,f=0.,message="",tol=1.e-8)      Exception which is thrown if the simulation does not manage to
916        progress in time.
917        """
918        pass
919    
920          def doInitialization(self,t):  class NonPositiveStepSizeError(Exception):
921              self.__tn=t      """
922              self.__iter=0      Exception which is thrown if the step size is not positive.
923                  """
924          def doIterationInitialization(self,dt):      pass
             self.__iter=0  
             self.__u_last=self.u              
   
         def doIterationStep(self,dt):  
             self.__iter+=1  
             self.__u_old=self.u  
             self.u=self.__u_last+dt*(self.a*self.__u_old+self.f)  
           
         def terminate(self):  
             if self.__iter<1:  
                 return False  
             else:  
                 return abs(self.__u_old-self.u)<self.tol*abs(self.u)  
925    
926          def doIterationFinalization(self,dt):  # vim: expandtab shiftwidth=4:
             self.__tn+=dt  
             self.message="current error = %e"%abs(self.u-10.*math.exp((self.a-1.)*self.__tn))  
   
         def getSafeTimeStepSize(self,dt):  
             return min(self.dt,1./(abs(self.a)+1.))  
   
         def finalize(self):  
             return self.__tn>=self.tend  
   
     #  
     #   s solves the coupled ODE:  
     #  
     #     du/dt=a*u+  v  
     #     dv/dt=  u+a*v  
     #    
     #   each equation is treated through the ODETEST class. The equations are  
     #   linked and iteration over each time step is performed.  the current  
     #   error of v is reported by the Messenger class.  
     #  
     o1=ODETEST()  
     o1.u=10  
     o2=ODETEST()  
     o2.u=-10.  
     o1.f=Link(o2,"u")  
     o2.f=Link(o1,"u")  
     m=Messenger()  
     o1.dt=0.01  
     m.message=Link(o1)  
     s=ExplicitSimulation([Simulation([o1,o2],debug=True),m],debug=True)  
     s.run()  
     s.writeXML()  

Legend:
Removed from v.142  
changed lines
  Added in v.155

  ViewVC Help
Powered by ViewVC 1.1.26