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

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

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

trunk/esys2/escript/py_src/util.py revision 149 by jgs, Thu Sep 1 03:31:39 2005 UTC trunk/escript/py_src/util.py revision 2237 by gross, Tue Feb 3 06:14:19 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
41    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  # a simple tool box to deal with _differentials of functions  #   some helpers:
49  #===========================================================  #=========================================================
50    def getEpsilon():
51         return escript.getMachinePrecision()
52    EPSILON=getEpsilon()
53    
54    def getMaxFloat():
55         return escript.getMaxFloat()
56    DBLE_MAX=getMaxFloat()
57    
58    
59    def getTagNames(domain):
60        """
61        Returns a list of tag names used by the domain.
62    
63        @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):
98        """
99        Writes L{Data} objects and their mesh into a file using the VTK XML file
100        format.
101    
102        Example::
103    
104            tmp=Scalar(..)
105            v=Vector(..)
106            saveVTK("solution.vtu", temperature=tmp, velocity=v)
107    
108        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
112        @type filename: C{str}
113        @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}
116        @keyword <name>: writes the assigned value to the VTK file using <name> as
117                         identifier
118        @type <name>: L{Data} object
119        @note: The data objects have to be defined on the same domain. They may not
120               be in the same L{FunctionSpace} but one cannot expect that all
121               L{FunctionSpace}s can be mixed. Typically, data on the boundary and
122               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:
137            raise ValueError,"saveVTK: no domain detected."
138        domain.saveVTK(filename,new_data)
139    
140    def saveDX(filename,domain=None,**data):
141        """
142        Writes L{Data} objects into a file using the OpenDX file format.
143    
144        Example::
145    
146            tmp=Scalar(..)
147            v=Vector(..)
148            saveDX("solution.dx", temperature=tmp, velocity=v)
149    
150        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
154        @type filename: C{str}
155        @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}
158        @keyword <name>: writes the assigned value to the DX file using <name> as
159                         identifier. The identifier can be used to select the data
160                         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:
182            raise ValueError,"saveDX: no domain detected."
183        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:
228            raise ValueError, "saveESD: no domain detected."
229    
230        if domain.onMasterProcessor() and not os.path.isdir(dataDir):
231            os.mkdir(dataDir)
232    
233        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  class Symbol:  def identityTensor(d=3):
298     """     """
299     Symbol class.     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     def __init__(self,name="symbol",shape=(),dim=3,args=[]):     Returns the C{d} x C{d} x C{d} x C{d} identity tensor.
318         """  
319         Creates an instance of a symbol of shape shape and spatial dimension     @param d: dimension or an object that has the C{getDim} method defining the
320         dim.               dimension
321             @type d: C{int} or any object with a C{getDim} method
322         The symbol may depending on a list of arguments args which may be     @return: the object u of rank 4 with M{u[i,j,k,l]=1} for M{i=k and j=l} and
323         symbols or other objects. name gives the name of the symbol.              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        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
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,numarray.NumArray):
364            return sup(abs(arg))
365        elif isinstance(arg,escript.Data):
366            return arg._Lsup()
367        elif isinstance(arg,float):
368            return abs(arg)
369        elif isinstance(arg,int):
370            return abs(float(arg))
371        else:
372          raise TypeError,"Lsup: Unknown argument type."
373    
374    def sup(arg):
375        """
376        Returns the maximum value over all data points.
377    
378        @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,numarray.NumArray):
385            return arg.max()
386        elif isinstance(arg,escript.Data):
387            return arg._sup()
388        elif isinstance(arg,float):
389            return arg
390        elif isinstance(arg,int):
391            return float(arg)
392        else:
393          raise TypeError,"sup: Unknown argument type."
394    
395    def inf(arg):
396        """
397        Returns the minimum value over all data points.
398    
399        @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,numarray.NumArray):
406            return arg.min()
407        elif isinstance(arg,escript.Data):
408            return arg._inf()
409        elif isinstance(arg,float):
410            return arg
411        elif isinstance(arg,int):
412            return float(arg)
413        else:
414          raise TypeError,"inf: Unknown argument type."
415    
416    
417    #=========================================================================
418    #   some little helpers
419    #=========================================================================
420    def getRank(arg):
421        """
422        Identifies the rank of the argument.
423    
424        @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    
432        if isinstance(arg,numarray.NumArray):
433            return arg.rank
434        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:
443          raise TypeError,"getRank: Unknown argument type."
444    
445    def getShape(arg):
446        """
447        Identifies the shape of the argument.
448    
449        @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    
457        if isinstance(arg,numarray.NumArray):
458            return arg.shape
459        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:
468          raise TypeError,"getShape: Cannot identify shape"
469    
470    def pokeDim(arg):
471        """
472        Identifies the spatial dimension of the argument.
473    
474        @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    
480        if isinstance(arg,escript.Data):
481            return arg.getFunctionSpace().getDim()
482        elif isinstance(arg,Symbol):
483            return arg.getDim()
484        else:
485            return None
486    
487    def commonShape(arg0, arg1):
488        """
489        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 arg0: an object with a shape (see L{getShape})
493        @param arg1: an object with a shape (see L{getShape})
494        @return: the shape of C{arg0} or C{arg1} such that the left part equals the
495                 shape of C{arg0} and the right end equals the shape of C{arg1}
496        @rtype: C{tuple} of C{int}
497        @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:
510           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 testForZero(arg):
538        """
539        Tests if the argument is identical to zero.
540    
541        @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,numarray.NumArray):
547           return not Lsup(arg)>0.
548        elif isinstance(arg,escript.Data):
549           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:
557           return False
558    
559    def matchType(arg0=0.,arg1=0.):
560        """
561        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    def matchShape(arg0,arg1):
651        """
652        Returns a representation of C{arg0} and C{arg1} which have the same shape.
653    
654        @param arg0: first argument
655        @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:
670           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         self.__args=args
        self.__name=name  
700         self.__shape=shape         self.__shape=shape
701         if hasattr(dim,"getDim"):         self.__dim=dim
            self.__dim=dim.getDim()  
        else:      
            self.__dim=dim  
        #  
        self.__cache_val=None  
        self.__cache_argval=None  
702    
703     def getArgument(self,i):     def getArgument(self,i=None):
        """  
        Returns the i-th argument.  
704         """         """
705         return self.__args[i]         Returns the i-th argument of the symbol.
706    
707     def getDim(self):         @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         Returns the spatial dimension of the symbol.         if i==None:
715         """            return self.__args
716         return self.__dim         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):     def getRank(self):
722         """         """
723         Returns the rank of the symbol.         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())         return len(self.getShape())
729    
730     def getShape(self):     def getShape(self):
731         """         """
732         Returns the shape of the symbol.         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         return self.__shape
738    
739     def getEvaluatedArguments(self,argval):     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         Returns the list of evaluated arguments by subsituting symbol u by         return self.__dim
747         argval[u].  
748       def __str__(self):
749         """         """
750         if argval==self.__cache_argval:         Returns a string representation of the symbol.
            print "%s: cached value used"%self  
            return self.__cache_val  
        else:  
            out=[]  
            for a  in self.__args:  
               if isinstance(a,Symbol):  
                 out.append(a.eval(argval))  
               else:  
                 out.append(a)  
            self.__cache_argval=argval  
            self.__cache_val=out  
            return out  
751    
752     def getDifferentiatedArguments(self,arg):         @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         """         """
        Returns the list of the arguments _differentiated by arg.  
        """  
778         out=[]         out=[]
779         for a in self.__args:         for a in self.getArgument():
780            if isinstance(a,Symbol):            if isinstance(a,Symbol):
781              out.append(a.diff(arg))               out.append(a.substitute(argvals))
782            else:            else:
783              out.append(0)               out.append(a)
784         return out         return out
785    
786     def diff(self,arg):     def getDifferentiatedArguments(self,arg):
787         """         """
788         Returns the _differention of self by arg.         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         if self==arg:         out=[]
800            out=numarray.zeros(tuple(2*list(self.getShape())),numarray.Float)         for a in self.getArgument():
801            if self.getRank()==0:            if isinstance(a,Symbol):
802               out=1.               out.append(a.substitute(argvals))
           elif self.getRank()==1:  
               for i0 in range(self.getShape()[0]):  
                  out[i0,i0]=1.    
           elif self.getRank()==2:  
               for i0 in range(self.getShape()[0]):  
                 for i1 in range(self.getShape()[1]):  
                      out[i0,i1,i0,i1]=1.    
           elif self.getRank()==3:  
               for i0 in range(self.getShape()[0]):  
                 for i1 in range(self.getShape()[1]):  
                   for i2 in range(self.getShape()[2]):  
                      out[i0,i1,i2,i0,i1,i2]=1.    
           elif self.getRank()==4:  
               for i0 in range(self.getShape()[0]):  
                 for i1 in range(self.getShape()[1]):  
                   for i2 in range(self.getShape()[2]):  
                     for i3 in range(self.getShape()[3]):  
                        out[i0,i1,i2,i3,i0,i1,i2,i3]=1.    
803            else:            else:
804               raise ValueError,"differential support rank<5 only."                s=getShape(s)+arg.getShape()
805            return out                if len(s)>0:
806         else:                   out.append(numarray.zeros(s),numarray.Float64)
807            return self._diff(arg)                else:
808                     out.append(a)
809           return out
810    
811     def _diff(self,arg):     def isAppropriateValue(self,arg):
812         """        """
813         Return derivate of self with respect to arg (!=self).        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         This method is overwritten by a particular symbol.     def getMyCode(self,argstrs,format="escript"):
848         """         """
849         return 0         Returns program code that can be used to evaluate the symbol.
850    
851     def eval(self,argval):         @param argstrs: a string for each argument representing the argument
852         """                         for the evaluation
853         Subsitutes symbol u in self by argval[u] and returns the result. If         @type argstrs: C{list} of C{str}
854         self is not a key of argval then self is returned.         @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         if argval.has_key(self):         raise NotImplementedError,"no code for %s representation available"%format
          return argval[self]  
        else:  
          return self  
865    
866     def __str__(self):     def substitute(self,argvals):
867         """        """
868         Returns a string representation of the symbol.        Assigns new values to symbols in the definition of the symbol.
        """  
        return self.__name  
869    
870     def __add__(self,other):        The method replaces the L{Symbol} u by argvals[u] in the expression
871         """        defining this object.
        Adds other to symbol self. if _testForZero(other) self is returned.  
        """  
        if _testForZero(other):  
           return self  
        else:  
           a=_matchShape([self,other])  
           return Add_Symbol(a[0],a[1])  
872    
873     def __radd__(self,other):        @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         Adds other to symbol self. if _testForZero(other) self is returned.         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         return self+other         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):     def __neg__(self):
916         """         """
917         Returns -self.         Returns -self.
918    
919           @return: a L{Symbol} representing the negative of the object
920           @rtype: L{DependendSymbol}
921         """         """
922         return self*(-1.)         return self*(-1.)
923    
924     def __pos__(self):     def __pos__(self):
925         """         """
926         Returns +self.         Returns +self.
927    
928           @return: a L{Symbol} representing the positive of the object
929           @rtype: L{DependendSymbol}
930         """         """
931         return self         return self*(1.)
932    
933     def __abs__(self):     def __abs__(self):
934         """         """
935         Returns absolute value.         Returns a L{Symbol} representing the absolute value of the object.
936         """         """
937         return Abs_Symbol(self)         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):     def __sub__(self,other):
964         """         """
965         Subtracts other from symbol self.         Subtracts another object from this object.
966          
967         If _testForZero(other) self is returned.         @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         if _testForZero(other):         return add(self,-other)
           return self  
        else:  
           return self+(-other)  
975    
976     def __rsub__(self,other):     def __rsub__(self,other):
977         """         """
978         Subtracts symbol self from other.         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 -self+other         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):     def __div__(self,other):
1014         """         """
1015         Divides symbol self by other.         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         if isinstance(other,Symbol):         return quotient(self,other)
           a=_matchShape([self,other])  
           return Div_Symbol(a[0],a[1])  
        else:  
           return self*(1./other)  
1025    
1026     def __rdiv__(self,other):     def __rdiv__(self,other):
1027         """         """
1028         Dived other by symbol self. if _testForZero(other) 0 is returned.         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         if _testForZero(other):         return quotient(other,self)
           return 0  
        else:  
           a=_matchShape([self,other])  
           return Div_Symbol(a[0],a[1])  
1038    
1039     def __pow__(self,other):     def __pow__(self,other):
1040         """         """
1041         Raises symbol self to the power of other.         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         a=_matchShape([self,other])         return power(self,other)
        return Power_Symbol(a[0],a[1])  
1050    
1051     def __rpow__(self,other):     def __rpow__(self,other):
1052         """         """
1053         Raises other to the symbol self.         Raises an object to the power of this object.
        """  
        a=_matchShape([self,other])  
        return Power_Symbol(a[1],a[0])  
1054    
1055     def __mul__(self,other):         @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         Multiplies other by symbol self. if _testForZero(other) 0 is returned.         return power(other,self)
        """  
        if _testForZero(other):  
           return 0  
        else:  
           a=_matchShape([self,other])  
           return Mult_Symbol(a[0],a[1])  
1062    
1063     def __rmul__(self,other):     def __getitem__(self,index):
1064         """         """
1065         Multiplies other by symbol self. if _testSForZero(other) 0 is returned.         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 self*other         return GetSlice_Symbol(self,index)
1073    
1074     def __getitem__(self,sl):  class DependendSymbol(Symbol):
1075            print sl     """
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  class Float_Symbol(Symbol):     Example::
     def __init__(self,name="symbol",shape=(),args=[]):  
         Symbol.__init__(self,dim=0,name="symbol",shape=(),args=[])  
1082    
1083  class ScalarSymbol(Symbol):       u1=Symbol(shape=(3,4),dim=2,args=[4.])
1084     """       u2=Symbol(shape=(3,4),dim=2,args=[4.])
1085     A scalar symbol.       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 __init__(self,dim=3,name="scalar"):     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        Creates a scalar symbol of spatial dimension dim.        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        if hasattr(dim,"getDim"):        Checks if C{other} is not equal to self.
            d=dim.getDim()  
       else:      
            d=dim  
       Symbol.__init__(self,shape=(),dim=d,name=name)  
1120    
1121  class VectorSymbol(Symbol):        @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     A vector symbol.     L{Symbol} representing getting a slice for a L{Symbol}.
1133     """     """
1134     def __init__(self,dim=3,name="vector"):     def __init__(self,arg,index):
1135        """        """
1136        Creates a vector symbol of spatial dimension dim.        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        if hasattr(dim,"getDim"):        Returns program code that can be used to evaluate the symbol.
1183             d=dim.getDim()  
1184        else:            @param argstrs: a string for each argument representing the argument
1185             d=dim                        for the evaluation
1186        Symbol.__init__(self,shape=(d,),dim=d,name=name)        @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  class TensorSymbol(Symbol):     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     A tensor symbol.     def __init__(self,arg):
1286     """        """
1287     def __init__(self,dim=3,name="tensor"):        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        Creates a tensor symbol of spatial dimension dim.        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 hasattr(dim,"getDim"):        if argvals.has_key(self):
1332             d=dim.getDim()           arg=argvals[self]
1333        else:               if self.isAppropriateValue(arg):
1334             d=dim              return arg
1335        Symbol.__init__(self,shape=(d,d),dim=d,name=name)           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 Tensor3Symbol(Symbol):  class WhereNegative_Symbol(DependendSymbol):
1373     """     """
1374     A tensor order 3 symbol.     L{Symbol} representing the result of the mask of negative values function.
1375     """     """
1376     def __init__(self,dim=3,name="tensor3"):     def __init__(self,arg):
1377        """        """
1378        Creates a tensor order 3 symbol of spatial dimension dim.        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        if hasattr(dim,"getDim"):        Returns program code that can be used to evaluate the symbol.
1388             d=dim.getDim()  
1389        else:            @param argstrs: a string for each argument representing the argument
1390             d=dim                        for the evaluation
1391        Symbol.__init__(self,shape=(d,d,d),dim=d,name=name)        @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  class Tensor4Symbol(Symbol):     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     A tensor order 4 symbol.     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     def __init__(self,dim=3,name="tensor4"):     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        Creates a tensor order 4 symbol of spatial dimension dim.        if argvals.has_key(self):
1577        """           arg=argvals[self]
1578        if hasattr(dim,"getDim"):           if self.isAppropriateValue(arg):
1579             d=dim.getDim()              return arg
1580        else:               else:
1581             d=dim              raise TypeError,"%s: new value is not appropriate."%str(self)
1582        Symbol.__init__(self,shape=(d,d,d,d),dim=d,name=name)        else:
1583             arg=self.getSubstitutedArguments(argvals)
1584             return whereZero(arg[0],arg[1])
1585    
1586  class Add_Symbol(Symbol):  def whereNonZero(arg,tol=0.):
1587     """     """
1588     Symbol representing the sum of two arguments.     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     def __init__(self,arg0,arg1):     Returns the error function M{erf} of argument C{arg}.
        a=[arg0,arg1]  
        Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)  
    def __str__(self):  
       return "(%s+%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))  
    def eval(self,argval):  
        a=self.getEvaluatedArguments(argval)  
        return a[0]+a[1]  
    def _diff(self,arg):  
        a=self.getDifferentiatedArguments(arg)  
        return a[0]+a[1]  
1620    
1621  class Mult_Symbol(Symbol):     @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     Symbol representing the product of two arguments.     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     def __init__(self,arg0,arg1):     Returns sine of argument C{arg}.
        a=[arg0,arg1]  
        Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)  
    def __str__(self):  
       return "(%s*%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))  
    def eval(self,argval):  
        a=self.getEvaluatedArguments(argval)  
        return a[0]*a[1]  
    def _diff(self,arg):  
        a=self.getDifferentiatedArguments(arg)  
        return self.getArgument(1)*a[0]+self.getArgument(0)*a[1]  
1635    
1636  class Div_Symbol(Symbol):     @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     Symbol representing the quotient of two arguments.     L{Symbol} representing the result of the sine function.
1658     """     """
1659     def __init__(self,arg0,arg1):     def __init__(self,arg):
1660         a=[arg0,arg1]        """
1661         Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)        Initialization of sin L{Symbol} with argument C{arg}.
1662     def __str__(self):  
1663        return "(%s/%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))        @param arg: argument of function
1664     def eval(self,argval):        @type arg: typically L{Symbol}
1665         a=self.getEvaluatedArguments(argval)        """
1666         return a[0]/a[1]        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1667     def _diff(self,arg):  
1668         a=self.getDifferentiatedArguments(arg)     def getMyCode(self,argstrs,format="escript"):
1669         return (a[0]*self.getArgument(1)-self.getArgument(0)*a[1])/ \        """
1670                            (self.getArgument(1)*self.getArgument(1))        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  class Power_Symbol(Symbol):  def cos(arg):
1733     """     """
1734     Symbol representing the power of the first argument to the power of the     Returns cosine of argument C{arg}.
1735     second argument.  
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     def __init__(self,arg0,arg1):     L{Symbol} representing the result of the cosine function.
1758         a=[arg0,arg1]     """
1759         Symbol.__init__(self,dim=_extractDim(a),shape=_extractShape(a),args=a)     def __init__(self,arg):
1760     def __str__(self):        """
1761        return "(%s**%s)"%(str(self.getArgument(0)),str(self.getArgument(1)))        Initialization of cos L{Symbol} with argument C{arg}.
1762     def eval(self,argval):  
1763         a=self.getEvaluatedArguments(argval)        @param arg: argument of function
1764         return a[0]**a[1]        @type arg: typically L{Symbol}
1765     def _diff(self,arg):        """
1766         a=self.getDifferentiatedArguments(arg)        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
1767         return self*(a[1]*log(self.getArgument(0))+self.getArgument(1)/self.getArgument(0)*a[0])  
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  class Abs_Symbol(Symbol):     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     Symbol representing absolute value of its argument.     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):     def __init__(self,arg):
1860         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
1861     def __str__(self):        Initialization of tan L{Symbol} with argument C{arg}.
       return "abs(%s)"%str(self.getArgument(0))  
    def eval(self,argval):  
        return abs(self.getEvaluatedArguments(argval)[0])  
    def _diff(self,arg):  
        return sign(self.getArgument(0))*self.getDifferentiatedArguments(arg)[0]  
1862    
1863  #=========================================================        @param arg: argument of function
1864  #   some little helpers        @type arg: typically L{Symbol}
1865  #=========================================================        """
1866  def _testForZero(arg):        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     Returns True is arg is considered to be zero.     L{Symbol} representing the result of the inverse sine function.
1958     """     """
1959     if isinstance(arg,int):     def __init__(self,arg):
1960        return not arg>0        """
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):     elif isinstance(arg,float):
2047        return not arg>0.        return math.acos(arg)
2048     elif isinstance(arg,numarray.NumArray):     elif isinstance(arg,int):
2049        a=abs(arg)        return math.acos(arg)
2050        while isinstance(a,numarray.NumArray): a=numarray.sometrue(a)     elif isinstance(arg,Symbol):
2051        return not a>0        return Acos_Symbol(arg)
2052     else:     else:
2053        return False        raise TypeError,"acos: Unknown argument type."
2054    
2055  def _extractDim(args):  class Acos_Symbol(DependendSymbol):
2056      dim=None     """
2057      for a in args:     L{Symbol} representing the result of the inverse cosine function.
2058         if hasattr(a,"getDim"):     """
2059            d=a.getDim()     def __init__(self,arg):
2060            if dim==None:        """
2061               dim=d        Initialization of acos L{Symbol} with argument C{arg}.
           else:  
              if dim!=d: raise ValueError,"inconsistent spatial dimension of arguments"  
     if dim==None:  
        raise ValueError,"cannot recover spatial dimension"  
     return dim  
2062    
2063  def _identifyShape(arg):        @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):
2133       """
2134       Returns inverse tangent of argument C{arg}.
2135    
2136       @param arg: argument
2137       @type arg: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray}
2138       @rtype: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray} depending
2139               on the type of C{arg}
2140       @raises TypeError: if the type of the argument is not expected
2141       """
2142       if isinstance(arg,numarray.NumArray):
2143          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     Identifies the shape of arg.     L{Symbol} representing the result of the inverse tangent function.
2158     """     """
2159     if hasattr(arg,"getShape"):     def __init__(self,arg):
2160         arg_shape=arg.getShape()        """
2161     elif hasattr(arg,"shape"):        Initialization of atan L{Symbol} with argument C{arg}.
2162       s=arg.shape  
2163       if callable(s):        @param arg: argument of function
2164         arg_shape=s()        @type arg: typically L{Symbol}
2165       else:        """
2166         arg_shape=s        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):
2233       """
2234       Returns the hyperbolic sine of argument C{arg}.
2235    
2236       @param arg: argument
2237       @type arg: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray}
2238       @rtype: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray} depending
2239               on the type of C{arg}
2240       @raises TypeError: if the type of the argument is not expected
2241       """
2242       if isinstance(arg,numarray.NumArray):
2243          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:     else:
2253         arg_shape=()        raise TypeError,"sinh: Unknown argument type."
    return arg_shape  
2254    
2255  def _extractShape(args):  class Sinh_Symbol(DependendSymbol):
2256      """     """
2257      Extracts the common shape of the list of arguments args.     L{Symbol} representing the result of the hyperbolic sine function.
2258      """     """
2259      shape=None     def __init__(self,arg):
2260      for a in args:        """
2261         a_shape=_identifyShape(a)        Initialization of sinh L{Symbol} with argument C{arg}.
        if shape==None: shape=a_shape  
        if shape!=a_shape: raise ValueError,"inconsistent shape"  
     if shape==None:  
        raise ValueError,"cannot recover shape"  
     return shape  
   
 def _matchShape(args,shape=None):  
     """  
     Returns the list of arguments args as object which have all the  
     specified shape.  
   
     If shape is not given the shape "largest" shape of args is used.  
     """  
     # identify the list of shapes:  
     arg_shapes=[]  
     for a in args: arg_shapes.append(_identifyShape(a))  
     # get the largest shape (currently the longest shape):  
     if shape==None: shape=max(arg_shapes)  
       
     out=[]  
     for i in range(len(args)):  
        if shape==arg_shapes[i]:  
           out.append(args[i])  
        else:  
           if len(shape)==0: # then len(arg_shapes[i])>0  
             raise ValueError,"cannot adopt shape of %s to %s"%(str(args[i]),str(shape))  
           else:  
             if len(arg_shapes[i])==0:  
                 out.append(outer(args[i],numarray.ones(shape)))          
             else:    
                 raise ValueError,"cannot adopt shape of %s to %s"%(str(args[i]),str(shape))  
     return out    
2262    
2263  #=========================================================        @param arg: argument of function
2264  #   wrappers for various mathematical functions:        @type arg: typically L{Symbol}
2265  #=========================================================        """
2266  def diff(arg,dep):        DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
     """  
     Returns the derivative of arg with respect to dep.  
       
     If arg is not Symbol object 0 is returned.  
     """  
     if isinstance(arg,Symbol):  
        return arg.diff(dep)  
     elif hasattr(arg,"shape"):  
           if callable(arg.shape):  
               return numarray.zeros(arg.shape(),numarray.Float)  
           else:  
               return numarray.zeros(arg.shape,numarray.Float)  
     else:  
        return 0  
2267    
2268  def exp(arg):     def getMyCode(self,argstrs,format="escript"):
2269      """        """
2270      Applies the exponential function to arg.        Returns program code that can be used to evaluate the symbol.
2271    
2272      @param arg: argument        @param argstrs: a string for each argument representing the argument
2273      """                        for the evaluation
2274      if isinstance(arg,Symbol):        @type argstrs: C{str} or a C{list} of length 1 of C{str}
2275         return Exp_Symbol(arg)        @param format: specifies the format to be used. At the moment only
2276      elif hasattr(arg,"exp"):                       "escript", "str" and "text" are supported.
2277         return arg.exp()        @type format: C{str}
2278      else:        @return: a piece of program code which can be used to evaluate the
2279         return numarray.exp(arg)                 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  class Exp_Symbol(Symbol):     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):
2333       """
2334       Returns the hyperbolic cosine of argument C{arg}.
2335    
2336       @param arg: argument
2337       @type arg: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray}
2338       @rtype: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray} depending
2339               on the type of C{arg}
2340       @raises TypeError: if the type of the argument is not expected
2341       """
2342       if isinstance(arg,numarray.NumArray):
2343          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     Symbol representing the power of the first argument to the power of the     L{Symbol} representing the result of the hyperbolic cosine function.
    second argument.  
2358     """     """
2359     def __init__(self,arg):     def __init__(self,arg):
2360         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2361     def __str__(self):        Initialization of cosh L{Symbol} with argument C{arg}.
       return "exp(%s)"%str(self.getArgument(0))  
    def eval(self,argval):  
        return exp(self.getEvaluatedArguments(argval)[0])  
    def _diff(self,arg):  
        return self*self.getDifferentiatedArguments(arg)[0]  
2362    
2363  def sqrt(arg):        @param arg: argument of function
2364      """        @type arg: typically L{Symbol}
2365      Applies the squre root function to arg.        """
2366          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2367    
2368      @param arg: argument     def getMyCode(self,argstrs,format="escript"):
2369      """        """
2370      if isinstance(arg,Symbol):        Returns program code that can be used to evaluate the symbol.
        return Sqrt_Symbol(arg)  
     elif hasattr(arg,"sqrt"):  
        return arg.sqrt()  
     else:  
        return numarray.sqrt(arg)        
2371    
2372  class Sqrt_Symbol(Symbol):        @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):
2433       """
2434       Returns the hyperbolic tangent of argument C{arg}.
2435    
2436       @param arg: argument
2437       @type arg: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray}
2438       @rtype: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray} depending
2439               on the type of C{arg}
2440       @raises TypeError: if the type of the argument is not expected
2441       """
2442       if isinstance(arg,numarray.NumArray):
2443          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     Symbol representing square root of argument.     L{Symbol} representing the result of the hyperbolic tangent function.
2458     """     """
2459     def __init__(self,arg):     def __init__(self,arg):
2460         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2461     def __str__(self):        Initialization of tanh L{Symbol} with argument C{arg}.
       return "sqrt(%s)"%str(self.getArgument(0))  
    def eval(self,argval):  
        return sqrt(self.getEvaluatedArguments(argval)[0])  
    def _diff(self,arg):  
        return (-0.5)/self*self.getDifferentiatedArguments(arg)[0]  
2462    
2463  def log(arg):        @param arg: argument of function
2464      """        @type arg: typically L{Symbol}
2465      Applies the logarithmic function bases exp(1.) to arg        """
2466          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2467    
2468      @param arg: argument     def getMyCode(self,argstrs,format="escript"):
2469      """        """
2470      if isinstance(arg,Symbol):        Returns program code that can be used to evaluate the symbol.
2471         return Log_Symbol(arg)  
2472      elif hasattr(arg,"log"):        @param argstrs: a string for each argument representing the argument
2473         return arg.log()                        for the evaluation
2474      else:        @type argstrs: C{str} or a C{list} of length 1 of C{str}
2475         return numarray.log(arg)        @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  class Log_Symbol(Symbol):     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):
2533       """
2534       Returns the inverse hyperbolic sine of argument C{arg}.
2535    
2536       @param arg: argument
2537       @type arg: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray}
2538       @rtype: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray} depending
2539               on the type of C{arg}
2540       @raises TypeError: if the type of the argument is not expected
2541       """
2542       if isinstance(arg,numarray.NumArray):
2543          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     Symbol representing logarithm of the argument.     L{Symbol} representing the result of the inverse hyperbolic sine function.
2558     """     """
2559     def __init__(self,arg):     def __init__(self,arg):
2560         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2561     def __str__(self):        Initialization of asinh L{Symbol} with argument C{arg}.
       return "log(%s)"%str(self.getArgument(0))  
    def eval(self,argval):  
        return log(self.getEvaluatedArguments(argval)[0])  
    def _diff(self,arg):  
        return self.getDifferentiatedArguments(arg)[0]/self.getArgument(0)  
2562    
2563  def ln(arg):        @param arg: argument of function
2564      """        @type arg: typically L{Symbol}
2565      Applies the natural logarithmic function to arg.        """
2566          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2567    
2568      @param arg: argument     def getMyCode(self,argstrs,format="escript"):
2569      """        """
2570      if isinstance(arg,Symbol):        Returns program code that can be used to evaluate the symbol.
2571         return Ln_Symbol(arg)  
2572      elif hasattr(arg,"ln"):        @param argstrs: a string for each argument representing the argument
2573         return arg.log()                        for the evaluation
2574      else:        @type argstrs: C{str} or a C{list} of length 1 of C{str}
2575         return numarray.log(arg)        @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):
2633       """
2634       Returns the inverse hyperbolic cosine of argument C{arg}.
2635    
2636       @param arg: argument
2637       @type arg: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray}
2638       @rtype: C{float}, L{escript.Data}, L{Symbol}, C{numarray.NumArray} depending
2639               on the type of C{arg}
2640       @raises TypeError: if the type of the argument is not expected
2641       """
2642       if isinstance(arg,numarray.NumArray):
2643          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 Ln_Symbol(Symbol):  class Acosh_Symbol(DependendSymbol):
2656     """     """
2657     Symbol representing natural logarithm of the argument.     L{Symbol} representing the result of the inverse hyperbolic cosine function.
2658     """     """
2659     def __init__(self,arg):     def __init__(self,arg):
2660         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2661     def __str__(self):        Initialization of acosh L{Symbol} with argument C{arg}.
       return "ln(%s)"%str(self.getArgument(0))  
    def eval(self,argval):  
        return ln(self.getEvaluatedArguments(argval)[0])  
    def _diff(self,arg):  
        return self.getDifferentiatedArguments(arg)[0]/self.getArgument(0)  
2662    
2663  def sin(arg):        @param arg: argument of function
2664      """        @type arg: typically L{Symbol}
2665      Applies the sin function to arg.        """
2666          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2667    
2668      @param arg: argument     def getMyCode(self,argstrs,format="escript"):
2669      """        """
2670      if isinstance(arg,Symbol):        Returns program code that can be used to evaluate the symbol.
2671         return Sin_Symbol(arg)  
2672      elif hasattr(arg,"sin"):        @param argstrs: a string for each argument representing the argument
2673         return arg.sin()                        for the evaluation
2674      else:        @type argstrs: C{str} or a C{list} of length 1 of C{str}
2675         return numarray.sin(arg)        @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):
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 Sin_Symbol(Symbol):  class Atanh_Symbol(DependendSymbol):
2756     """     """
2757     Symbol representing sin of the argument.     L{Symbol} representing the result of the inverse hyperbolic tangent function.
2758     """     """
2759     def __init__(self,arg):     def __init__(self,arg):
2760         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2761     def __str__(self):        Initialization of atanh L{Symbol} with argument C{arg}.
       return "sin(%s)"%str(self.getArgument(0))  
    def eval(self,argval):  
        return sin(self.getEvaluatedArguments(argval)[0])  
    def _diff(self,arg):  
        return cos(self.getArgument(0))*self.getDifferentiatedArguments(arg)[0]  
2762    
2763  def cos(arg):        @param arg: argument of function
2764      """        @type arg: typically L{Symbol}
2765      Applies the cos function to arg.        """
2766          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2767    
2768      @param arg: argument     def getMyCode(self,argstrs,format="escript"):
2769      """        """
2770      if isinstance(arg,Symbol):        Returns program code that can be used to evaluate the symbol.
2771         return Cos_Symbol(arg)  
2772      elif hasattr(arg,"cos"):        @param argstrs: a string for each argument representing the argument
2773         return arg.cos()                        for the evaluation
2774      else:        @type argstrs: C{str} or a C{list} of length 1 of C{str}
2775         return numarray.cos(arg)        @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  class Cos_Symbol(Symbol):     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     Symbol representing cos of the argument.     L{Symbol} representing the result of the exponential function.
2858     """     """
2859     def __init__(self,arg):     def __init__(self,arg):
2860         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2861     def __str__(self):        Initialization of exp L{Symbol} with argument C{arg}.
       return "cos(%s)"%str(self.getArgument(0))  
    def eval(self,argval):  
        return cos(self.getEvaluatedArguments(argval)[0])  
    def _diff(self,arg):  
        return -sin(self.getArgument(0))*self.getDifferentiatedArguments(arg)[0]  
2862    
2863  def tan(arg):        @param arg: argument of function
2864      """        @type arg: typically L{Symbol}
2865      Applies the tan function to arg.        """
2866          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2867    
2868      @param arg: argument     def getMyCode(self,argstrs,format="escript"):
2869      """        """
2870      if isinstance(arg,Symbol):        Returns program code that can be used to evaluate the symbol.
        return Tan_Symbol(arg)  
     elif hasattr(arg,"tan"):  
        return arg.tan()  
     else:  
        return numarray.tan(arg)  
2871    
2872  class Tan_Symbol(Symbol):        @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     Symbol representing tan of the argument.     L{Symbol} representing the result of the square root function.
2958     """     """
2959     def __init__(self,arg):     def __init__(self,arg):
2960         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
2961     def __str__(self):        Initialization of sqrt L{Symbol} with argument C{arg}.
       return "tan(%s)"%str(self.getArgument(0))  
    def eval(self,argval):  
        return tan(self.getEvaluatedArguments(argval)[0])  
    def _diff(self,arg):  
        s=cos(self.getArgument(0))  
        return 1./(s*s)*self.getDifferentiatedArguments(arg)[0]  
2962    
2963  def sign(arg):        @param arg: argument of function
2964      """        @type arg: typically L{Symbol}
2965      Applies the sign function to arg.        """
2966          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
2967    
2968      @param arg: argument     def getMyCode(self,argstrs,format="escript"):
2969      """        """
2970      if isinstance(arg,Symbol):        Returns program code that can be used to evaluate the symbol.
2971         return Sign_Symbol(arg)  
2972      elif hasattr(arg,"sign"):        @param argstrs: a string for each argument representing the argument
2973         return arg.sign()                        for the evaluation
2974      else:        @type argstrs: C{str} or a C{list} of length 1 of C{str}
2975         return numarray.greater(arg,numarray.zeros(arg.shape,numarray.Float))- \        @param format: specifies the format to be used. At the moment only
2976                numarray.less(arg,numarray.zeros(arg.shape,numarray.Float))                       "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  class Sign_Symbol(Symbol):  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     Symbol representing the sign of the argument.     L{Symbol} representing the result of the natural logarithm function.
3058     """     """
3059     def __init__(self,arg):     def __init__(self,arg):
3060         Symbol.__init__(self,shape=arg.getShape(),dim=arg.getDim(),args=[arg])        """
3061     def __str__(self):        Initialization of log L{Symbol} with argument C{arg}.
       return "sign(%s)"%str(self.getArgument(0))  
    def eval(self,argval):  
        return sign(self.getEvaluatedArguments(argval)[0])  
3062    
3063  def maxval(arg):        @param arg: argument of function
3064      """        @type arg: typically L{Symbol}
3065      Returns the maximum value of argument arg.        """
3066          DependendSymbol.__init__(self,args=[arg],shape=arg.getShape(),dim=arg.getDim())
3067    
3068      @param arg: argument     def getMyCode(self,argstrs,format="escript"):
3069      """        """
3070      if isinstance(arg,Symbol):        Returns program code that can be used to evaluate the symbol.
3071         return Max_Symbol(arg)  
3072      elif hasattr(arg,"maxval"):        @param argstrs: a string for each argument representing the argument
3073         return arg.maxval()                        for the evaluation
3074      elif hasattr(arg,"max"):        @type argstrs: C{str} or a C{list} of length 1 of C{str}
3075         return arg.max()        @param format: specifies the format to be used. At the moment only
3076      else:                       "escript", "str" and "text" are supported.
3077         return arg        @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.