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

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

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

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