/[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

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