/[escript]/trunk-mpi-branch/escript/py_src/util.py
ViewVC logotype

Diff of /trunk-mpi-branch/escript/py_src/util.py

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

trunk/esys2/escript/py_src/util.py revision 149 by jgs, Thu Sep 1 03:31:39 2005 UTC trunk-mpi-branch/escript/py_src/util.py revision 1295 by ksteube, Mon Sep 10 06:07:09 2007 UTC
# Line 1  Line 1 
1  # $Id$  # $Id$
2    
 ## @file util.py  
   
3  """  """
4  Utility functions for escript  Utility functions for escript
5    
6  @todo:  @var __author__: name of author
7    @var __copyright__: copyrights
8    - binary operations @ (@=+,-,*,/,**)::  @var __license__: licence agreement
9        (a@b)[:,*]=a[:]@b[:,*] if rank(a)<rank(b)  @var __url__: url entry point on documentation
10        (a@b)[:]=a[:]@b[:] if rank(a)=rank(b)  @var __version__: version
11        (a@b)[*,:]=a[*,:]@b[:] if rank(a)>rank(b)  @var __date__: date of the version
   - implementation of outer::  
       outer(a,b)[:,*]=a[:]*b[*]  
   - trace::  
       trace(arg,axis0=a0,axis1=a1)(:,&,*)=sum_i trace(:,i,&,i,*) (i are at index a0 and a1)  
12  """  """
13                                                                                                                                                                                                        
14    __author__="Lutz Gross, l.gross@uq.edu.au"
15    __copyright__="""  Copyright (c) 2006 by ACcESS MNRF
16                        http://www.access.edu.au
17                    Primary Business: Queensland, Australia"""
18    __license__="""Licensed under the Open Software License version 3.0
19                 http://www.opensource.org/licenses/osl-3.0.php"""
20    __url__="http://www.iservo.edu.au/esys/escript"
21    __version__="$Revision$"
22    __date__="$Date$"
23    
24    
25    import math
26  import numarray  import numarray
27  import escript  import escript
28    import os
29    from esys.escript import C_GeneralTensorProduct
30    from esys.escript import getVersion
31    
32    #=========================================================
33    #   some helpers:
34    #=========================================================
35    def getTagNames(domain):
36        """
37        returns a list of the tag names used by the domain
38    
39        
40        @param domain: a domain object
41        @type domain: L{escript.Domain}
42        @return: a list of the tag name used by the domain.
43        @rtype: C{list} of C{str}
44        """
45        return [n.strip() for n in domain.showTagNames().split(",") ]
46    
47    def insertTagNames(domain,**kwargs):
48        """
49        inserts tag names into the domain
50    
51        @param domain: a domain object
52        @type domain: C{escript.Domain}
53        @keyword <tag name>: tag key assigned to <tag name>
54        @type <tag name>: C{int}
55        """
56        for  k in kwargs:
57             domain.setTagMap(k,kwargs[k])
58    
59    def insertTaggedValues(target,**kwargs):
60        """
61        inserts tagged values into the tagged using tag names
62    
63        @param target: data to be filled by tagged values
64        @type target: L{escript.Data}
65        @keyword <tag name>: value to be used for <tag name>
66        @type <tag name>: C{float} or {numarray.NumArray}
67        @return: C{target}
68        @rtype: L{escript.Data}
69        """
70        for k in kwargs:
71            target.setTaggedValue(k,kwargs[k])
72        return target
73    
74    def saveVTK(filename,domain=None,**data):
75        """
76        writes a L{Data} objects into a files using the the VTK XML file format.
77    
78        Example::
79    
80           tmp=Scalar(..)
81           v=Vector(..)
82           saveVTK("solution.xml",temperature=tmp,velovity=v)
83    
84        tmp and v are written into "solution.xml" where tmp is named "temperature" and v is named "velovity"
85    
86        @param filename: file name of the output file
87        @type filename: C{str}
88        @param domain: domain of the L{Data} object. If not specified, the domain of the given L{Data} objects is used.
89        @type domain: L{escript.Domain}
90        @keyword <name>: writes the assigned value to the VTK file using <name> as identifier.
91        @type <name>: L{Data} object.
92        @note: The data objects have to be defined on the same domain. They may not be in the same L{FunctionSpace} but one cannot expect that all L{FunctionSpace} can be mixed. Typically, data on the boundary and data on the interior cannot be mixed.
93        """
94        new_data={}
95        for n,d in data.items():
96              if not d.isEmpty():
97                fs=d.getFunctionSpace()
98                domain2=fs.getDomain()
99                if fs == escript.Solution(domain2):
100                   new_data[n]=interpolate(d,escript.ContinuousFunction(domain2))
101                elif fs == escript.ReducedSolution(domain2):
102                   new_data[n]=interpolate(d,escript.ReducedContinuousFunction(domain2))
103                else:
104                   new_data[n]=d
105                if domain==None: domain=domain2
106        if domain==None:
107            raise ValueError,"no domain detected."
108        domain.saveVTK(filename,new_data)
109    
110    def saveDX(filename,domain=None,**data):
111        """
112        writes a L{Data} objects into a files using the the DX file format.
113    
114        Example::
115    
116           tmp=Scalar(..)
117           v=Vector(..)
118           saveDX("solution.dx",temperature=tmp,velovity=v)
119    
120        tmp and v are written into "solution.dx" where tmp is named "temperature" and v is named "velovity".
121    
122        @param filename: file name of the output file
123        @type filename: C{str}
124        @param domain: domain of the L{Data} object. If not specified, the domain of the given L{Data} objects is used.
125        @type domain: L{escript.Domain}
126        @keyword <name>: writes the assigned value to the DX file using <name> as identifier. The identifier can be used to select the data set when data are imported into DX.
127        @type <name>: L{Data} object.
128        @note: The data objects have to be defined on the same domain. They may not be in the same L{FunctionSpace} but one cannot expect that all L{FunctionSpace} can be mixed. Typically, data on the boundary and data on the interior cannot be mixed.
129        """
130        new_data={}
131        for n,d in data.items():
132              if not d.isEmpty():
133                fs=d.getFunctionSpace()
134                domain2=fs.getDomain()
135                if fs == escript.Solution(domain2):
136                   new_data[n]=interpolate(d,escript.ReducedContinuousFunction(domain2))
137                elif fs == escript.ReducedSolution(domain2):
138                   new_data[n]=interpolate(d,escript.ReducedContinuousFunction(domain2))
139                elif fs == escript.ContinuousFunction(domain2):
140                   new_data[n]=interpolate(d,escript.ReducedContinuousFunction(domain2))
141                else:
142                   new_data[n]=d
143                if domain==None: domain=domain2
144        if domain==None:
145            raise ValueError,"no domain detected."
146        domain.saveDX(filename,new_data)
147    
148    def kronecker(d=3):
149       """
150       return the kronecker S{delta}-symbol
151    
152       @param d: dimension or an object that has the C{getDim} method defining the dimension
153       @type d: C{int}, L{escript.Domain} or L{escript.FunctionSpace}
154       @return: the object u of rank 2 with M{u[i,j]=1} for M{i=j} and M{u[i,j]=0} otherwise
155       @rtype: L{numarray.NumArray} or L{escript.Data} of rank 2.
156       """
157       return identityTensor(d)
158    
159    def identity(shape=()):
160       """
161       return the shape x shape identity tensor
162    
163       @param shape: input shape for the identity tensor
164       @type shape: C{tuple} of C{int}
165       @return: array of shape shape x shape with M{u[i,k]=1} for M{i=k} and M{u[i,k]=0} otherwise for len(shape)=1 and, for len(shape)=2: M{u[i,j,k,l]=1} for M{i=k and j=l} and M{u[i,j,k,l]=0} otherwise.
166       @rtype: L{numarray.NumArray} of rank 1, rankk 2 or rank 4.
167       @raise ValueError: if len(shape)>2.
168       """
169       if len(shape)>0:
170          out=numarray.zeros(shape+shape,numarray.Float64)
171          if len(shape)==1:
172              for i0 in range(shape[0]):
173                 out[i0,i0]=1.
174          elif len(shape)==2:
175              for i0 in range(shape[0]):
176                 for i1 in range(shape[1]):
177                    out[i0,i1,i0,i1]=1.
178          else:
179              raise ValueError,"identity: length of shape is restricted to 2."
180       else:
181          out=1.
182       return out
183    
184    def identityTensor(d=3):
185       """
186       return the dxd identity matrix
187    
188       @param d: dimension or an object that has the C{getDim} method defining the dimension
189       @type d: C{int}, L{escript.Domain} or L{escript.FunctionSpace}
190       @return: the object u of rank 2 with M{u[i,j]=1} for M{i=j} and M{u[i,j]=0} otherwise
191       @rtype: L{numarray.NumArray} or L{escript.Data} of rank 2
192       """
193       if isinstance(d,escript.FunctionSpace):
194           return escript.Data(identity((d.getDim(),)),d)
195       elif isinstance(d,escript.Domain):
196           return identity((d.getDim(),))
197       else:
198           return identity((d,))
199    
200  #===========================================================  def identityTensor4(d=3):
201  # a simple tool box to deal with _differentials of functions     """
202  #===========================================================     return the dxdxdxd identity tensor
203    
204  class Symbol:     @param d: dimension or an object that has the C{getDim} method defining the dimension
205       @type d: C{int} or any object with a C{getDim} method
206       @return: the object u of rank 4 with M{u[i,j,k,l]=1} for M{i=k and j=l} and M{u[i,j,k,l]=0} otherwise
207       @rtype: L{numarray.NumArray} or L{escript.Data} of rank 4.
208     """     """
209     Symbol class.     if isinstance(d,escript.FunctionSpace):
210           return escript.Data(identity((d.getDim(),d.getDim())),d)
211       elif isinstance(d,escript.Domain):
212           return identity((d.getDim(),d.getDim()))
213       else:
214           return identity((d,d))
215    
216    def unitVector(i=0,d=3):
217     """     """
218     def __init__(self,name="symbol",shape=(),dim=3,args=[]):     return a unit vector u of dimension d with nonzero index i:
219         """  
220         Creates an instance of a symbol of shape shape and spatial dimension     @param i: index
221         dim.     @type i: C{int}
222             @param d: dimension or an object that has the C{getDim} method defining the dimension
223         The symbol may depending on a list of arguments args which may be     @type d: C{int}, L{escript.Domain} or L{escript.FunctionSpace}
224         symbols or other objects. name gives the name of the symbol.     @return: the object u of rank 1 with M{u[j]=1} for M{j=i} and M{u[i]=0} otherwise
225       @rtype: L{numarray.NumArray} or L{escript.Data} of rank 1
226       """
227       return kronecker(d)[i]
228    
229    #=========================================================================
230    #   global reduction operations (these functions have no symbolic version)
231    #=========================================================================
232    def Lsup(arg):
233        """
234        returns the Lsup-norm of argument arg. This is the maximum absolute value over all data points.
235        This function is equivalent to sup(abs(arg)).
236    
237        @param arg: argument
238        @type arg: C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
239        @return: maximum value of the absolute value of arg over all components and all data points
240        @rtype: C{float}
241        @raise TypeError: if type of arg cannot be processed
242        """
243        if isinstance(arg,numarray.NumArray):
244            return sup(abs(arg))
245        elif isinstance(arg,escript.Data):
246            return arg._Lsup()
247        elif isinstance(arg,float):
248            return abs(arg)
249        elif isinstance(arg,int):
250            return abs(float(arg))
251        else:
252          raise TypeError,"Lsup: Unknown argument type."
253    
254    def sup(arg):
255        """
256        returns the maximum value over all data points.
257    
258        @param arg: argument
259        @type arg: C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
260        @return: maximum value of arg over all components and all data points
261        @rtype: C{float}
262        @raise TypeError: if type of arg cannot be processed
263        """
264        if isinstance(arg,numarray.NumArray):
265            return arg.max()
266        elif isinstance(arg,escript.Data):
267            return arg._sup()
268        elif isinstance(arg,float):
269            return arg
270        elif isinstance(arg,int):
271            return float(arg)
272        else:
273          raise TypeError,"sup: Unknown argument type."
274    
275    def inf(arg):
276        """
277        returns the maximum value over all data points.
278    
279        @param arg: argument
280        @type arg: C{float}, C{int}, L{escript.Data}, L{numarray.NumArray}.
281        @return: minimum value of arg over all components and all data points
282        @rtype: C{float}
283        @raise TypeError: if type of arg cannot be processed
284        """
285        if isinstance(arg,numarray.NumArray):
286            return arg.min()
287        elif isinstance(arg,escript.Data):
288            return arg._inf()
289        elif isinstance(arg,float):
290            return arg
291        elif isinstance(arg,int):
292            return float(arg)
293        else:
294          raise TypeError,"inf: Unknown argument type."
295    
296    
297    #=========================================================================
298    #   some little helpers
299    #=========================================================================
300    def getRank(arg):
301        """
302        identifies the rank of its argument
303    
304        @param arg: a given object
305        @type arg: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
306        @return: the rank of the argument
307        @rtype: C{int}
308        @raise TypeError: if type of arg cannot be processed
309        """
310    
311        if isinstance(arg,numarray.NumArray):
312            return arg.rank
313        elif isinstance(arg,escript.Data):
314            return arg.getRank()
315        elif isinstance(arg,float):
316            return 0
317        elif isinstance(arg,int):
318            return 0
319        elif isinstance(arg,Symbol):
320            return arg.getRank()
321        else:
322          raise TypeError,"getShape: cannot identify shape"
323    def getShape(arg):
324        """
325        identifies the shape of its argument
326    
327        @param arg: a given object
328        @type arg: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
329        @return: the shape of the argument
330        @rtype: C{tuple} of C{int}
331        @raise TypeError: if type of arg cannot be processed
332        """
333    
334        if isinstance(arg,numarray.NumArray):
335            return arg.shape
336        elif isinstance(arg,escript.Data):
337            return arg.getShape()
338        elif isinstance(arg,float):
339            return ()
340        elif isinstance(arg,int):
341            return ()
342        elif isinstance(arg,Symbol):
343            return arg.getShape()
344        else:
345          raise TypeError,"getShape: cannot identify shape"
346    
347    def pokeDim(arg):
348        """
349        identifies the spatial dimension of its argument
350    
351        @param arg: a given object
352        @type arg: any
353        @return: the spatial dimension of the argument, if available, or C{None}
354        @rtype: C{int} or C{None}
355        """
356    
357        if isinstance(arg,escript.Data):
358            return arg.getFunctionSpace().getDim()
359        elif isinstance(arg,Symbol):
360            return arg.getDim()
361        else:
362            return None
363    
364    def commonShape(arg0,arg1):
365        """
366        returns a shape to which arg0 can be extendent from the right and arg1 can be extended from the left.
367    
368        @param arg0: an object with a shape (see L{getShape})
369        @param arg1: an object with a shape (see L{getShape})
370        @return: the shape of arg0 or arg1 such that the left port equals the shape of arg0 and the right end equals the shape of arg1.
371        @rtype: C{tuple} of C{int}
372        @raise ValueError: if no shape can be found.
373        """
374        sh0=getShape(arg0)
375        sh1=getShape(arg1)
376        if len(sh0)<len(sh1):
377           if not sh0==sh1[:len(sh0)]:
378                 raise ValueError,"argument 0 cannot be extended to the shape of argument 1"
379           return sh1
380        elif len(sh0)>len(sh1):
381           if not sh1==sh0[:len(sh1)]:
382                 raise ValueError,"argument 1 cannot be extended to the shape of argument 0"
383           return sh0
384        else:
385           if not sh0==sh1:
386                 raise ValueError,"argument 1 and argument 0 have not the same shape."
387           return sh0
388    
389    def commonDim(*args):
390        """
391        identifies, if possible, the spatial dimension across a set of objects which may or my not have a spatial dimension.
392    
393        @param args: given objects
394        @return: the spatial dimension of the objects with identifiable dimension (see L{pokeDim}). If none the objects has
395                 a spatial dimension C{None} is returned.
396        @rtype: C{int} or C{None}
397        @raise ValueError: if the objects with identifiable dimension don't have the same spatial dimension.
398        """
399        out=None
400        for a in args:
401           d=pokeDim(a)
402           if not out==None:
403              if not (d==None or out==d):
404                 raise ValueError,"dimension of arguments don't match"
405           else:
406              out=d
407        return out
408    
409    def testForZero(arg):
410        """
411        test the argument for being identical to Zero
412    
413        @param arg: a given object
414        @type arg: typically L{numarray.NumArray},L{escript.Data},C{float}, C{int}
415        @return: True if the argument is identical to zero.
416        @rtype: C{bool}
417        """
418        if isinstance(arg,numarray.NumArray):
419           return not Lsup(arg)>0.
420        elif isinstance(arg,escript.Data):
421           return False
422        elif isinstance(arg,float):
423           return not Lsup(arg)>0.
424        elif isinstance(arg,int):
425           return not Lsup(arg)>0.
426        elif isinstance(arg,Symbol):
427           return False
428        else:
429           return False
430    
431    def matchType(arg0=0.,arg1=0.):
432        """
433        converting arg0 and arg1 both to the same type L{numarray.NumArray} or L{escript.Data} or, if one of arg0 or arg1 is of type L{Symbol}, the other one to be of type L{numarray.NumArray} or L{escript.Data}.
434    
435        @param arg0: first argument
436        @type arg0: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
437        @param arg1: second argument
438        @type arg1: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
439        @return: a tuple representing arg0 and arg1 with the same type or with one of them being a L{Symbol}
440        @rtype: C{tuple} of two L{numarray.NumArray}, two L{escript.Data}, a C{Symbol} and one of the types L{numarray.NumArray} or L{escript.Data}.  
441        @raise TypeError: if type of arg0 or arg1 cannot be processed
442        """
443        if isinstance(arg0,numarray.NumArray):
444           if isinstance(arg1,numarray.NumArray):
445              pass
446           elif isinstance(arg1,escript.Data):
447              arg0=escript.Data(arg0,arg1.getFunctionSpace())
448           elif isinstance(arg1,float):
449              arg1=numarray.array(arg1,type=numarray.Float64)
450           elif isinstance(arg1,int):
451              arg1=numarray.array(float(arg1),type=numarray.Float64)
452           elif isinstance(arg1,Symbol):
453              pass
454           else:
455              raise TypeError,"function: Unknown type of second argument."    
456        elif isinstance(arg0,escript.Data):
457           if isinstance(arg1,numarray.NumArray):
458              arg1=escript.Data(arg1,arg0.getFunctionSpace())
459           elif isinstance(arg1,escript.Data):
460              pass
461           elif isinstance(arg1,float):
462              arg1=escript.Data(arg1,(),arg0.getFunctionSpace())
463           elif isinstance(arg1,int):
464              arg1=escript.Data(float(arg1),(),arg0.getFunctionSpace())
465           elif isinstance(arg1,Symbol):
466              pass
467           else:
468              raise TypeError,"function: Unknown type of second argument."    
469        elif isinstance(arg0,Symbol):
470           if isinstance(arg1,numarray.NumArray):
471              pass
472           elif isinstance(arg1,escript.Data):
473              pass
474           elif isinstance(arg1,float):
475              arg1=numarray.array(arg1,type=numarray.Float64)
476           elif isinstance(arg1,int):
477              arg1=numarray.array(float(arg1),type=numarray.Float64)
478           elif isinstance(arg1,Symbol):
479              pass
480           else:
481              raise TypeError,"function: Unknown type of second argument."    
482        elif isinstance(arg0,float):
483           if isinstance(arg1,numarray.NumArray):
484              arg0=numarray.array(arg0,type=numarray.Float64)
485           elif isinstance(arg1,escript.Data):
486              arg0=escript.Data(arg0,arg1.getFunctionSpace())
487           elif isinstance(arg1,float):
488              arg0=numarray.array(arg0,type=numarray.Float64)
489              arg1=numarray.array(arg1,type=numarray.Float64)
490           elif isinstance(arg1,int):
491              arg0=numarray.array(arg0,type=numarray.Float64)
492              arg1=numarray.array(float(arg1),type=numarray.Float64)
493           elif isinstance(arg1,Symbol):
494              arg0=numarray.array(arg0,type=numarray.Float64)
495           else:
496              raise TypeError,"function: Unknown type of second argument."    
497        elif isinstance(arg0,int):
498           if isinstance(arg1,numarray.NumArray):
499              arg0=numarray.array(float(arg0),type=numarray.Float64)
500           elif isinstance(arg1,escript.Data):
501              arg0=escript.Data(float(arg0),arg1.getFunctionSpace())
502           elif isinstance(arg1,float):
503              arg0=numarray.array(float(arg0),type=numarray.Float64)
504              arg1=numarray.array(arg1,type=numarray.Float64)
505           elif isinstance(arg1,int):
506              arg0=numarray.array(float(arg0),type=numarray.Float64)
507              arg1=numarray.array(float(arg1),type=numarray.Float64)
508           elif isinstance(arg1,Symbol):
509              arg0=numarray.array(float(arg0),type=numarray.Float64)
510           else:
511              raise TypeError,"function: Unknown type of second argument."    
512        else:
513          raise TypeError,"function: Unknown type of first argument."    
514    
515        return arg0,arg1
516    
517    def matchShape(arg0,arg1):
518        """
519        return representations of arg0 amd arg1 which ahve the same shape
520    
521        @param arg0: a given object
522        @type arg0: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, L{Symbol}
523        @param arg1: a given object
524        @type arg1: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, L{Symbol}
525        @return: C{arg0} and C{arg1} where copies are returned when the shape has to be changed.
526        @rtype: C{tuple}
527        """
528        sh=commonShape(arg0,arg1)
529        sh0=getShape(arg0)
530        sh1=getShape(arg1)
531        if len(sh0)<len(sh):
532           return outer(arg0,numarray.ones(sh[len(sh0):],numarray.Float64)),arg1
533        elif len(sh1)<len(sh):
534           return arg0,outer(arg1,numarray.ones(sh[len(sh1):],numarray.Float64))
535        else:
536           return arg0,arg1
537    #=========================================================
538    #   symbolic tool box starts here:
539    #=========================================================
540    class Symbol(object):
541       """
542       Symbol class.
543    
544       Symbol class objects provide the same functionality as L{numarray.NumArray} and L{escript.Data} objects
545       but they do not have a value and therefore cannot be plotted or visualize. The main purpose is the possibilty
546       calculate derivatives with respect to other Symbols used to define a Symbol.
547    
548       """
549       def __init__(self,shape=(),args=[],dim=None):
550         """         """
551           Creates an instance of a symbol of a given shape. The symbol may depending on a list of arguments args which may be
552           symbols or any other object.
553    
554           @param args: the arguments of the symbol.
555           @type args: C{list}
556           @param shape: the shape
557           @type shape: C{tuple} of C{int}
558           @param dim: spatial dimension of the symbol. If dim=C{None} the spatial dimension is undefined.  
559           @type dim: C{None} or C{int}  
560    
561           """
562           if len(shape)>4:
563               raise ValueError,"Symbol supports only tensors up to order 4"
564         self.__args=args         self.__args=args
        self.__name=name  
565         self.__shape=shape         self.__shape=shape
566         if hasattr(dim,"getDim"):         self.__dim=dim
            self.__dim=dim.getDim()  
        else:      
            self.__dim=dim  
        #  
        self.__cache_val=None  
        self.__cache_argval=None  
567    
568     def getArgument(self,i):     def getArgument(self,i=None):
569         """         """
570         Returns the i-th argument.         returns the i-th argument of the symbol
        """  
        return self.__args[i]  
571    
572     def getDim(self):         @param i: index of the argument requested.
573           @type i: C{int} or C{None}
574           @raise IndexError: if the requested index does not exist
575           @return: the vlaue of the i-th argument or i is not specified the list of all arguments.
576           @rtype: a single object or a list of objects
577         """         """
578         Returns the spatial dimension of the symbol.         if i==None:
579         """            return self.__args
580         return self.__dim         else:
581              if i<0 or i>=len(self.__args):
582                 raise IndexError,"there are only %s arguments"%len(self.__args)
583              return self.__args[i]
584    
585     def getRank(self):     def getRank(self):
586         """         """
587         Returns the rank of the symbol.         the rank of the symbol
588    
589           @return: the rank of the symbol. This is length of the shape
590           @rtype: C{int}
591         """         """
592         return len(self.getShape())         return len(self.getShape())
593    
594     def getShape(self):     def getShape(self):
595         """         """
596         Returns the shape of the symbol.         the shape of the symbol.
597    
598           @return: the shape of the symbol.
599           @rtype: C{tuple} of C{int}
600         """         """
601         return self.__shape         return self.__shape
602    
603     def getEvaluatedArguments(self,argval):     def getDim(self):
604         """         """
605         Returns the list of evaluated arguments by subsituting symbol u by         the spatial dimension
606         argval[u].  
607           @return: the spatial dimension
608           @rtype: C{int} if the dimension is defined. Otherwise C{None} is returned.
609         """         """
610         if argval==self.__cache_argval:         return self.__dim
611             print "%s: cached value used"%self    
612             return self.__cache_val     def __str__(self):
613         else:         """
614             out=[]         a string representation of the symbol.
615             for a  in self.__args:         @return: a string representation of the object
616                if isinstance(a,Symbol):         @rtype: C{str}
617                  out.append(a.eval(argval))         """
618                else:         args=[]
619                  out.append(a)         for arg in self.getArgument():
620             self.__cache_argval=argval            args.append(str(arg))
621             self.__cache_val=out         try:
622             return out             out=self.getMyCode(args,format="str")
623           except NotImplementedError:
624               out="<Symbol %s>"%id(self)
625           return out
626          
627       def getSubstitutedArguments(self,argvals):
628           """
629           substitutes symbols in the arguments of this object and returns the result as a list.
630    
631           @param argvals: L{Symbol} and their substitutes. The L{Symbol} u in the expression defining this object is replaced by argvals[u].
632           @type argvals: C{dict} with keywords of type L{Symbol}.
633           @rtype: C{list} of objects
634           @return: list of the object assigned to the arguments through substitution or for the arguments which are not L{Symbol} the value assigned to the argument at instantiation.
635           """
636           out=[]
637           for a in self.getArgument():
638              if isinstance(a,Symbol):
639                 out.append(a.substitute(argvals))
640              else:
641                 out.append(a)
642           return out
643    
644     def getDifferentiatedArguments(self,arg):     def getDifferentiatedArguments(self,arg):
645         """         """
646         Returns the list of the arguments _differentiated by arg.         applifies differentials to the arguments of this object and returns the result as a list.
647         """  
648           @param arg: the derivative is calculated with respect to arg
649           @type arg: typically L{escript.Symbol} but can also be C{float}, L{escript.Data}, L{numarray.NumArray} depending the involved functions and data.
650           @rtype: C{list} of objects
651           @return: list of object obtained by calculating the derivatives of the argumenst with respct to arg
652           """
653         out=[]         out=[]
654         for a in self.__args:         for a in self.getArgument():
655            if isinstance(a,Symbol):            if isinstance(a,Symbol):
656              out.append(a.diff(arg))               out.append(a.substitute(argvals))
657            else:            else:
658              out.append(0)                s=getShape(s)+arg.getShape()
659                  if len(s)>0:
660                     out.append(numarray.zeros(s),numarray.Float64)
661                  else:
662                     out.append(a)
663         return out         return out
664    
665       def isAppropriateValue(self,arg):
666          """
667          checks if the given argument arg can be used as a substitution of this object. The method checks
668          the shape of arg and, if the spatial dimension is defined, the spatial dimension of arg.    
669    
670          @param arg: a given object
671          @type arg: L{numarray.NumArray},L{escript.Data},C{float}, C{int}, C{Symbol}
672          @return: True if arg is a suitbale object to be used for substitution. Otherwise False is returned.
673          @rtype: C{bool}
674          """
675          if isinstance(arg,numarray.NumArray):
676              return arg.shape==self.getShape()
677          elif isinstance(arg,escript.Data):
678              if self.getDim()==None:
679                  return arg.getShape()==self.getShape()
680              elif self.getDim()==arg.getFunctionSpace().getDim():
681                  return arg.getShape()==self.getShape()
682              else:
683                  return False
684          elif isinstance(arg,Symbol):
685              if self.getDim()==None:
686                  return arg.getShape()==self.getShape()
687              elif self.getDim()==arg.getDim():
688                  return arg.getShape()==self.getShape()
689              else:
690                  return False
691          elif isinstance(arg,float):
692              return ()==self.getShape()
693          elif isinstance(arg,int):
694              return ()==self.getShape()
695          else:
696             return False
697    
698       def getMyCode(self,argstrs,format="escript"):
699           """
700           returns a program code that can be used to evaluate the symbol.
701    
702           @param argstrs: gives for each argument a string representing the argument for the evaluation.
703           @type argstrs: C{list} of C{str}.
704           @param format: specifies the format to be used. At the moment only "escript", "str" and "text" are supported.
705           @type format: C{str}
706           @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
707           @rtype: C{str}
708           @raise NotImplementedError: if no implementation for the given format is available
709           @note: This method has to be overwritten by subclasses.
710           """
711           raise NotImplementedError,"no code for %s representation available"%format
712    
713       def substitute(self,argvals):
714          """  
715          assigns new values to symbols in the definition of the symbol.
716          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
717    
718          @param argvals: new values assigned to symbols
719          @type argvals: C{dict} with keywords of type L{Symbol}.
720          @return: result of the substitution process. Operations are executed as much as possible.
721          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
722          @note: this method has to be overwritten by a particular L{Symbol}
723          @raise NotImplementedError: if no implementation for the given format is available
724          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
725          """
726          if argvals.has_key(self):
727             arg=argvals[self]
728             if self.isAppropriateValue(arg):
729                return arg
730             else:
731                raise TypeError,"Symbol: new value is not appropriate."
732          else:
733             raise NotImplementedError,"no substitution in %s avialable"%str(self)
734    
735     def diff(self,arg):     def diff(self,arg):
736         """         """
737         Returns the _differention of self by arg.         returns the derivative of the symbol with respect to L{Symbol} arg
738    
739           @param arg: the derivative is calculated with respect to arg
740           @type arg: typically L{escript.Symbol} but can also be C{float}, L{escript.Data}, L{numarray.NumArray} depending the involved functions and data.
741           @return: derivative with respect to C{arg}
742           @rtype: typically L{escript.Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
743           @note: this method is overwritten by a particular L{Symbol}
744         """         """
745         if self==arg:         if arg==self:
746            out=numarray.zeros(tuple(2*list(self.getShape())),numarray.Float)            return identity(self.getShape())
           if self.getRank()==0:  
              out=1.  
           elif self.getRank()==1:  
               for i0 in range(self.getShape()[0]):  
                  out[i0,i0]=1.    
           elif self.getRank()==2:  
               for i0 in range(self.getShape()[0]):  
                 for i1 in range(self.getShape()[1]):  
                      out[i0,i1,i0,i1]=1.    
           elif self.getRank()==3:  
               for i0 in range(self.getShape()[0]):  
                 for i1 in range(self.getShape()[1]):  
                   for i2 in range(self.getShape()[2]):  
                      out[i0,i1,i2,i0,i1,i2]=1.    
           elif self.getRank()==4:  
               for i0 in range(self.getShape()[0]):  
                 for i1 in range(self.getShape()[1]):  
                   for i2 in range(self.getShape()[2]):  
                     for i3 in range(self.getShape()[3]):  
                        out[i0,i1,i2,i3,i0,i1,i2,i3]=1.    
           else:  
              raise ValueError,"differential support rank<5 only."  
           return out  
747         else:         else:
748            return self._diff(arg)            s=self.getShape()+arg.getShape()
749              if len(s)>0:
750                 return numarray.zeros(s,numarray.Float64)
751              else:
752                 return 0.
753    
754     def _diff(self,arg):     def __neg__(self):
755         """         """
756         Return derivate of self with respect to arg (!=self).         returns -self.
757    
758         This method is overwritten by a particular symbol.         @return:  a L{Symbol} representing the negative of the object
759           @rtype: L{DependendSymbol}
760         """         """
761         return 0         return self*(-1.)
762    
763     def eval(self,argval):     def __pos__(self):
764         """         """
765         Subsitutes symbol u in self by argval[u] and returns the result. If         returns +self.
766         self is not a key of argval then self is returned.  
767           @return:  a L{Symbol} representing the positive of the object
768           @rtype: L{DependendSymbol}
769         """         """
770         if argval.has_key(self):         return self*(1.)
          return argval[self]  
        else:  
          return self  
771    
772     def __str__(self):     def __abs__(self):
773         """         """
774         Returns a string representation of the symbol.         returns a L{Symbol} representing the absolute value of the object.
775         """         """
776         return self.__name         return Abs_Symbol(self)
777    
778     def __add__(self,other):     def __add__(self,other):
779         """         """
780         Adds other to symbol self. if _testForZero(other) self is returned.         add another object to this object
781    
782           @param other: object to be added to this object
783           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
784           @return:  a L{Symbol} representing the sum of this object and C{other}
785           @rtype: L{DependendSymbol}
786         """         """
787         if _testForZero(other):         return add(self,other)
           return self  
        else:  
           a=_matchShape([self,other])  
           return Add_Symbol(a[0],a[1])  
788    
789     def __radd__(self,other):     def __radd__(self,other):
790         """         """
791         Adds other to symbol self. if _testForZero(other) self is returned.         add this object to another object
        """  
        return self+other  
792    
793     def __neg__(self):         @param other: object this object is added to
794         """         @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
795         Returns -self.         @return: a L{Symbol} representing the sum of C{other} and this object object
796           @rtype: L{DependendSymbol}
797         """         """
798         return self*(-1.)         return add(other,self)
799    
800     def __pos__(self):     def __sub__(self,other):
801         """         """
802         Returns +self.         subtracts another object from this object
803    
804           @param other: object to be subtracted from this object
805           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
806           @return: a L{Symbol} representing the difference of C{other} and this object
807           @rtype: L{DependendSymbol}
808         """         """
809         return self         return add(self,-other)
810    
811     def __abs__(self):     def __rsub__(self,other):
812         """         """
813         Returns absolute value.         subtracts this object from another object
814    
815           @param other: object this object is been subtracted from
816           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
817           @return: a L{Symbol} representing the difference of this object and C{other}.
818           @rtype: L{DependendSymbol}
819         """         """
820         return Abs_Symbol(self)         return add(-self,other)
821    
822     def __sub__(self,other):     def __mul__(self,other):
823         """         """
824         Subtracts other from symbol self.         multiplies this object with other object
825          
826         If _testForZero(other) self is returned.         @param other: object to be mutiplied by this object
827           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
828           @return: a L{Symbol} representing the product of the object and C{other}.
829           @rtype: L{DependendSymbol} or 0 if other is identical to zero.
830         """         """
831         if _testForZero(other):         return mult(self,other)
           return self  
        else:  
           return self+(-other)  
832    
833     def __rsub__(self,other):     def __rmul__(self,other):
834         """         """
835         Subtracts symbol self from other.         multiplies this object with other object
836    
837           @param other: object this object is multiplied with
838           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
839           @return: a L{Symbol} representing the product of C{other} and the object.
840           @rtype: L{DependendSymbol} or 0 if other is identical to zero.
841         """         """
842         return -self+other         return mult(other,self)
843    
844     def __div__(self,other):     def __div__(self,other):
845         """         """
846         Divides symbol self by other.         divides this object by other object
847    
848           @param other: object dividing this object
849           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
850           @return: a L{Symbol} representing the quotient of this object and C{other}
851           @rtype: L{DependendSymbol}
852         """         """
853         if isinstance(other,Symbol):         return quotient(self,other)
           a=_matchShape([self,other])  
           return Div_Symbol(a[0],a[1])  
        else:  
           return self*(1./other)  
854    
855     def __rdiv__(self,other):     def __rdiv__(self,other):
856         """         """
857         Dived other by symbol self. if _testForZero(other) 0 is returned.         divides this object by other object
858    
859           @param other: object dividing this object
860           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
861           @return: a L{Symbol} representing the quotient of C{other} and this object
862           @rtype: L{DependendSymbol} or 0 if C{other} is identical to zero.
863         """         """
864         if _testForZero(other):         return quotient(other,self)
           return 0  
        else:  
           a=_matchShape([self,other])  
           return Div_Symbol(a[0],a[1])  
865    
866     def __pow__(self,other):     def __pow__(self,other):
867         """         """
868         Raises symbol self to the power of other.         raises this object to the power of other
869    
870           @param other: exponent
871           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
872           @return: a L{Symbol} representing the power of this object to C{other}
873           @rtype: L{DependendSymbol} or 1 if C{other} is identical to zero.
874         """         """
875         a=_matchShape([self,other])         return power(self,other)
        return Power_Symbol(a[0],a[1])  
876    
877     def __rpow__(self,other):     def __rpow__(self,other):
878         """         """
879         Raises other to the symbol self.         raises an object to the power of this object
        """  
        a=_matchShape([self,other])  
        return Power_Symbol(a[1],a[0])  
880    
881     def __mul__(self,other):         @param other: basis
882           @type other: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray}.
883           @return: a L{Symbol} representing the power of C{other} to this object
884           @rtype: L{DependendSymbol} or 0 if C{other} is identical to zero.
885         """         """
886         Multiplies other by symbol self. if _testForZero(other) 0 is returned.         return power(other,self)
        """  
        if _testForZero(other):  
           return 0  
        else:  
           a=_matchShape([self,other])  
           return Mult_Symbol(a[0],a[1])  
887    
888     def __rmul__(self,other):     def __getitem__(self,index):
889         """         """
890         Multiplies other by symbol self. if _testSForZero(other) 0 is returned.         returns the slice defined by index
891    
892           @param index: defines a
893           @type index: C{slice} or C{int} or a C{tuple} of them
894           @return: a L{Symbol} representing the slice defined by index
895           @rtype: L{DependendSymbol}
896         """         """
897         return self*other         return GetSlice_Symbol(self,index)
898    
899     def __getitem__(self,sl):  class DependendSymbol(Symbol):
900            print sl     """
901       DependendSymbol extents L{Symbol} by modifying the == operator to allow two instances to be equal.
902       Two DependendSymbol are equal if they have the same shape, the same arguments and one of them has an unspecified spatial dimension or the spatial dimension is identical  
903      
904       Example::
905      
906         u1=Symbol(shape=(3,4),dim=2,args=[4.])
907         u2=Symbol(shape=(3,4),dim=2,args=[4.])
908         print u1==u2
909         False
910      
911       but::
912    
913  class Float_Symbol(Symbol):       u1=DependendSymbol(shape=(3,4),dim=2,args=[4.])
914      def __init__(self,name="symbol",shape=(),args=[]):       u2=DependendSymbol(shape=(3,4),dim=2,args=[4.])
915          Symbol.__init__(self,dim=0,name="symbol",shape=(),args=[])       u3=DependendSymbol(shape=(2,),dim=2,args=[4.])  
916         print u1==u2, u1==u3
917         True False
918    
919  class ScalarSymbol(Symbol):     @note: DependendSymbol should be used as return value of functions with L{Symbol} arguments. This will allow the optimizer to remove redundant function calls.
    """  
    A scalar symbol.  
920     """     """
921     def __init__(self,dim=3,name="scalar"):     def __eq__(self,other):
922        """        """
923        Creates a scalar symbol of spatial dimension dim.        checks if other equals self
924    
925          @param other: any object
926          @return: True if other has the same class like self, and the shape, the spatial diemsnion and the arguments are equal.
927          @rtype: C{bool}
928        """        """
929        if hasattr(dim,"getDim"):        if isinstance(other,DependendSymbol):
930             d=dim.getDim()           if self.__class__==other.__class__:  
931        else:                  if self.getShape()==other.getShape():
932             d=dim                if self.getArgument()==other.getArgument():
933        Symbol.__init__(self,shape=(),dim=d,name=name)                   if self.getDim()==None or other.getDim()==None or self.getDim()==other.getDim():
934                        return True
935          return False
936    
937  class VectorSymbol(Symbol):     def __ne__(self,other):
938          """
939          checks if other equals self
940    
941          @param other: any object
942          @return: Flase if other has the same class like self, and the shape, the spatial diemsnion and the arguments are equal.
943          @rtype: C{bool}
944          """
945          return not self==other
946    #=========================================================
947    #  Unary operations prserving the shape
948    #========================================================
949    class GetSlice_Symbol(DependendSymbol):
950     """     """
951     A vector symbol.     L{Symbol} representing getting a slice for a L{Symbol}
952     """     """
953     def __init__(self,dim=3,name="vector"):     def __init__(self,arg,index):
954          """
955          initialization of wherePositive L{Symbol} with argument arg
956          @param arg: argument
957          @type arg: L{Symbol}.
958          @param index: defines index
959          @type index: C{slice} or C{int} or a C{tuple} of them
960          @raises IndexError: if length of index is larger than rank of arg or a index start or stop is out of range
961          @raises ValueError: if a step is given
962          """
963          if not isinstance(index,tuple): index=(index,)
964          if len(index)>arg.getRank():
965               raise IndexError,"GetSlice_Symbol: index out of range."
966          sh=()
967          index2=()
968          for i in range(len(index)):
969             ix=index[i]
970             if isinstance(ix,int):
971                if ix<0 or ix>=arg.getShape()[i]:
972                   raise ValueError,"GetSlice_Symbol: index out of range."
973                index2=index2+(ix,)
974             else:
975               if not ix.step==None:
976                 raise ValueError,"GetSlice_Symbol: steping is not supported."
977               if ix.start==None:
978                  s=0
979               else:
980                  s=ix.start
981               if ix.stop==None:
982                  e=arg.getShape()[i]
983               else:
984                  e=ix.stop
985                  if e>arg.getShape()[i]:
986                     raise IndexError,"GetSlice_Symbol: index out of range."
987               index2=index2+(slice(s,e),)
988               if e>s:
989                   sh=sh+(e-s,)
990               elif s>e:
991                   raise IndexError,"GetSlice_Symbol: slice start must be less or equal slice end"
992          for i in range(len(index),arg.getRank()):
993              index2=index2+(slice(0,arg.getShape()[i]),)
994              sh=sh+(arg.getShape()[i],)
995          super(GetSlice_Symbol, self).__init__(args=[arg,index2],shape=sh,dim=arg.getDim())
996    
997       def getMyCode(self,argstrs,format="escript"):
998          """
999          returns a program code that can be used to evaluate the symbol.
1000    
1001          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1002          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1003          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1004          @type format: C{str}
1005          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1006          @rtype: C{str}
1007          @raise NotImplementedError: if the requested format is not available
1008        """        """
1009        Creates a vector symbol of spatial dimension dim.        if format=="escript" or format=="str"  or format=="text":
1010             return "%s.__getitem__(%s)"%(argstrs[0],argstrs[1])
1011          else:
1012             raise NotImplementedError,"GetItem_Symbol does not provide program code for format %s."%format
1013    
1014       def substitute(self,argvals):
1015        """        """
1016        if hasattr(dim,"getDim"):        assigns new values to symbols in the definition of the symbol.
1017             d=dim.getDim()        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
       else:      
            d=dim  
       Symbol.__init__(self,shape=(d,),dim=d,name=name)  
1018    
1019  class TensorSymbol(Symbol):        @param argvals: new values assigned to symbols
1020          @type argvals: C{dict} with keywords of type L{Symbol}.
1021          @return: result of the substitution process. Operations are executed as much as possible.
1022          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1023          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1024          """
1025          if argvals.has_key(self):
1026             arg=argvals[self]
1027             if self.isAppropriateValue(arg):
1028                return arg
1029             else:
1030                raise TypeError,"%s: new value is not appropriate."%str(self)
1031          else:
1032             args=self.getSubstitutedArguments(argvals)
1033             arg=args[0]
1034             index=args[1]
1035             return arg.__getitem__(index)
1036    
1037    def log10(arg):
1038       """
1039       returns base-10 logarithm of argument arg
1040    
1041       @param arg: argument
1042       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1043       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1044       @raises TypeError: if the type of the argument is not expected.
1045       """
1046       if isinstance(arg,numarray.NumArray):
1047          return numarray.log10(arg)
1048       elif isinstance(arg,escript.Data):
1049          return arg._log10()
1050       elif isinstance(arg,float):
1051          return math.log10(arg)
1052       elif isinstance(arg,int):
1053          return math.log10(float(arg))
1054       elif isinstance(arg,Symbol):
1055          return log(arg)/log(10.)
1056       else:
1057          raise TypeError,"log10: Unknown argument type."
1058    
1059    def wherePositive(arg):
1060     """     """
1061     A tensor symbol.     returns mask of positive values of argument arg
1062     """  
1063     def __init__(self,dim=3,name="tensor"):     @param arg: argument
1064       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1065       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1066       @raises TypeError: if the type of the argument is not expected.
1067       """
1068       if isinstance(arg,numarray.NumArray):
1069          out=numarray.greater(arg,numarray.zeros(arg.shape,numarray.Float64))*1.
1070          if isinstance(out,float): out=numarray.array(out,type=numarray.Float64)
1071          return out
1072       elif isinstance(arg,escript.Data):
1073          return arg._wherePositive()
1074       elif isinstance(arg,float):
1075          if arg>0:
1076            return 1.
1077          else:
1078            return 0.
1079       elif isinstance(arg,int):
1080          if arg>0:
1081            return 1.
1082          else:
1083            return 0.
1084       elif isinstance(arg,Symbol):
1085          return WherePositive_Symbol(arg)
1086       else:
1087          raise TypeError,"wherePositive: Unknown argument type."
1088    
1089    class WherePositive_Symbol(DependendSymbol):
1090       """
1091       L{Symbol} representing the result of the mask of positive values function
1092       """
1093       def __init__(self,arg):
1094        """        """
1095        Creates a tensor symbol of spatial dimension dim.        initialization of wherePositive L{Symbol} with argument arg
1096          @param arg: argument of function
1097          @type arg: typically L{Symbol}.
1098          """
1099          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1100    
1101       def getMyCode(self,argstrs,format="escript"):
1102        """        """
1103        if hasattr(dim,"getDim"):        returns a program code that can be used to evaluate the symbol.
            d=dim.getDim()  
       else:      
            d=dim  
       Symbol.__init__(self,shape=(d,d),dim=d,name=name)  
1104    
1105  class Tensor3Symbol(Symbol):        @param argstrs: gives for each argument a string representing the argument for the evaluation.
1106          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1107          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1108          @type format: C{str}
1109          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1110          @rtype: C{str}
1111          @raise NotImplementedError: if the requested format is not available
1112          """
1113          if isinstance(argstrs,list):
1114              argstrs=argstrs[0]
1115          if format=="escript" or format=="str"  or format=="text":
1116             return "wherePositive(%s)"%argstrs
1117          else:
1118             raise NotImplementedError,"WherePositive_Symbol does not provide program code for format %s."%format
1119    
1120       def substitute(self,argvals):
1121          """
1122          assigns new values to symbols in the definition of the symbol.
1123          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1124    
1125          @param argvals: new values assigned to symbols
1126          @type argvals: C{dict} with keywords of type L{Symbol}.
1127          @return: result of the substitution process. Operations are executed as much as possible.
1128          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1129          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1130          """
1131          if argvals.has_key(self):
1132             arg=argvals[self]
1133             if self.isAppropriateValue(arg):
1134                return arg
1135             else:
1136                raise TypeError,"%s: new value is not appropriate."%str(self)
1137          else:
1138             arg=self.getSubstitutedArguments(argvals)[0]
1139             return wherePositive(arg)
1140    
1141    def whereNegative(arg):
1142       """
1143       returns mask of positive values of argument arg
1144    
1145       @param arg: argument
1146       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1147       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1148       @raises TypeError: if the type of the argument is not expected.
1149       """
1150       if isinstance(arg,numarray.NumArray):
1151          out=numarray.less(arg,numarray.zeros(arg.shape,numarray.Float64))*1.
1152          if isinstance(out,float): out=numarray.array(out,type=numarray.Float64)
1153          return out
1154       elif isinstance(arg,escript.Data):
1155          return arg._whereNegative()
1156       elif isinstance(arg,float):
1157          if arg<0:
1158            return 1.
1159          else:
1160            return 0.
1161       elif isinstance(arg,int):
1162          if arg<0:
1163            return 1.
1164          else:
1165            return 0.
1166       elif isinstance(arg,Symbol):
1167          return WhereNegative_Symbol(arg)
1168       else:
1169          raise TypeError,"whereNegative: Unknown argument type."
1170    
1171    class WhereNegative_Symbol(DependendSymbol):
1172     """     """
1173     A tensor order 3 symbol.     L{Symbol} representing the result of the mask of positive values function
1174     """     """
1175     def __init__(self,dim=3,name="tensor3"):     def __init__(self,arg):
1176          """
1177          initialization of whereNegative L{Symbol} with argument arg
1178          @param arg: argument of function
1179          @type arg: typically L{Symbol}.
1180          """
1181          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1182    
1183       def getMyCode(self,argstrs,format="escript"):
1184          """
1185          returns a program code that can be used to evaluate the symbol.
1186    
1187          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1188          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1189          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1190          @type format: C{str}
1191          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1192          @rtype: C{str}
1193          @raise NotImplementedError: if the requested format is not available
1194        """        """
1195        Creates a tensor order 3 symbol of spatial dimension dim.        if isinstance(argstrs,list):
1196              argstrs=argstrs[0]
1197          if format=="escript" or format=="str"  or format=="text":
1198             return "whereNegative(%s)"%argstrs
1199          else:
1200             raise NotImplementedError,"WhereNegative_Symbol does not provide program code for format %s."%format
1201    
1202       def substitute(self,argvals):
1203        """        """
1204        if hasattr(dim,"getDim"):        assigns new values to symbols in the definition of the symbol.
1205             d=dim.getDim()        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
       else:      
            d=dim  
       Symbol.__init__(self,shape=(d,d,d),dim=d,name=name)  
1206    
1207  class Tensor4Symbol(Symbol):        @param argvals: new values assigned to symbols
1208          @type argvals: C{dict} with keywords of type L{Symbol}.
1209          @return: result of the substitution process. Operations are executed as much as possible.
1210          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1211          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1212          """
1213          if argvals.has_key(self):
1214             arg=argvals[self]
1215             if self.isAppropriateValue(arg):
1216                return arg
1217             else:
1218                raise TypeError,"%s: new value is not appropriate."%str(self)
1219          else:
1220             arg=self.getSubstitutedArguments(argvals)[0]
1221             return whereNegative(arg)
1222    
1223    def whereNonNegative(arg):
1224     """     """
1225     A tensor order 4 symbol.     returns mask of non-negative values of argument arg
1226    
1227       @param arg: argument
1228       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1229       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1230       @raises TypeError: if the type of the argument is not expected.
1231       """
1232       if isinstance(arg,numarray.NumArray):
1233          out=numarray.greater_equal(arg,numarray.zeros(arg.shape,numarray.Float64))*1.
1234          if isinstance(out,float): out=numarray.array(out,type=numarray.Float64)
1235          return out
1236       elif isinstance(arg,escript.Data):
1237          return arg._whereNonNegative()
1238       elif isinstance(arg,float):
1239          if arg<0:
1240            return 0.
1241          else:
1242            return 1.
1243       elif isinstance(arg,int):
1244          if arg<0:
1245            return 0.
1246          else:
1247            return 1.
1248       elif isinstance(arg,Symbol):
1249          return 1.-whereNegative(arg)
1250       else:
1251          raise TypeError,"whereNonNegative: Unknown argument type."
1252    
1253    def whereNonPositive(arg):
1254     """     """
1255     def __init__(self,dim=3,name="tensor4"):     returns mask of non-positive values of argument arg
1256    
1257       @param arg: argument
1258       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1259       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1260       @raises TypeError: if the type of the argument is not expected.
1261       """
1262       if isinstance(arg,numarray.NumArray):
1263          out=numarray.less_equal(arg,numarray.zeros(arg.shape,numarray.Float64))*1.
1264          if isinstance(out,float): out=numarray.array(out,type=numarray.Float64)
1265          return out
1266       elif isinstance(arg,escript.Data):
1267          return arg._whereNonPositive()
1268       elif isinstance(arg,float):
1269          if arg>0:
1270            return 0.
1271          else:
1272            return 1.
1273       elif isinstance(arg,int):
1274          if arg>0:
1275            return 0.
1276          else:
1277            return 1.
1278       elif isinstance(arg,Symbol):
1279          return 1.-wherePositive(arg)
1280       else:
1281          raise TypeError,"whereNonPositive: Unknown argument type."
1282    
1283    def whereZero(arg,tol=0.):
1284       """
1285       returns mask of zero entries of argument arg
1286    
1287       @param arg: argument
1288       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1289       @param tol: tolerance. values with absolute value less then tol are accepted as zero.
1290       @type tol: C{float}
1291       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1292       @raises TypeError: if the type of the argument is not expected.
1293       """
1294       if isinstance(arg,numarray.NumArray):
1295          out=numarray.less_equal(abs(arg)-tol,numarray.zeros(arg.shape,numarray.Float64))*1.
1296          if isinstance(out,float): out=numarray.array(out,type=numarray.Float64)
1297          return out
1298       elif isinstance(arg,escript.Data):
1299          return arg._whereZero(tol)
1300       elif isinstance(arg,float):
1301          if abs(arg)<=tol:
1302            return 1.
1303          else:
1304            return 0.
1305       elif isinstance(arg,int):
1306          if abs(float(arg))<=tol:
1307            return 1.
1308          else:
1309            return 0.
1310       elif isinstance(arg,Symbol):
1311          return WhereZero_Symbol(arg,tol)
1312       else:
1313          raise TypeError,"whereZero: Unknown argument type."
1314    
1315    class WhereZero_Symbol(DependendSymbol):
1316       """
1317       L{Symbol} representing the result of the mask of zero entries function
1318       """
1319       def __init__(self,arg,tol=0.):
1320        """        """
1321        Creates a tensor order 4 symbol of spatial dimension dim.        initialization of whereZero L{Symbol} with argument arg
1322        """        @param arg: argument of function
1323        if hasattr(dim,"getDim"):        @type arg: typically L{Symbol}.
1324             d=dim.getDim()        """
1325        else:            DependendSymbol.__init__(self,args=[arg,tol],shape=arg.getShape(),dim=arg.getDim())
1326             d=dim  
1327        Symbol.__init__(self,shape=(d,d,d,d),dim=d,name=name)     def getMyCode(self,argstrs,format="escript"):
1328          """
1329          returns a program code that can be used to evaluate the symbol.
1330    
1331  class Add_Symbol(Symbol):        @param argstrs: gives for each argument a string representing the argument for the evaluation.
1332          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1333          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1334          @type format: C{str}
1335          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1336          @rtype: C{str}
1337          @raise NotImplementedError: if the requested format is not available
1338          """
1339          if format=="escript" or format=="str"  or format=="text":
1340             return "whereZero(%s,tol=%s)"%(argstrs[0],argstrs[1])
1341          else:
1342             raise NotImplementedError,"WhereZero_Symbol does not provide program code for format %s."%format
1343    
1344       def substitute(self,argvals):
1345          """
1346          assigns new values to symbols in the definition of the symbol.
1347          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1348    
1349          @param argvals: new values assigned to symbols
1350          @type argvals: C{dict} with keywords of type L{Symbol}.
1351          @return: result of the substitution process. Operations are executed as much as possible.
1352          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1353          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1354          """
1355          if argvals.has_key(self):
1356             arg=argvals[self]
1357             if self.isAppropriateValue(arg):
1358                return arg
1359             else:
1360                raise TypeError,"%s: new value is not appropriate."%str(self)
1361          else:
1362             arg=self.getSubstitutedArguments(argvals)
1363             return whereZero(arg[0],arg[1])
1364    
1365    def whereNonZero(arg,tol=0.):
1366     """     """
1367     Symbol representing the sum of two arguments.     returns mask of values different from zero of argument arg
1368    
1369       @param arg: argument
1370       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1371       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1372       @raises TypeError: if the type of the argument is not expected.
1373       """
1374       if isinstance(arg,numarray.NumArray):
1375          out=numarray.greater(abs(arg)-tol,numarray.zeros(arg.shape,numarray.Float64))*1.
1376          if isinstance(out,float): out=numarray.array(out,type=numarray.Float64)
1377          return out
1378       elif isinstance(arg,escript.Data):
1379          return arg._whereNonZero(tol)
1380       elif isinstance(arg,float):
1381          if abs(arg)>tol:
1382            return 1.
1383          else:
1384            return 0.
1385       elif isinstance(arg,int):
1386          if abs(float(arg))>tol:
1387            return 1.
1388          else:
1389            return 0.
1390       elif isinstance(arg,Symbol):
1391          return 1.-whereZero(arg,tol)
1392       else:
1393          raise TypeError,"whereNonZero: Unknown argument type."
1394    
1395    def erf(arg):
1396     """     """
1397     def __init__(self,arg0,arg1):     returns erf of argument arg
        a=[arg0,arg1]  
        Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)  
    def __str__(self):  
       return "(%s+%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))  
    def eval(self,argval):  
        a=self.getEvaluatedArguments(argval)  
        return a[0]+a[1]  
    def _diff(self,arg):  
        a=self.getDifferentiatedArguments(arg)  
        return a[0]+a[1]  
1398    
1399  class Mult_Symbol(Symbol):     @param arg: argument
1400       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1401       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1402       @raises TypeError: if the type of the argument is not expected.
1403     """     """
1404     Symbol representing the product of two arguments.     if isinstance(arg,escript.Data):
1405          return arg._erf()
1406       else:
1407          raise TypeError,"erf: Unknown argument type."
1408    
1409    def sin(arg):
1410     """     """
1411     def __init__(self,arg0,arg1):     returns sine of argument arg
1412         a=[arg0,arg1]  
1413         Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)     @param arg: argument
1414     def __str__(self):     @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1415        return "(%s*%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))     @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1416     def eval(self,argval):     @raises TypeError: if the type of the argument is not expected.
1417         a=self.getEvaluatedArguments(argval)     """
1418         return a[0]*a[1]     if isinstance(arg,numarray.NumArray):
1419     def _diff(self,arg):        return numarray.sin(arg)
1420         a=self.getDifferentiatedArguments(arg)     elif isinstance(arg,escript.Data):
1421         return self.getArgument(1)*a[0]+self.getArgument(0)*a[1]        return arg._sin()
1422       elif isinstance(arg,float):
1423          return math.sin(arg)
1424       elif isinstance(arg,int):
1425          return math.sin(arg)
1426       elif isinstance(arg,Symbol):
1427          return Sin_Symbol(arg)
1428       else:
1429          raise TypeError,"sin: Unknown argument type."
1430    
1431  class Div_Symbol(Symbol):  class Sin_Symbol(DependendSymbol):
1432     """     """
1433     Symbol representing the quotient of two arguments.     L{Symbol} representing the result of the sine function
1434     """     """
1435     def __init__(self,arg0,arg1):     def __init__(self,arg):
1436         a=[arg0,arg1]        """
1437         Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)        initialization of sin L{Symbol} with argument arg
1438     def __str__(self):        @param arg: argument of function
1439        return "(%s/%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))        @type arg: typically L{Symbol}.
1440     def eval(self,argval):        """
1441         a=self.getEvaluatedArguments(argval)        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1442         return a[0]/a[1]  
1443     def _diff(self,arg):     def getMyCode(self,argstrs,format="escript"):
1444         a=self.getDifferentiatedArguments(arg)        """
1445         return (a[0]*self.getArgument(1)-self.getArgument(0)*a[1])/ \        returns a program code that can be used to evaluate the symbol.
1446                            (self.getArgument(1)*self.getArgument(1))  
1447          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1448          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1449          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1450          @type format: C{str}
1451          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1452          @rtype: C{str}
1453          @raise NotImplementedError: if the requested format is not available
1454          """
1455          if isinstance(argstrs,list):
1456              argstrs=argstrs[0]
1457          if format=="escript" or format=="str"  or format=="text":
1458             return "sin(%s)"%argstrs
1459          else:
1460             raise NotImplementedError,"Sin_Symbol does not provide program code for format %s."%format
1461    
1462       def substitute(self,argvals):
1463          """
1464          assigns new values to symbols in the definition of the symbol.
1465          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1466    
1467          @param argvals: new values assigned to symbols
1468          @type argvals: C{dict} with keywords of type L{Symbol}.
1469          @return: result of the substitution process. Operations are executed as much as possible.
1470          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1471          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1472          """
1473          if argvals.has_key(self):
1474             arg=argvals[self]
1475             if self.isAppropriateValue(arg):
1476                return arg
1477             else:
1478                raise TypeError,"%s: new value is not appropriate."%str(self)
1479          else:
1480             arg=self.getSubstitutedArguments(argvals)[0]
1481             return sin(arg)
1482    
1483       def diff(self,arg):
1484          """
1485          differential of this object
1486    
1487  class Power_Symbol(Symbol):        @param arg: the derivative is calculated with respect to arg
1488          @type arg: L{escript.Symbol}
1489          @return: derivative with respect to C{arg}
1490          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1491          """
1492          if arg==self:
1493             return identity(self.getShape())
1494          else:
1495             myarg=self.getArgument()[0]
1496             val=matchShape(cos(myarg),self.getDifferentiatedArguments(arg)[0])
1497             return val[0]*val[1]
1498    
1499    def cos(arg):
1500     """     """
1501     Symbol representing the power of the first argument to the power of the     returns cosine of argument arg
1502     second argument.  
1503       @param arg: argument
1504       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1505       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1506       @raises TypeError: if the type of the argument is not expected.
1507       """
1508       if isinstance(arg,numarray.NumArray):
1509          return numarray.cos(arg)
1510       elif isinstance(arg,escript.Data):
1511          return arg._cos()
1512       elif isinstance(arg,float):
1513          return math.cos(arg)
1514       elif isinstance(arg,int):
1515          return math.cos(arg)
1516       elif isinstance(arg,Symbol):
1517          return Cos_Symbol(arg)
1518       else:
1519          raise TypeError,"cos: Unknown argument type."
1520    
1521    class Cos_Symbol(DependendSymbol):
1522     """     """
1523     def __init__(self,arg0,arg1):     L{Symbol} representing the result of the cosine function
1524         a=[arg0,arg1]     """
1525         Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)     def __init__(self,arg):
1526     def __str__(self):        """
1527        return "(%s**%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))        initialization of cos L{Symbol} with argument arg
1528     def eval(self,argval):        @param arg: argument of function
1529         a=self.getEvaluatedArguments(argval)        @type arg: typically L{Symbol}.
1530         return a[0]**a[1]        """
1531     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1532         a=self.getDifferentiatedArguments(arg)  
1533         return self*(a[1]*log(self.getArgument(0))+self.getArgument(1)/self.getArgument(0)*a[0])     def getMyCode(self,argstrs,format="escript"):
1534          """
1535          returns a program code that can be used to evaluate the symbol.
1536    
1537          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1538          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1539          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1540          @type format: C{str}
1541          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1542          @rtype: C{str}
1543          @raise NotImplementedError: if the requested format is not available
1544          """
1545          if isinstance(argstrs,list):
1546              argstrs=argstrs[0]
1547          if format=="escript" or format=="str"  or format=="text":
1548             return "cos(%s)"%argstrs
1549          else:
1550             raise NotImplementedError,"Cos_Symbol does not provide program code for format %s."%format
1551    
1552       def substitute(self,argvals):
1553          """
1554          assigns new values to symbols in the definition of the symbol.
1555          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1556    
1557          @param argvals: new values assigned to symbols
1558          @type argvals: C{dict} with keywords of type L{Symbol}.
1559          @return: result of the substitution process. Operations are executed as much as possible.
1560          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1561          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1562          """
1563          if argvals.has_key(self):
1564             arg=argvals[self]
1565             if self.isAppropriateValue(arg):
1566                return arg
1567             else:
1568                raise TypeError,"%s: new value is not appropriate."%str(self)
1569          else:
1570             arg=self.getSubstitutedArguments(argvals)[0]
1571             return cos(arg)
1572    
1573  class Abs_Symbol(Symbol):     def diff(self,arg):
1574          """
1575          differential of this object
1576    
1577          @param arg: the derivative is calculated with respect to arg
1578          @type arg: L{escript.Symbol}
1579          @return: derivative with respect to C{arg}
1580          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1581          """
1582          if arg==self:
1583             return identity(self.getShape())
1584          else:
1585             myarg=self.getArgument()[0]
1586             val=matchShape(-sin(myarg),self.getDifferentiatedArguments(arg)[0])
1587             return val[0]*val[1]
1588    
1589    def tan(arg):
1590       """
1591       returns tangent of argument arg
1592    
1593       @param arg: argument
1594       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1595       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1596       @raises TypeError: if the type of the argument is not expected.
1597       """
1598       if isinstance(arg,numarray.NumArray):
1599          return numarray.tan(arg)
1600       elif isinstance(arg,escript.Data):
1601          return arg._tan()
1602       elif isinstance(arg,float):
1603          return math.tan(arg)
1604       elif isinstance(arg,int):
1605          return math.tan(arg)
1606       elif isinstance(arg,Symbol):
1607          return Tan_Symbol(arg)
1608       else:
1609          raise TypeError,"tan: Unknown argument type."
1610    
1611    class Tan_Symbol(DependendSymbol):
1612     """     """
1613     Symbol representing absolute value of its argument.     L{Symbol} representing the result of the tangent function
1614     """     """
1615     def __init__(self,arg):     def __init__(self,arg):
1616         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1617     def __str__(self):        initialization of tan L{Symbol} with argument arg
1618        return "abs(%s)"%str(self.getArgument(0))        @param arg: argument of function
1619     def eval(self,argval):        @type arg: typically L{Symbol}.
1620         return abs(self.getEvaluatedArguments(argval)[0])        """
1621     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
        return sign(self.getArgument(0))*self.getDifferentiatedArguments(arg)[0]  
1622    
1623  #=========================================================     def getMyCode(self,argstrs,format="escript"):
1624  #   some little helpers        """
1625  #=========================================================        returns a program code that can be used to evaluate the symbol.
1626  def _testForZero(arg):  
1627          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1628          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1629          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1630          @type format: C{str}
1631          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1632          @rtype: C{str}
1633          @raise NotImplementedError: if the requested format is not available
1634          """
1635          if isinstance(argstrs,list):
1636              argstrs=argstrs[0]
1637          if format=="escript" or format=="str"  or format=="text":
1638             return "tan(%s)"%argstrs
1639          else:
1640             raise NotImplementedError,"Tan_Symbol does not provide program code for format %s."%format
1641    
1642       def substitute(self,argvals):
1643          """
1644          assigns new values to symbols in the definition of the symbol.
1645          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1646    
1647          @param argvals: new values assigned to symbols
1648          @type argvals: C{dict} with keywords of type L{Symbol}.
1649          @return: result of the substitution process. Operations are executed as much as possible.
1650          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1651          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1652          """
1653          if argvals.has_key(self):
1654             arg=argvals[self]
1655             if self.isAppropriateValue(arg):
1656                return arg
1657             else:
1658                raise TypeError,"%s: new value is not appropriate."%str(self)
1659          else:
1660             arg=self.getSubstitutedArguments(argvals)[0]
1661             return tan(arg)
1662    
1663       def diff(self,arg):
1664          """
1665          differential of this object
1666    
1667          @param arg: the derivative is calculated with respect to arg
1668          @type arg: L{escript.Symbol}
1669          @return: derivative with respect to C{arg}
1670          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1671          """
1672          if arg==self:
1673             return identity(self.getShape())
1674          else:
1675             myarg=self.getArgument()[0]
1676             val=matchShape(1./cos(myarg)**2,self.getDifferentiatedArguments(arg)[0])
1677             return val[0]*val[1]
1678    
1679    def asin(arg):
1680       """
1681       returns inverse sine of argument arg
1682    
1683       @param arg: argument
1684       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1685       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1686       @raises TypeError: if the type of the argument is not expected.
1687       """
1688       if isinstance(arg,numarray.NumArray):
1689          return numarray.arcsin(arg)
1690       elif isinstance(arg,escript.Data):
1691          return arg._asin()
1692       elif isinstance(arg,float):
1693          return math.asin(arg)
1694       elif isinstance(arg,int):
1695          return math.asin(arg)
1696       elif isinstance(arg,Symbol):
1697          return Asin_Symbol(arg)
1698       else:
1699          raise TypeError,"asin: Unknown argument type."
1700    
1701    class Asin_Symbol(DependendSymbol):
1702     """     """
1703     Returns True is arg is considered to be zero.     L{Symbol} representing the result of the inverse sine function
1704     """     """
1705     if isinstance(arg,int):     def __init__(self,arg):
1706        return not arg>0        """
1707          initialization of asin L{Symbol} with argument arg
1708          @param arg: argument of function
1709          @type arg: typically L{Symbol}.
1710          """
1711          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1712    
1713       def getMyCode(self,argstrs,format="escript"):
1714          """
1715          returns a program code that can be used to evaluate the symbol.
1716    
1717          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1718          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1719          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1720          @type format: C{str}
1721          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1722          @rtype: C{str}
1723          @raise NotImplementedError: if the requested format is not available
1724          """
1725          if isinstance(argstrs,list):
1726              argstrs=argstrs[0]
1727          if format=="escript" or format=="str"  or format=="text":
1728             return "asin(%s)"%argstrs
1729          else:
1730             raise NotImplementedError,"Asin_Symbol does not provide program code for format %s."%format
1731    
1732       def substitute(self,argvals):
1733          """
1734          assigns new values to symbols in the definition of the symbol.
1735          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1736    
1737          @param argvals: new values assigned to symbols
1738          @type argvals: C{dict} with keywords of type L{Symbol}.
1739          @return: result of the substitution process. Operations are executed as much as possible.
1740          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1741          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1742          """
1743          if argvals.has_key(self):
1744             arg=argvals[self]
1745             if self.isAppropriateValue(arg):
1746                return arg
1747             else:
1748                raise TypeError,"%s: new value is not appropriate."%str(self)
1749          else:
1750             arg=self.getSubstitutedArguments(argvals)[0]
1751             return asin(arg)
1752    
1753       def diff(self,arg):
1754          """
1755          differential of this object
1756    
1757          @param arg: the derivative is calculated with respect to arg
1758          @type arg: L{escript.Symbol}
1759          @return: derivative with respect to C{arg}
1760          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1761          """
1762          if arg==self:
1763             return identity(self.getShape())
1764          else:
1765             myarg=self.getArgument()[0]
1766             val=matchShape(1./sqrt(1.-myarg**2),self.getDifferentiatedArguments(arg)[0])
1767             return val[0]*val[1]
1768    
1769    def acos(arg):
1770       """
1771       returns inverse cosine of argument arg
1772    
1773       @param arg: argument
1774       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1775       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1776       @raises TypeError: if the type of the argument is not expected.
1777       """
1778       if isinstance(arg,numarray.NumArray):
1779          return numarray.arccos(arg)
1780       elif isinstance(arg,escript.Data):
1781          return arg._acos()
1782     elif isinstance(arg,float):     elif isinstance(arg,float):
1783        return not arg>0.        return math.acos(arg)
1784     elif isinstance(arg,numarray.NumArray):     elif isinstance(arg,int):
1785        a=abs(arg)        return math.acos(arg)
1786        while isinstance(a,numarray.NumArray): a=numarray.sometrue(a)     elif isinstance(arg,Symbol):
1787        return not a>0        return Acos_Symbol(arg)
1788     else:     else:
1789        return False        raise TypeError,"acos: Unknown argument type."
1790    
1791  def _extractDim(args):  class Acos_Symbol(DependendSymbol):
1792      dim=None     """
1793      for a in args:     L{Symbol} representing the result of the inverse cosine function
1794         if hasattr(a,"getDim"):     """
1795            d=a.getDim()     def __init__(self,arg):
1796            if dim==None:        """
1797               dim=d        initialization of acos L{Symbol} with argument arg
1798            else:        @param arg: argument of function
1799               if dim!=d: raise ValueError,"inconsistent spatial dimension of arguments"        @type arg: typically L{Symbol}.
1800      if dim==None:        """
1801         raise ValueError,"cannot recover spatial dimension"        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1802      return dim  
1803       def getMyCode(self,argstrs,format="escript"):
1804          """
1805          returns a program code that can be used to evaluate the symbol.
1806    
1807  def _identifyShape(arg):        @param argstrs: gives for each argument a string representing the argument for the evaluation.
1808          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1809          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1810          @type format: C{str}
1811          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1812          @rtype: C{str}
1813          @raise NotImplementedError: if the requested format is not available
1814          """
1815          if isinstance(argstrs,list):
1816              argstrs=argstrs[0]
1817          if format=="escript" or format=="str"  or format=="text":
1818             return "acos(%s)"%argstrs
1819          else:
1820             raise NotImplementedError,"Acos_Symbol does not provide program code for format %s."%format
1821    
1822       def substitute(self,argvals):
1823          """
1824          assigns new values to symbols in the definition of the symbol.
1825          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1826    
1827          @param argvals: new values assigned to symbols
1828          @type argvals: C{dict} with keywords of type L{Symbol}.
1829          @return: result of the substitution process. Operations are executed as much as possible.
1830          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1831          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1832          """
1833          if argvals.has_key(self):
1834             arg=argvals[self]
1835             if self.isAppropriateValue(arg):
1836                return arg
1837             else:
1838                raise TypeError,"%s: new value is not appropriate."%str(self)
1839          else:
1840             arg=self.getSubstitutedArguments(argvals)[0]
1841             return acos(arg)
1842    
1843       def diff(self,arg):
1844          """
1845          differential of this object
1846    
1847          @param arg: the derivative is calculated with respect to arg
1848          @type arg: L{escript.Symbol}
1849          @return: derivative with respect to C{arg}
1850          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1851          """
1852          if arg==self:
1853             return identity(self.getShape())
1854          else:
1855             myarg=self.getArgument()[0]
1856             val=matchShape(-1./sqrt(1.-myarg**2),self.getDifferentiatedArguments(arg)[0])
1857             return val[0]*val[1]
1858    
1859    def atan(arg):
1860       """
1861       returns inverse tangent of argument arg
1862    
1863       @param arg: argument
1864       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1865       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1866       @raises TypeError: if the type of the argument is not expected.
1867       """
1868       if isinstance(arg,numarray.NumArray):
1869          return numarray.arctan(arg)
1870       elif isinstance(arg,escript.Data):
1871          return arg._atan()
1872       elif isinstance(arg,float):
1873          return math.atan(arg)
1874       elif isinstance(arg,int):
1875          return math.atan(arg)
1876       elif isinstance(arg,Symbol):
1877          return Atan_Symbol(arg)
1878       else:
1879          raise TypeError,"atan: Unknown argument type."
1880    
1881    class Atan_Symbol(DependendSymbol):
1882     """     """
1883     Identifies the shape of arg.     L{Symbol} representing the result of the inverse tangent function
1884     """     """
1885     if hasattr(arg,"getShape"):     def __init__(self,arg):
1886         arg_shape=arg.getShape()        """
1887     elif hasattr(arg,"shape"):        initialization of atan L{Symbol} with argument arg
1888       s=arg.shape        @param arg: argument of function
1889       if callable(s):        @type arg: typically L{Symbol}.
1890         arg_shape=s()        """
1891       else:        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1892         arg_shape=s  
1893       def getMyCode(self,argstrs,format="escript"):
1894          """
1895          returns a program code that can be used to evaluate the symbol.
1896    
1897          @param argstrs: gives for each argument a string representing the argument for the evaluation.
1898          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1899          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1900          @type format: C{str}
1901          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1902          @rtype: C{str}
1903          @raise NotImplementedError: if the requested format is not available
1904          """
1905          if isinstance(argstrs,list):
1906              argstrs=argstrs[0]
1907          if format=="escript" or format=="str"  or format=="text":
1908             return "atan(%s)"%argstrs
1909          else:
1910             raise NotImplementedError,"Atan_Symbol does not provide program code for format %s."%format
1911    
1912       def substitute(self,argvals):
1913          """
1914          assigns new values to symbols in the definition of the symbol.
1915          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
1916    
1917          @param argvals: new values assigned to symbols
1918          @type argvals: C{dict} with keywords of type L{Symbol}.
1919          @return: result of the substitution process. Operations are executed as much as possible.
1920          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
1921          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
1922          """
1923          if argvals.has_key(self):
1924             arg=argvals[self]
1925             if self.isAppropriateValue(arg):
1926                return arg
1927             else:
1928                raise TypeError,"%s: new value is not appropriate."%str(self)
1929          else:
1930             arg=self.getSubstitutedArguments(argvals)[0]
1931             return atan(arg)
1932    
1933       def diff(self,arg):
1934          """
1935          differential of this object
1936    
1937          @param arg: the derivative is calculated with respect to arg
1938          @type arg: L{escript.Symbol}
1939          @return: derivative with respect to C{arg}
1940          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
1941          """
1942          if arg==self:
1943             return identity(self.getShape())
1944          else:
1945             myarg=self.getArgument()[0]
1946             val=matchShape(1./(1+myarg**2),self.getDifferentiatedArguments(arg)[0])
1947             return val[0]*val[1]
1948    
1949    def sinh(arg):
1950       """
1951       returns hyperbolic sine of argument arg
1952    
1953       @param arg: argument
1954       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
1955       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
1956       @raises TypeError: if the type of the argument is not expected.
1957       """
1958       if isinstance(arg,numarray.NumArray):
1959          return numarray.sinh(arg)
1960       elif isinstance(arg,escript.Data):
1961          return arg._sinh()
1962       elif isinstance(arg,float):
1963          return math.sinh(arg)
1964       elif isinstance(arg,int):
1965          return math.sinh(arg)
1966       elif isinstance(arg,Symbol):
1967          return Sinh_Symbol(arg)
1968     else:     else:
1969         arg_shape=()        raise TypeError,"sinh: Unknown argument type."
    return arg_shape  
1970    
1971  def _extractShape(args):  class Sinh_Symbol(DependendSymbol):
1972      """     """
1973      Extracts the common shape of the list of arguments args.     L{Symbol} representing the result of the hyperbolic sine function
1974      """     """
1975      shape=None     def __init__(self,arg):
1976      for a in args:        """
1977         a_shape=_identifyShape(a)        initialization of sinh L{Symbol} with argument arg
1978         if shape==None: shape=a_shape        @param arg: argument of function
1979         if shape!=a_shape: raise ValueError,"inconsistent shape"        @type arg: typically L{Symbol}.
1980      if shape==None:        """
1981         raise ValueError,"cannot recover shape"        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
     return shape  
   
 def _matchShape(args,shape=None):  
     """  
     Returns the list of arguments args as object which have all the  
     specified shape.  
   
     If shape is not given the shape "largest" shape of args is used.  
     """  
     # identify the list of shapes:  
     arg_shapes=[]  
     for a in args: arg_shapes.append(_identifyShape(a))  
     # get the largest shape (currently the longest shape):  
     if shape==None: shape=max(arg_shapes)  
       
     out=[]  
     for i in range(len(args)):  
        if shape==arg_shapes[i]:  
           out.append(args[i])  
        else:  
           if len(shape)==0: # then len(arg_shapes[i])>0  
             raise ValueError,"cannot adopt shape of %s to %s"%(str(args[i]),str(shape))  
           else:  
             if len(arg_shapes[i])==0:  
                 out.append(outer(args[i],numarray.ones(shape)))          
             else:    
                 raise ValueError,"cannot adopt shape of %s to %s"%(str(args[i]),str(shape))  
     return out    
1982    
1983  #=========================================================     def getMyCode(self,argstrs,format="escript"):
1984  #   wrappers for various mathematical functions:        """
1985  #=========================================================        returns a program code that can be used to evaluate the symbol.
 def diff(arg,dep):  
     """  
     Returns the derivative of arg with respect to dep.  
       
     If arg is not Symbol object 0 is returned.  
     """  
     if isinstance(arg,Symbol):  
        return arg.diff(dep)  
     elif hasattr(arg,"shape"):  
           if callable(arg.shape):  
               return numarray.zeros(arg.shape(),numarray.Float)  
           else:  
               return numarray.zeros(arg.shape,numarray.Float)  
     else:  
        return 0  
1986    
1987  def exp(arg):        @param argstrs: gives for each argument a string representing the argument for the evaluation.
1988      """        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
1989      Applies the exponential function to arg.        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
1990          @type format: C{str}
1991          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
1992          @rtype: C{str}
1993          @raise NotImplementedError: if the requested format is not available
1994          """
1995          if isinstance(argstrs,list):
1996              argstrs=argstrs[0]
1997          if format=="escript" or format=="str"  or format=="text":
1998             return "sinh(%s)"%argstrs
1999          else:
2000             raise NotImplementedError,"Sinh_Symbol does not provide program code for format %s."%format
2001    
2002      @param arg: argument     def substitute(self,argvals):
2003      """        """
2004      if isinstance(arg,Symbol):        assigns new values to symbols in the definition of the symbol.
2005         return Exp_Symbol(arg)        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2006      elif hasattr(arg,"exp"):  
2007         return arg.exp()        @param argvals: new values assigned to symbols
2008      else:        @type argvals: C{dict} with keywords of type L{Symbol}.
2009         return numarray.exp(arg)        @return: result of the substitution process. Operations are executed as much as possible.
2010          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2011          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2012          """
2013          if argvals.has_key(self):
2014             arg=argvals[self]
2015             if self.isAppropriateValue(arg):
2016                return arg
2017             else:
2018                raise TypeError,"%s: new value is not appropriate."%str(self)
2019          else:
2020             arg=self.getSubstitutedArguments(argvals)[0]
2021             return sinh(arg)
2022    
2023       def diff(self,arg):
2024          """
2025          differential of this object
2026    
2027  class Exp_Symbol(Symbol):        @param arg: the derivative is calculated with respect to arg
2028          @type arg: L{escript.Symbol}
2029          @return: derivative with respect to C{arg}
2030          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2031          """
2032          if arg==self:
2033             return identity(self.getShape())
2034          else:
2035             myarg=self.getArgument()[0]
2036             val=matchShape(cosh(myarg),self.getDifferentiatedArguments(arg)[0])
2037             return val[0]*val[1]
2038    
2039    def cosh(arg):
2040       """
2041       returns hyperbolic cosine of argument arg
2042    
2043       @param arg: argument
2044       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2045       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2046       @raises TypeError: if the type of the argument is not expected.
2047       """
2048       if isinstance(arg,numarray.NumArray):
2049          return numarray.cosh(arg)
2050       elif isinstance(arg,escript.Data):
2051          return arg._cosh()
2052       elif isinstance(arg,float):
2053          return math.cosh(arg)
2054       elif isinstance(arg,int):
2055          return math.cosh(arg)
2056       elif isinstance(arg,Symbol):
2057          return Cosh_Symbol(arg)
2058       else:
2059          raise TypeError,"cosh: Unknown argument type."
2060    
2061    class Cosh_Symbol(DependendSymbol):
2062     """     """
2063     Symbol representing the power of the first argument to the power of the     L{Symbol} representing the result of the hyperbolic cosine function
    second argument.  
2064     """     """
2065     def __init__(self,arg):     def __init__(self,arg):
2066         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2067     def __str__(self):        initialization of cosh L{Symbol} with argument arg
2068        return "exp(%s)"%str(self.getArgument(0))        @param arg: argument of function
2069     def eval(self,argval):        @type arg: typically L{Symbol}.
2070         return exp(self.getEvaluatedArguments(argval)[0])        """
2071     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
        return self*self.getDifferentiatedArguments(arg)[0]  
2072    
2073  def sqrt(arg):     def getMyCode(self,argstrs,format="escript"):
2074      """        """
2075      Applies the squre root function to arg.        returns a program code that can be used to evaluate the symbol.
2076    
2077      @param arg: argument        @param argstrs: gives for each argument a string representing the argument for the evaluation.
2078      """        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2079      if isinstance(arg,Symbol):        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2080         return Sqrt_Symbol(arg)        @type format: C{str}
2081      elif hasattr(arg,"sqrt"):        @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2082         return arg.sqrt()        @rtype: C{str}
2083      else:        @raise NotImplementedError: if the requested format is not available
2084         return numarray.sqrt(arg)              """
2085          if isinstance(argstrs,list):
2086              argstrs=argstrs[0]
2087          if format=="escript" or format=="str"  or format=="text":
2088             return "cosh(%s)"%argstrs
2089          else:
2090             raise NotImplementedError,"Cosh_Symbol does not provide program code for format %s."%format
2091    
2092       def substitute(self,argvals):
2093          """
2094          assigns new values to symbols in the definition of the symbol.
2095          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2096    
2097          @param argvals: new values assigned to symbols
2098          @type argvals: C{dict} with keywords of type L{Symbol}.
2099          @return: result of the substitution process. Operations are executed as much as possible.
2100          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2101          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2102          """
2103          if argvals.has_key(self):
2104             arg=argvals[self]
2105             if self.isAppropriateValue(arg):
2106                return arg
2107             else:
2108                raise TypeError,"%s: new value is not appropriate."%str(self)
2109          else:
2110             arg=self.getSubstitutedArguments(argvals)[0]
2111             return cosh(arg)
2112    
2113       def diff(self,arg):
2114          """
2115          differential of this object
2116    
2117          @param arg: the derivative is calculated with respect to arg
2118          @type arg: L{escript.Symbol}
2119          @return: derivative with respect to C{arg}
2120          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2121          """
2122          if arg==self:
2123             return identity(self.getShape())
2124          else:
2125             myarg=self.getArgument()[0]
2126             val=matchShape(sinh(myarg),self.getDifferentiatedArguments(arg)[0])
2127             return val[0]*val[1]
2128    
2129    def tanh(arg):
2130       """
2131       returns hyperbolic tangent of argument arg
2132    
2133       @param arg: argument
2134       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2135       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2136       @raises TypeError: if the type of the argument is not expected.
2137       """
2138       if isinstance(arg,numarray.NumArray):
2139          return numarray.tanh(arg)
2140       elif isinstance(arg,escript.Data):
2141          return arg._tanh()
2142       elif isinstance(arg,float):
2143          return math.tanh(arg)
2144       elif isinstance(arg,int):
2145          return math.tanh(arg)
2146       elif isinstance(arg,Symbol):
2147          return Tanh_Symbol(arg)
2148       else:
2149          raise TypeError,"tanh: Unknown argument type."
2150    
2151  class Sqrt_Symbol(Symbol):  class Tanh_Symbol(DependendSymbol):
2152     """     """
2153     Symbol representing square root of argument.     L{Symbol} representing the result of the hyperbolic tangent function
2154     """     """
2155     def __init__(self,arg):     def __init__(self,arg):
2156         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2157     def __str__(self):        initialization of tanh L{Symbol} with argument arg
2158        return "sqrt(%s)"%str(self.getArgument(0))        @param arg: argument of function
2159     def eval(self,argval):        @type arg: typically L{Symbol}.
2160         return sqrt(self.getEvaluatedArguments(argval)[0])        """
2161     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
        return (-0.5)/self*self.getDifferentiatedArguments(arg)[0]  
2162    
2163  def log(arg):     def getMyCode(self,argstrs,format="escript"):
2164      """        """
2165      Applies the logarithmic function bases exp(1.) to arg        returns a program code that can be used to evaluate the symbol.
2166    
2167      @param arg: argument        @param argstrs: gives for each argument a string representing the argument for the evaluation.
2168      """        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2169      if isinstance(arg,Symbol):        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2170         return Log_Symbol(arg)        @type format: C{str}
2171      elif hasattr(arg,"log"):        @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2172         return arg.log()        @rtype: C{str}
2173      else:        @raise NotImplementedError: if the requested format is not available
2174         return numarray.log(arg)        """
2175          if isinstance(argstrs,list):
2176              argstrs=argstrs[0]
2177          if format=="escript" or format=="str"  or format=="text":
2178             return "tanh(%s)"%argstrs
2179          else:
2180             raise NotImplementedError,"Tanh_Symbol does not provide program code for format %s."%format
2181    
2182       def substitute(self,argvals):
2183          """
2184          assigns new values to symbols in the definition of the symbol.
2185          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2186    
2187  class Log_Symbol(Symbol):        @param argvals: new values assigned to symbols
2188          @type argvals: C{dict} with keywords of type L{Symbol}.
2189          @return: result of the substitution process. Operations are executed as much as possible.
2190          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2191          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2192          """
2193          if argvals.has_key(self):
2194             arg=argvals[self]
2195             if self.isAppropriateValue(arg):
2196                return arg
2197             else:
2198                raise TypeError,"%s: new value is not appropriate."%str(self)
2199          else:
2200             arg=self.getSubstitutedArguments(argvals)[0]
2201             return tanh(arg)
2202    
2203       def diff(self,arg):
2204          """
2205          differential of this object
2206    
2207          @param arg: the derivative is calculated with respect to arg
2208          @type arg: L{escript.Symbol}
2209          @return: derivative with respect to C{arg}
2210          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2211          """
2212          if arg==self:
2213             return identity(self.getShape())
2214          else:
2215             myarg=self.getArgument()[0]
2216             val=matchShape(1./cosh(myarg)**2,self.getDifferentiatedArguments(arg)[0])
2217             return val[0]*val[1]
2218    
2219    def asinh(arg):
2220       """
2221       returns inverse hyperbolic sine of argument arg
2222    
2223       @param arg: argument
2224       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2225       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2226       @raises TypeError: if the type of the argument is not expected.
2227       """
2228       if isinstance(arg,numarray.NumArray):
2229          return numarray.arcsinh(arg)
2230       elif isinstance(arg,escript.Data):
2231          return arg._asinh()
2232       elif isinstance(arg,float):
2233          return numarray.arcsinh(arg)
2234       elif isinstance(arg,int):
2235          return numarray.arcsinh(float(arg))
2236       elif isinstance(arg,Symbol):
2237          return Asinh_Symbol(arg)
2238       else:
2239          raise TypeError,"asinh: Unknown argument type."
2240    
2241    class Asinh_Symbol(DependendSymbol):
2242     """     """
2243     Symbol representing logarithm of the argument.     L{Symbol} representing the result of the inverse hyperbolic sine function
2244     """     """
2245     def __init__(self,arg):     def __init__(self,arg):
2246         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2247     def __str__(self):        initialization of asinh L{Symbol} with argument arg
2248        return "log(%s)"%str(self.getArgument(0))        @param arg: argument of function
2249     def eval(self,argval):        @type arg: typically L{Symbol}.
2250         return log(self.getEvaluatedArguments(argval)[0])        """
2251     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
        return self.getDifferentiatedArguments(arg)[0]/self.getArgument(0)  
2252    
2253  def ln(arg):     def getMyCode(self,argstrs,format="escript"):
2254      """        """
2255      Applies the natural logarithmic function to arg.        returns a program code that can be used to evaluate the symbol.
2256    
2257      @param arg: argument        @param argstrs: gives for each argument a string representing the argument for the evaluation.
2258      """        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2259      if isinstance(arg,Symbol):        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2260         return Ln_Symbol(arg)        @type format: C{str}
2261      elif hasattr(arg,"ln"):        @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2262         return arg.log()        @rtype: C{str}
2263      else:        @raise NotImplementedError: if the requested format is not available
2264         return numarray.log(arg)        """
2265          if isinstance(argstrs,list):
2266              argstrs=argstrs[0]
2267          if format=="escript" or format=="str"  or format=="text":
2268             return "asinh(%s)"%argstrs
2269          else:
2270             raise NotImplementedError,"Asinh_Symbol does not provide program code for format %s."%format
2271    
2272       def substitute(self,argvals):
2273          """
2274          assigns new values to symbols in the definition of the symbol.
2275          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2276    
2277          @param argvals: new values assigned to symbols
2278          @type argvals: C{dict} with keywords of type L{Symbol}.
2279          @return: result of the substitution process. Operations are executed as much as possible.
2280          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2281          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2282          """
2283          if argvals.has_key(self):
2284             arg=argvals[self]
2285             if self.isAppropriateValue(arg):
2286                return arg
2287             else:
2288                raise TypeError,"%s: new value is not appropriate."%str(self)
2289          else:
2290             arg=self.getSubstitutedArguments(argvals)[0]
2291             return asinh(arg)
2292    
2293       def diff(self,arg):
2294          """
2295          differential of this object
2296    
2297  class Ln_Symbol(Symbol):        @param arg: the derivative is calculated with respect to arg
2298          @type arg: L{escript.Symbol}
2299          @return: derivative with respect to C{arg}
2300          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2301          """
2302          if arg==self:
2303             return identity(self.getShape())
2304          else:
2305             myarg=self.getArgument()[0]
2306             val=matchShape(1./sqrt(myarg**2+1),self.getDifferentiatedArguments(arg)[0])
2307             return val[0]*val[1]
2308    
2309    def acosh(arg):
2310       """
2311       returns inverse hyperolic cosine of argument arg
2312    
2313       @param arg: argument
2314       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2315       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2316       @raises TypeError: if the type of the argument is not expected.
2317       """
2318       if isinstance(arg,numarray.NumArray):
2319          return numarray.arccosh(arg)
2320       elif isinstance(arg,escript.Data):
2321          return arg._acosh()
2322       elif isinstance(arg,float):
2323          return numarray.arccosh(arg)
2324       elif isinstance(arg,int):
2325          return numarray.arccosh(float(arg))
2326       elif isinstance(arg,Symbol):
2327          return Acosh_Symbol(arg)
2328       else:
2329          raise TypeError,"acosh: Unknown argument type."
2330    
2331    class Acosh_Symbol(DependendSymbol):
2332     """     """
2333     Symbol representing natural logarithm of the argument.     L{Symbol} representing the result of the inverse hyperolic cosine function
2334     """     """
2335     def __init__(self,arg):     def __init__(self,arg):
2336         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2337     def __str__(self):        initialization of acosh L{Symbol} with argument arg
2338        return "ln(%s)"%str(self.getArgument(0))        @param arg: argument of function
2339     def eval(self,argval):        @type arg: typically L{Symbol}.
2340         return ln(self.getEvaluatedArguments(argval)[0])        """
2341     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
        return self.getDifferentiatedArguments(arg)[0]/self.getArgument(0)  
2342    
2343  def sin(arg):     def getMyCode(self,argstrs,format="escript"):
2344      """        """
2345      Applies the sin function to arg.        returns a program code that can be used to evaluate the symbol.
2346    
2347      @param arg: argument        @param argstrs: gives for each argument a string representing the argument for the evaluation.
2348      """        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2349      if isinstance(arg,Symbol):        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2350         return Sin_Symbol(arg)        @type format: C{str}
2351      elif hasattr(arg,"sin"):        @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2352         return arg.sin()        @rtype: C{str}
2353      else:        @raise NotImplementedError: if the requested format is not available
2354         return numarray.sin(arg)        """
2355          if isinstance(argstrs,list):
2356              argstrs=argstrs[0]
2357          if format=="escript" or format=="str"  or format=="text":
2358             return "acosh(%s)"%argstrs
2359          else:
2360             raise NotImplementedError,"Acosh_Symbol does not provide program code for format %s."%format
2361    
2362       def substitute(self,argvals):
2363          """
2364          assigns new values to symbols in the definition of the symbol.
2365          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2366    
2367          @param argvals: new values assigned to symbols
2368          @type argvals: C{dict} with keywords of type L{Symbol}.
2369          @return: result of the substitution process. Operations are executed as much as possible.
2370          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2371          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2372          """
2373          if argvals.has_key(self):
2374             arg=argvals[self]
2375             if self.isAppropriateValue(arg):
2376                return arg
2377             else:
2378                raise TypeError,"%s: new value is not appropriate."%str(self)
2379          else:
2380             arg=self.getSubstitutedArguments(argvals)[0]
2381             return acosh(arg)
2382    
2383       def diff(self,arg):
2384          """
2385          differential of this object
2386    
2387          @param arg: the derivative is calculated with respect to arg
2388          @type arg: L{escript.Symbol}
2389          @return: derivative with respect to C{arg}
2390          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2391          """
2392          if arg==self:
2393             return identity(self.getShape())
2394          else:
2395             myarg=self.getArgument()[0]
2396             val=matchShape(1./sqrt(myarg**2-1),self.getDifferentiatedArguments(arg)[0])
2397             return val[0]*val[1]
2398    
2399    def atanh(arg):
2400       """
2401       returns inverse hyperbolic tangent of argument arg
2402    
2403       @param arg: argument
2404       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2405       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2406       @raises TypeError: if the type of the argument is not expected.
2407       """
2408       if isinstance(arg,numarray.NumArray):
2409          return numarray.arctanh(arg)
2410       elif isinstance(arg,escript.Data):
2411          return arg._atanh()
2412       elif isinstance(arg,float):
2413          return numarray.arctanh(arg)
2414       elif isinstance(arg,int):
2415          return numarray.arctanh(float(arg))
2416       elif isinstance(arg,Symbol):
2417          return Atanh_Symbol(arg)
2418       else:
2419          raise TypeError,"atanh: Unknown argument type."
2420    
2421  class Sin_Symbol(Symbol):  class Atanh_Symbol(DependendSymbol):
2422     """     """
2423     Symbol representing sin of the argument.     L{Symbol} representing the result of the inverse hyperbolic tangent function
2424     """     """
2425     def __init__(self,arg):     def __init__(self,arg):
2426         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2427     def __str__(self):        initialization of atanh L{Symbol} with argument arg
2428        return "sin(%s)"%str(self.getArgument(0))        @param arg: argument of function
2429     def eval(self,argval):        @type arg: typically L{Symbol}.
2430         return sin(self.getEvaluatedArguments(argval)[0])        """
2431     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
        return cos(self.getArgument(0))*self.getDifferentiatedArguments(arg)[0]  
2432    
2433  def cos(arg):     def getMyCode(self,argstrs,format="escript"):
2434      """        """
2435      Applies the cos function to arg.        returns a program code that can be used to evaluate the symbol.
2436    
2437      @param arg: argument        @param argstrs: gives for each argument a string representing the argument for the evaluation.
2438      """        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2439      if isinstance(arg,Symbol):        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2440         return Cos_Symbol(arg)        @type format: C{str}
2441      elif hasattr(arg,"cos"):        @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2442         return arg.cos()        @rtype: C{str}
2443      else:        @raise NotImplementedError: if the requested format is not available
2444         return numarray.cos(arg)        """
2445          if isinstance(argstrs,list):
2446              argstrs=argstrs[0]
2447          if format=="escript" or format=="str"  or format=="text":
2448             return "atanh(%s)"%argstrs
2449          else:
2450             raise NotImplementedError,"Atanh_Symbol does not provide program code for format %s."%format
2451    
2452       def substitute(self,argvals):
2453          """
2454          assigns new values to symbols in the definition of the symbol.
2455          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2456    
2457          @param argvals: new values assigned to symbols
2458          @type argvals: C{dict} with keywords of type L{Symbol}.
2459          @return: result of the substitution process. Operations are executed as much as possible.
2460          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2461          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2462          """
2463          if argvals.has_key(self):
2464             arg=argvals[self]
2465             if self.isAppropriateValue(arg):
2466                return arg
2467             else:
2468                raise TypeError,"%s: new value is not appropriate."%str(self)
2469          else:
2470             arg=self.getSubstitutedArguments(argvals)[0]
2471             return atanh(arg)
2472    
2473       def diff(self,arg):
2474          """
2475          differential of this object
2476    
2477  class Cos_Symbol(Symbol):        @param arg: the derivative is calculated with respect to arg
2478          @type arg: L{escript.Symbol}
2479          @return: derivative with respect to C{arg}
2480          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2481          """
2482          if arg==self:
2483             return identity(self.getShape())
2484          else:
2485             myarg=self.getArgument()[0]
2486             val=matchShape(1./(1.-myarg**2),self.getDifferentiatedArguments(arg)[0])
2487             return val[0]*val[1]
2488    
2489    def exp(arg):
2490       """
2491       returns exponential of argument arg
2492    
2493       @param arg: argument
2494       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2495       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2496       @raises TypeError: if the type of the argument is not expected.
2497       """
2498       if isinstance(arg,numarray.NumArray):
2499          return numarray.exp(arg)
2500       elif isinstance(arg,escript.Data):
2501          return arg._exp()
2502       elif isinstance(arg,float):
2503          return math.exp(arg)
2504       elif isinstance(arg,int):
2505          return math.exp(arg)
2506       elif isinstance(arg,Symbol):
2507          return Exp_Symbol(arg)
2508       else:
2509          raise TypeError,"exp: Unknown argument type."
2510    
2511    class Exp_Symbol(DependendSymbol):
2512     """     """
2513     Symbol representing cos of the argument.     L{Symbol} representing the result of the exponential function
2514     """     """
2515     def __init__(self,arg):     def __init__(self,arg):
2516         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2517     def __str__(self):        initialization of exp L{Symbol} with argument arg
2518        return "cos(%s)"%str(self.getArgument(0))        @param arg: argument of function
2519     def eval(self,argval):        @type arg: typically L{Symbol}.
2520         return cos(self.getEvaluatedArguments(argval)[0])        """
2521     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
        return -sin(self.getArgument(0))*self.getDifferentiatedArguments(arg)[0]  
2522    
2523  def tan(arg):     def getMyCode(self,argstrs,format="escript"):
2524      """        """
2525      Applies the tan function to arg.        returns a program code that can be used to evaluate the symbol.
2526    
2527      @param arg: argument        @param argstrs: gives for each argument a string representing the argument for the evaluation.
2528      """        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2529      if isinstance(arg,Symbol):        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2530         return Tan_Symbol(arg)        @type format: C{str}
2531      elif hasattr(arg,"tan"):        @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2532         return arg.tan()        @rtype: C{str}
2533      else:        @raise NotImplementedError: if the requested format is not available
2534         return numarray.tan(arg)        """
2535          if isinstance(argstrs,list):
2536              argstrs=argstrs[0]
2537          if format=="escript" or format=="str"  or format=="text":
2538             return "exp(%s)"%argstrs
2539          else:
2540             raise NotImplementedError,"Exp_Symbol does not provide program code for format %s."%format
2541    
2542       def substitute(self,argvals):
2543          """
2544          assigns new values to symbols in the definition of the symbol.
2545          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2546    
2547          @param argvals: new values assigned to symbols
2548          @type argvals: C{dict} with keywords of type L{Symbol}.
2549          @return: result of the substitution process. Operations are executed as much as possible.
2550          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2551          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2552          """
2553          if argvals.has_key(self):
2554             arg=argvals[self]
2555             if self.isAppropriateValue(arg):
2556                return arg
2557             else:
2558                raise TypeError,"%s: new value is not appropriate."%str(self)
2559          else:
2560             arg=self.getSubstitutedArguments(argvals)[0]
2561             return exp(arg)
2562    
2563       def diff(self,arg):
2564          """
2565          differential of this object
2566    
2567          @param arg: the derivative is calculated with respect to arg
2568          @type arg: L{escript.Symbol}
2569          @return: derivative with respect to C{arg}
2570          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2571          """
2572          if arg==self:
2573             return identity(self.getShape())
2574          else:
2575             myarg=self.getArgument()[0]
2576             val=matchShape(self,self.getDifferentiatedArguments(arg)[0])
2577             return val[0]*val[1]
2578    
2579    def sqrt(arg):
2580       """
2581       returns square root of argument arg
2582    
2583  class Tan_Symbol(Symbol):     @param arg: argument
2584       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2585       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2586       @raises TypeError: if the type of the argument is not expected.
2587       """
2588       if isinstance(arg,numarray.NumArray):
2589          return numarray.sqrt(arg)
2590       elif isinstance(arg,escript.Data):
2591          return arg._sqrt()
2592       elif isinstance(arg,float):
2593          return math.sqrt(arg)
2594       elif isinstance(arg,int):
2595          return math.sqrt(arg)
2596       elif isinstance(arg,Symbol):
2597          return Sqrt_Symbol(arg)
2598       else:
2599          raise TypeError,"sqrt: Unknown argument type."
2600    
2601    class Sqrt_Symbol(DependendSymbol):
2602     """     """
2603     Symbol representing tan of the argument.     L{Symbol} representing the result of the square root function
2604     """     """
2605     def __init__(self,arg):     def __init__(self,arg):
2606         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2607     def __str__(self):        initialization of sqrt L{Symbol} with argument arg
2608        return "tan(%s)"%str(self.getArgument(0))        @param arg: argument of function
2609     def eval(self,argval):        @type arg: typically L{Symbol}.
2610         return tan(self.getEvaluatedArguments(argval)[0])        """
2611     def _diff(self,arg):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
        s=cos(self.getArgument(0))  
        return 1./(s*s)*self.getDifferentiatedArguments(arg)[0]  
2612    
2613  def sign(arg):     def getMyCode(self,argstrs,format="escript"):
2614      """        """
2615      Applies the sign function to arg.        returns a program code that can be used to evaluate the symbol.
2616    
2617      @param arg: argument        @param argstrs: gives for each argument a string representing the argument for the evaluation.
2618      """        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2619      if isinstance(arg,Symbol):        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2620         return Sign_Symbol(arg)        @type format: C{str}
2621      elif hasattr(arg,"sign"):        @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2622         return arg.sign()        @rtype: C{str}
2623      else:        @raise NotImplementedError: if the requested format is not available
2624         return numarray.greater(arg,numarray.zeros(arg.shape,numarray.Float))- \        """
2625                numarray.less(arg,numarray.zeros(arg.shape,numarray.Float))        if isinstance(argstrs,list):
2626              argstrs=argstrs[0]
2627          if format=="escript" or format=="str"  or format=="text":
2628             return "sqrt(%s)"%argstrs
2629          else:
2630             raise NotImplementedError,"Sqrt_Symbol does not provide program code for format %s."%format
2631    
2632       def substitute(self,argvals):
2633          """
2634          assigns new values to symbols in the definition of the symbol.
2635          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2636    
2637          @param argvals: new values assigned to symbols
2638          @type argvals: C{dict} with keywords of type L{Symbol}.
2639          @return: result of the substitution process. Operations are executed as much as possible.
2640          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2641          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2642          """
2643          if argvals.has_key(self):
2644             arg=argvals[self]
2645             if self.isAppropriateValue(arg):
2646                return arg
2647             else:
2648                raise TypeError,"%s: new value is not appropriate."%str(self)
2649          else:
2650             arg=self.getSubstitutedArguments(argvals)[0]
2651             return sqrt(arg)
2652    
2653       def diff(self,arg):
2654          """
2655          differential of this object
2656    
2657          @param arg: the derivative is calculated with respect to arg
2658          @type arg: L{escript.Symbol}
2659          @return: derivative with respect to C{arg}
2660          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2661          """
2662          if arg==self:
2663             return identity(self.getShape())
2664          else:
2665             myarg=self.getArgument()[0]
2666             val=matchShape(0.5/self,self.getDifferentiatedArguments(arg)[0])
2667             return val[0]*val[1]
2668    
2669    def log(arg):
2670       """
2671       returns natural logarithm of argument arg
2672    
2673       @param arg: argument
2674       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2675       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2676       @raises TypeError: if the type of the argument is not expected.
2677       """
2678       if isinstance(arg,numarray.NumArray):
2679          return numarray.log(arg)
2680       elif isinstance(arg,escript.Data):
2681          return arg._log()
2682       elif isinstance(arg,float):
2683          return math.log(arg)
2684       elif isinstance(arg,int):
2685          return math.log(arg)
2686       elif isinstance(arg,Symbol):
2687          return Log_Symbol(arg)
2688       else:
2689          raise TypeError,"log: Unknown argument type."
2690    
2691  class Sign_Symbol(Symbol):  class Log_Symbol(DependendSymbol):
2692     """     """
2693     Symbol representing the sign of the argument.     L{Symbol} representing the result of the natural logarithm function
2694     """     """
2695     def __init__(self,arg):     def __init__(self,arg):
2696         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2697     def __str__(self):        initialization of log L{Symbol} with argument arg
2698        return "sign(%s)"%str(self.getArgument(0))        @param arg: argument of function
2699     def eval(self,argval):        @type arg: typically L{Symbol}.
2700         return sign(self.getEvaluatedArguments(argval)[0])        """
2701          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2702    
2703  def maxval(arg):     def getMyCode(self,argstrs,format="escript"):
2704      """        """
2705      Returns the maximum value of argument arg.        returns a program code that can be used to evaluate the symbol.
2706    
2707      @param arg: argument        @param argstrs: gives for each argument a string representing the argument for the evaluation.
2708      """        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2709      if isinstance(arg,Symbol):        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2710         return Max_Symbol(arg)        @type format: C{str}
2711      elif hasattr(arg,"maxval"):        @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2712         return arg.maxval()        @rtype: C{str}
2713      elif hasattr(arg,"max"):        @raise NotImplementedError: if the requested format is not available
2714         return arg.max()        """
2715      else:        if isinstance(argstrs,list):
2716         return arg            argstrs=argstrs[0]
2717          if format=="escript" or format=="str"  or format=="text":
2718             return "log(%s)"%argstrs
2719          else:
2720             raise NotImplementedError,"Log_Symbol does not provide program code for format %s."%format
2721    
2722       def substitute(self,argvals):
2723          """
2724          assigns new values to symbols in the definition of the symbol.
2725          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2726    
2727  class Max_Symbol(Symbol):        @param argvals: new values assigned to symbols
2728          @type argvals: C{dict} with keywords of type L{Symbol}.
2729          @return: result of the substitution process. Operations are executed as much as possible.
2730          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2731          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2732          """
2733          if argvals.has_key(self):
2734             arg=argvals[self]
2735             if self.isAppropriateValue(arg):
2736                return arg
2737             else:
2738                raise TypeError,"%s: new value is not appropriate."%str(self)
2739          else:
2740             arg=self.getSubstitutedArguments(argvals)[0]
2741             return log(arg)
2742    
2743       def diff(self,arg):
2744          """
2745          differential of this object
2746    
2747          @param arg: the derivative is calculated with respect to arg
2748          @type arg: L{escript.Symbol}
2749          @return: derivative with respect to C{arg}
2750          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2751          """
2752          if arg==self:
2753             return identity(self.getShape())
2754          else:
2755             myarg=self.getArgument()[0]
2756             val=matchShape(1./arg,self.getDifferentiatedArguments(arg)[0])
2757             return val[0]*val[1]
2758    
2759    def sign(arg):
2760     """     """
2761     Symbol representing the maximum value of the argument.     returns sign of argument arg
2762    
2763       @param arg: argument
2764       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2765       @rtype: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2766       @raises TypeError: if the type of the argument is not expected.
2767       """
2768       if isinstance(arg,numarray.NumArray):
2769          return wherePositive(arg)-whereNegative(arg)
2770       elif isinstance(arg,escript.Data):
2771          return arg._sign()
2772       elif isinstance(arg,float):
2773          if arg>0:
2774            return 1.
2775          elif arg<0:
2776            return -1.
2777          else:
2778            return 0.
2779       elif isinstance(arg,int):
2780          if float(arg)>0:
2781            return 1.
2782          elif float(arg)<0:
2783            return -1.
2784          else:
2785            return 0.
2786       elif isinstance(arg,Symbol):
2787          return wherePositive(arg)-whereNegative(arg)
2788       else:
2789          raise TypeError,"sign: Unknown argument type."
2790    
2791    class Abs_Symbol(DependendSymbol):
2792       """
2793       L{Symbol} representing the result of the absolute value function
2794     """     """
2795     def __init__(self,arg):     def __init__(self,arg):
2796         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2797     def __str__(self):        initialization of abs L{Symbol} with argument arg
2798        return "maxval(%s)"%str(self.getArgument(0))        @param arg: argument of function
2799     def eval(self,argval):        @type arg: typically L{Symbol}.
2800         return maxval(self.getEvaluatedArguments(argval)[0])        """
2801          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2802    
2803       def getMyCode(self,argstrs,format="escript"):
2804          """
2805          returns a program code that can be used to evaluate the symbol.
2806    
2807          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2808          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2809          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2810          @type format: C{str}
2811          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2812          @rtype: C{str}
2813          @raise NotImplementedError: if the requested format is not available
2814          """
2815          if isinstance(argstrs,list):
2816              argstrs=argstrs[0]
2817          if format=="escript" or format=="str"  or format=="text":
2818             return "abs(%s)"%argstrs
2819          else:
2820             raise NotImplementedError,"Abs_Symbol does not provide program code for format %s."%format
2821    
2822       def substitute(self,argvals):
2823          """
2824          assigns new values to symbols in the definition of the symbol.
2825          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2826    
2827          @param argvals: new values assigned to symbols
2828          @type argvals: C{dict} with keywords of type L{Symbol}.
2829          @return: result of the substitution process. Operations are executed as much as possible.
2830          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2831          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2832          """
2833          if argvals.has_key(self):
2834             arg=argvals[self]
2835             if self.isAppropriateValue(arg):
2836                return arg
2837             else:
2838                raise TypeError,"%s: new value is not appropriate."%str(self)
2839          else:
2840             arg=self.getSubstitutedArguments(argvals)[0]
2841             return abs(arg)
2842    
2843       def diff(self,arg):
2844          """
2845          differential of this object
2846    
2847          @param arg: the derivative is calculated with respect to arg
2848          @type arg: L{escript.Symbol}
2849          @return: derivative with respect to C{arg}
2850          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
2851          """
2852          if arg==self:
2853             return identity(self.getShape())
2854          else:
2855             myarg=self.getArgument()[0]
2856             val=matchShape(sign(myarg),self.getDifferentiatedArguments(arg)[0])
2857             return val[0]*val[1]
2858    
2859  def minval(arg):  def minval(arg):
2860      """     """
2861      Returns the minimum value of argument arg.     returns minimum value over all components of arg at each data point
2862    
2863      @param arg: argument     @param arg: argument
2864      """     @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2865      if isinstance(arg,Symbol):     @rtype: C{float}, L{escript.Data}, L{Symbol} depending on the type of arg.
2866         return Min_Symbol(arg)     @raises TypeError: if the type of the argument is not expected.
2867      elif hasattr(arg,"maxval"):     """
2868         return arg.minval()     if isinstance(arg,numarray.NumArray):
2869      elif hasattr(arg,"min"):        if arg.rank==0:
2870         return arg.min()           return float(arg)
2871      else:        else:
2872         return arg           return arg.min()
2873       elif isinstance(arg,escript.Data):
2874          return arg._minval()
2875       elif isinstance(arg,float):
2876          return arg
2877       elif isinstance(arg,int):
2878          return float(arg)
2879       elif isinstance(arg,Symbol):
2880          return Minval_Symbol(arg)
2881       else:
2882          raise TypeError,"minval: Unknown argument type."
2883    
2884  class Min_Symbol(Symbol):  class Minval_Symbol(DependendSymbol):
2885     """     """
2886     Symbol representing the minimum value of the argument.     L{Symbol} representing the result of the minimum value function
2887     """     """
2888     def __init__(self,arg):     def __init__(self,arg):
2889         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2890     def __str__(self):        initialization of minimum value L{Symbol} with argument arg
2891        return "minval(%s)"%str(self.getArgument(0))        @param arg: argument of function
2892     def eval(self,argval):        @type arg: typically L{Symbol}.
2893         return minval(self.getEvaluatedArguments(argval)[0])        """
2894          DependendSymbol.__init__(self,args=[arg],shape=(),dim=arg.getDim())
2895    
2896  def wherePositive(arg):     def getMyCode(self,argstrs,format="escript"):
2897          """
2898          returns a program code that can be used to evaluate the symbol.
2899    
2900          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2901          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2902          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2903          @type format: C{str}
2904          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2905          @rtype: C{str}
2906          @raise NotImplementedError: if the requested format is not available
2907          """
2908          if isinstance(argstrs,list):
2909              argstrs=argstrs[0]
2910          if format=="escript" or format=="str"  or format=="text":
2911             return "minval(%s)"%argstrs
2912          else:
2913             raise NotImplementedError,"Minval_Symbol does not provide program code for format %s."%format
2914    
2915       def substitute(self,argvals):
2916          """
2917          assigns new values to symbols in the definition of the symbol.
2918          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2919    
2920          @param argvals: new values assigned to symbols
2921          @type argvals: C{dict} with keywords of type L{Symbol}.
2922          @return: result of the substitution process. Operations are executed as much as possible.
2923          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
2924          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
2925          """
2926          if argvals.has_key(self):
2927             arg=argvals[self]
2928             if self.isAppropriateValue(arg):
2929                return arg
2930             else:
2931                raise TypeError,"%s: new value is not appropriate."%str(self)
2932          else:
2933             arg=self.getSubstitutedArguments(argvals)[0]
2934             return minval(arg)
2935    
2936    def maxval(arg):
2937       """
2938       returns maximum value over all components of arg at each data point
2939    
2940       @param arg: argument
2941       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2942       @rtype: C{float}, L{escript.Data}, L{Symbol} depending on the type of arg.
2943       @raises TypeError: if the type of the argument is not expected.
2944       """
2945       if isinstance(arg,numarray.NumArray):
2946          if arg.rank==0:
2947             return float(arg)
2948          else:
2949             return arg.max()
2950       elif isinstance(arg,escript.Data):
2951          return arg._maxval()
2952       elif isinstance(arg,float):
2953          return arg
2954       elif isinstance(arg,int):
2955          return float(arg)
2956       elif isinstance(arg,Symbol):
2957          return Maxval_Symbol(arg)
2958       else:
2959          raise TypeError,"maxval: Unknown argument type."
2960    
2961    class Maxval_Symbol(DependendSymbol):
2962       """
2963       L{Symbol} representing the result of the maximum value function
2964       """
2965       def __init__(self,arg):
2966          """
2967          initialization of maximum value L{Symbol} with argument arg
2968          @param arg: argument of function
2969          @type arg: typically L{Symbol}.
2970          """
2971          DependendSymbol.__init__(self,args=[arg],shape=(),dim=arg.getDim())
2972    
2973       def getMyCode(self,argstrs,format="escript"):
2974          """
2975          returns a program code that can be used to evaluate the symbol.
2976    
2977          @param argstrs: gives for each argument a string representing the argument for the evaluation.
2978          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
2979          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
2980          @type format: C{str}
2981          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
2982          @rtype: C{str}
2983          @raise NotImplementedError: if the requested format is not available
2984          """
2985          if isinstance(argstrs,list):
2986              argstrs=argstrs[0]
2987          if format=="escript" or format=="str"  or format=="text":
2988             return "maxval(%s)"%argstrs
2989          else:
2990             raise NotImplementedError,"Maxval_Symbol does not provide program code for format %s."%format
2991    
2992       def substitute(self,argvals):
2993          """
2994          assigns new values to symbols in the definition of the symbol.
2995          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
2996    
2997          @param argvals: new values assigned to symbols
2998          @type argvals: C{dict} with keywords of type L{Symbol}.
2999          @return: result of the substitution process. Operations are executed as much as possible.
3000          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
3001          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
3002          """
3003          if argvals.has_key(self):
3004             arg=argvals[self]
3005             if self.isAppropriateValue(arg):
3006                return arg
3007             else:
3008                raise TypeError,"%s: new value is not appropriate."%str(self)
3009          else:
3010             arg=self.getSubstitutedArguments(argvals)[0]
3011             return maxval(arg)
3012    
3013    def length(arg):
3014       """
3015       returns length/Euclidean norm of argument arg at each data point
3016    
3017       @param arg: argument
3018       @type arg: C{float}, L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
3019       @rtype: C{float}, L{escript.Data}, L{Symbol} depending on the type of arg.
3020       """
3021       return sqrt(inner(arg,arg))
3022    
3023    def trace(arg,axis_offset=0):
3024       """
3025       returns the trace of arg which the sum of arg[k,k] over k.
3026    
3027       @param arg: argument
3028       @type arg: L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
3029       @param axis_offset: C{axis_offset} to components to sum over. C{axis_offset} must be non-negative and less than the rank of arg +1. The dimensions on component
3030                      C{axis_offset} and axis_offset+1 must be equal.
3031       @type axis_offset: C{int}
3032       @return: trace of arg. The rank of the returned object is minus 2 of the rank of arg.
3033       @rtype: L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
3034       """
3035       if isinstance(arg,numarray.NumArray):
3036          sh=arg.shape
3037          if len(sh)<2:
3038            raise ValueError,"rank of argument must be greater than 1"
3039          if axis_offset<0 or axis_offset>len(sh)-2:
3040            raise ValueError,"axis_offset must be between 0 and %s"%len(sh)-2
3041          s1=1
3042          for i in range(axis_offset): s1*=sh[i]
3043          s2=1
3044          for i in range(axis_offset+2,len(sh)): s2*=sh[i]
3045          if not sh[axis_offset] == sh[axis_offset+1]: