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

revision 329 by gross, Wed Dec 7 04:42:43 2005 UTC revision 529 by gross, Wed Feb 15 03:58:50 2006 UTC
# Line 30  __date__="\$Date\$" Line 30  __date__="\$Date\$"
30
31  import math  import math
32  import numarray  import numarray
33    import numarray.linear_algebra
34  import escript  import escript
35  import os  import os
36
# Line 43  import os Line 44  import os
44  # def matchType(arg0=0.,arg1=0.):  # def matchType(arg0=0.,arg1=0.):
45  # def matchShape(arg0,arg1):  # def matchShape(arg0,arg1):
46
# def maximum(arg0,arg1):
# def minimum(arg0,arg1):

# def transpose(arg,axis=None):
# def trace(arg,axis0=0,axis1=1):
47  # def reorderComponents(arg,index):  # def reorderComponents(arg,index):
48
# def integrate(arg,where=None):
# def interpolate(arg,where):
# def div(arg,where=None):

49  #  #
50  # slicing: get  # slicing: get
51  #          set  #          set
# Line 125  def kronecker(d=3): Line 116  def kronecker(d=3):
116     return the kronecker S{delta}-symbol     return the kronecker S{delta}-symbol
117
118     @param d: dimension or an object that has the C{getDim} method defining the dimension     @param d: dimension or an object that has the C{getDim} method defining the dimension
119     @type d: C{int} or any object with a C{getDim} method     @type d: C{int}, L{escript.Domain} or L{escript.FunctionSpace}
120     @return: the object u of rank 2 with M{u[i,j]=1} for M{i=j} and M{u[i,j]=0} otherwise     @return: the object u of rank 2 with M{u[i,j]=1} for M{i=j} and M{u[i,j]=0} otherwise
121     @rtype d: L{numarray.NumArray} of rank 2.     @rtype d: L{numarray.NumArray} or L{escript.Data} of rank 2.
@remark: the function is identical L{identity}
122     """     """
123     return identityTensor(d)     return identityTensor(d)
124
# Line 147  def identity(shape=()): Line 137  def identity(shape=()):
137        if len(shape)==1:        if len(shape)==1:
138            for i0 in range(shape[0]):            for i0 in range(shape[0]):
139               out[i0,i0]=1.               out[i0,i0]=1.

140        elif len(shape)==2:        elif len(shape)==2:
141            for i0 in range(shape[0]):            for i0 in range(shape[0]):
142               for i1 in range(shape[1]):               for i1 in range(shape[1]):
# Line 163  def identityTensor(d=3): Line 152  def identityTensor(d=3):
152     return the dxd identity matrix     return the dxd identity matrix
153
154     @param d: dimension or an object that has the C{getDim} method defining the dimension     @param d: dimension or an object that has the C{getDim} method defining the dimension
155     @type d: C{int} or any object with a C{getDim} method     @type d: C{int}, L{escript.Domain} or L{escript.FunctionSpace}
156     @return: the object u of rank 2 with M{u[i,j]=1} for M{i=j} and M{u[i,j]=0} otherwise     @return: the object u of rank 2 with M{u[i,j]=1} for M{i=j} and M{u[i,j]=0} otherwise
157     @rtype: L{numarray.NumArray} of rank 2.     @rtype d: L{numarray.NumArray} or L{escript.Data} of rank 2
158     """     """
159     if hasattr(d,"getDim"):     if isinstance(d,escript.FunctionSpace):
160        d=d.getDim()         return escript.Data(identity((d.getDim(),)),d)
161     return identity(shape=(d,))     elif isinstance(d,escript.Domain):
162           return identity((d.getDim(),))
163       else:
164           return identity((d,))
165
166  def identityTensor4(d=3):  def identityTensor4(d=3):
167     """     """
# Line 178  def identityTensor4(d=3): Line 170  def identityTensor4(d=3):
170     @param d: dimension or an object that has the C{getDim} method defining the dimension     @param d: dimension or an object that has the C{getDim} method defining the dimension
171     @type d: C{int} or any object with a C{getDim} method     @type d: C{int} or any object with a C{getDim} method
172     @return: the object u of rank 4 with M{u[i,j,k,l]=1} for M{i=k and j=l} and M{u[i,j,k,l]=0} otherwise     @return: the object u of rank 4 with M{u[i,j,k,l]=1} for M{i=k and j=l} and M{u[i,j,k,l]=0} otherwise
173     @rtype: L{numarray.NumArray} of rank 4.     @rtype d: L{numarray.NumArray} or L{escript.Data} of rank 4.
174     """     """
175     if hasattr(d,"getDim"):     if isinstance(d,escript.FunctionSpace):
176        d=d.getDim()         return escript.Data(identity((d.getDim(),d.getDim())),d)
177     return identity((d,d))     elif isinstance(d,escript.Domain):
178           return identity((d.getDim(),d.getDim()))
179       else:
180           return identity((d,d))
181
182  def unitVector(i=0,d=3):  def unitVector(i=0,d=3):
183     """     """
# Line 191  def unitVector(i=0,d=3): Line 186  def unitVector(i=0,d=3):
186     @param i: index     @param i: index
187     @type i: C{int}     @type i: C{int}
188     @param d: dimension or an object that has the C{getDim} method defining the dimension     @param d: dimension or an object that has the C{getDim} method defining the dimension
189     @type d: C{int} or any object with a C{getDim} method     @type d: C{int}, L{escript.Domain} or L{escript.FunctionSpace}
190     @return: the object u of rank 1 with M{u[j]=1} for M{j=i} and M{u[i]=0} otherwise     @return: the object u of rank 1 with M{u[j]=1} for M{j=i} and M{u[i]=0} otherwise
191     @rtype: L{numarray.NumArray} of rank 1.     @rtype d: L{numarray.NumArray} or L{escript.Data} of rank 1
192     """     """
193     return kronecker(d)[i]     return kronecker(d)[i]
194
# Line 363  def testForZero(arg): Line 358  def testForZero(arg):
358      @return : True if the argument is identical to zero.      @return : True if the argument is identical to zero.
359      @rtype : C{bool}      @rtype : C{bool}
360      """      """
361      try:      if isinstance(arg,numarray.NumArray):
362           return not Lsup(arg)>0.
363        elif isinstance(arg,escript.Data):
364           return False
365        elif isinstance(arg,float):
366           return not Lsup(arg)>0.
367        elif isinstance(arg,int):
368         return not Lsup(arg)>0.         return not Lsup(arg)>0.
369      except TypeError:      elif isinstance(arg,Symbol):
370           return False
371        else:
372         return False         return False
373
374  def matchType(arg0=0.,arg1=0.):  def matchType(arg0=0.,arg1=0.):
# Line 825  class Symbol(object): Line 828  class Symbol(object):
828         """         """
829         return power(other,self)         return power(other,self)
830
831       def __getitem__(self,index):
832           """
833           returns the slice defined by index
834
835           @param index: defines a
836           @type index: C{slice} or C{int} or a C{tuple} of them
837           @return: a S{Symbol} representing the slice defined by index
838           @rtype: L{DependendSymbol}
839           """
840           return GetSlice_Symbol(self,index)
841
842  class DependendSymbol(Symbol):  class DependendSymbol(Symbol):
843     """     """
844     DependendSymbol extents L{Symbol} by modifying the == operator to allow two instances to be equal.     DependendSymbol extents L{Symbol} by modifying the == operator to allow two instances to be equal.
# Line 875  class DependendSymbol(Symbol): Line 889  class DependendSymbol(Symbol):
889  #=========================================================  #=========================================================
890  #  Unary operations prserving the shape  #  Unary operations prserving the shape
891  #========================================================  #========================================================
892    class GetSlice_Symbol(DependendSymbol):
893       """
894       L{Symbol} representing getting a slice for a L{Symbol}
895       """
896       def __init__(self,arg,index):
897          """
898          initialization of wherePositive L{Symbol} with argument arg
899          @param arg: argument
900          @type arg: L{Symbol}.
901          @param index: defines index
902          @type index: C{slice} or C{int} or a C{tuple} of them
903          @raises IndexError: if length of index is larger than rank of arg or a index start or stop is out of range
904          @raises ValueError: if a step is given
905          """
906          if not isinstance(index,tuple): index=(index,)
907          if len(index)>arg.getRank():
908               raise IndexError,"GetSlice_Symbol: index out of range."
909          sh=()
910          index2=()
911          for i in range(len(index)):
912             ix=index[i]
913             if isinstance(ix,int):
914                if ix<0 or ix>=arg.getShape()[i]:
915                   raise ValueError,"GetSlice_Symbol: index out of range."
916                index2=index2+(ix,)
917             else:
918               if not ix.step==None:
919                 raise ValueError,"GetSlice_Symbol: steping is not supported."
920               if ix.start==None:
921                  s=0
922               else:
923                  s=ix.start
924               if ix.stop==None:
925                  e=arg.getShape()[i]
926               else:
927                  e=ix.stop
928                  if e>arg.getShape()[i]:
929                     raise IndexError,"GetSlice_Symbol: index out of range."
930               index2=index2+(slice(s,e),)
931               if e>s:
932                   sh=sh+(e-s,)
933               elif s>e:
934                   raise IndexError,"GetSlice_Symbol: slice start must be less or equal slice end"
935          for i in range(len(index),arg.getRank()):
936              index2=index2+(slice(0,arg.getShape()[i]),)
937              sh=sh+(arg.getShape()[i],)
938          super(GetSlice_Symbol, self).__init__(args=[arg,index2],shape=sh,dim=arg.getDim())
939
940       def getMyCode(self,argstrs,format="escript"):
941          """
942          returns a program code that can be used to evaluate the symbol.
943
944          @param argstrs: gives for each argument a string representing the argument for the evaluation.
945          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
946          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
947          @type format: C{str}
948          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
949          @rtype: C{str}
950          @raise: NotImplementedError: if the requested format is not available
951          """
952          if format=="escript" or format=="str"  or format=="text":
953             return "%s.__getitem__(%s)"%(argstrs[0],argstrs[1])
954          else:
955             raise NotImplementedError,"GetItem_Symbol does not provide program code for format %s."%format
956
957       def substitute(self,argvals):
958          """
959          assigns new values to symbols in the definition of the symbol.
960          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
961
962          @param argvals: new values assigned to symbols
963          @type argvals: C{dict} with keywords of type L{Symbol}.
964          @return: result of the substitution process. Operations are executed as much as possible.
965          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
966          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
967          """
968          if argvals.has_key(self):
969             arg=argvals[self]
970             if self.isAppropriateValue(arg):
971                return arg
972             else:
973                raise TypeError,"%s: new value is not appropriate."%str(self)
974          else:
975             args=self.getSubstitutedArguments(argvals)
976             arg=args[0]
977             index=args[1]
978             return arg.__getitem__(index)
979
980  def log10(arg):  def log10(arg):
981     """     """
982     returns base-10 logarithm of argument arg     returns base-10 logarithm of argument arg
# Line 907  def wherePositive(arg): Line 1009  def wherePositive(arg):
1009     @raises TypeError: if the type of the argument is not expected.     @raises TypeError: if the type of the argument is not expected.
1010     """     """
1011     if isinstance(arg,numarray.NumArray):     if isinstance(arg,numarray.NumArray):
1012        return numarray.greater(arg,numarray.zeros(arg.shape,numarray.Float))        out=numarray.greater(arg,numarray.zeros(arg.shape,numarray.Float))*1.
1013          if isinstance(out,float): out=numarray.array(out)
1014          return out
1015     elif isinstance(arg,escript.Data):     elif isinstance(arg,escript.Data):
1016        return arg._wherePositive()        return arg._wherePositive()
1017     elif isinstance(arg,float):     elif isinstance(arg,float):
# Line 987  def whereNegative(arg): Line 1091  def whereNegative(arg):
1091     @raises TypeError: if the type of the argument is not expected.     @raises TypeError: if the type of the argument is not expected.
1092     """     """
1093     if isinstance(arg,numarray.NumArray):     if isinstance(arg,numarray.NumArray):
1094        return numarray.less(arg,numarray.zeros(arg.shape,numarray.Float))        out=numarray.less(arg,numarray.zeros(arg.shape,numarray.Float))*1.
1095          if isinstance(out,float): out=numarray.array(out)
1096          return out
1097     elif isinstance(arg,escript.Data):     elif isinstance(arg,escript.Data):
1098        return arg._whereNegative()        return arg._whereNegative()
1099     elif isinstance(arg,float):     elif isinstance(arg,float):
# Line 1067  def whereNonNegative(arg): Line 1173  def whereNonNegative(arg):
1173     @raises TypeError: if the type of the argument is not expected.     @raises TypeError: if the type of the argument is not expected.
1174     """     """
1175     if isinstance(arg,numarray.NumArray):     if isinstance(arg,numarray.NumArray):
1176        return numarray.greater_equal(arg,numarray.zeros(arg.shape,numarray.Float))        out=numarray.greater_equal(arg,numarray.zeros(arg.shape,numarray.Float))*1.
1177          if isinstance(out,float): out=numarray.array(out)
1178          return out
1179     elif isinstance(arg,escript.Data):     elif isinstance(arg,escript.Data):
1180        return arg._whereNonNegative()        return arg._whereNonNegative()
1181     elif isinstance(arg,float):     elif isinstance(arg,float):
# Line 1095  def whereNonPositive(arg): Line 1203  def whereNonPositive(arg):
1203     @raises TypeError: if the type of the argument is not expected.     @raises TypeError: if the type of the argument is not expected.
1204     """     """
1205     if isinstance(arg,numarray.NumArray):     if isinstance(arg,numarray.NumArray):
1206        return numarray.less_equal(arg,numarray.zeros(arg.shape,numarray.Float))        out=numarray.less_equal(arg,numarray.zeros(arg.shape,numarray.Float))*1.
1207          if isinstance(out,float): out=numarray.array(out)
1208          return out
1209     elif isinstance(arg,escript.Data):     elif isinstance(arg,escript.Data):
1210        return arg._whereNonPositive()        return arg._whereNonPositive()
1211     elif isinstance(arg,float):     elif isinstance(arg,float):
# Line 1125  def whereZero(arg,tol=0.): Line 1235  def whereZero(arg,tol=0.):
1235     @raises TypeError: if the type of the argument is not expected.     @raises TypeError: if the type of the argument is not expected.
1236     """     """
1237     if isinstance(arg,numarray.NumArray):     if isinstance(arg,numarray.NumArray):
1238        return numarray.less_equal(abs(arg)-tol,numarray.zeros(arg.shape,numarray.Float))        out=numarray.less_equal(abs(arg)-tol,numarray.zeros(arg.shape,numarray.Float))*1.
1239          if isinstance(out,float): out=numarray.array(out)
1240          return out
1241     elif isinstance(arg,escript.Data):     elif isinstance(arg,escript.Data):
1242        if tol>0.:        if tol>0.:
1243           return whereNegative(abs(arg)-tol)           return whereNegative(abs(arg)-tol)
# Line 1206  def whereNonZero(arg,tol=0.): Line 1318  def whereNonZero(arg,tol=0.):
1318     @raises TypeError: if the type of the argument is not expected.     @raises TypeError: if the type of the argument is not expected.
1319     """     """
1320     if isinstance(arg,numarray.NumArray):     if isinstance(arg,numarray.NumArray):
1321        return numarray.greater(abs(arg)-tol,numarray.zeros(arg.shape,numarray.Float))        out=numarray.greater(abs(arg)-tol,numarray.zeros(arg.shape,numarray.Float))*1.
1322          if isinstance(out,float): out=numarray.array(out)
1323          return out
1324     elif isinstance(arg,escript.Data):     elif isinstance(arg,escript.Data):
1325        if tol>0.:        if tol>0.:
1326           return 1.-whereZero(arg,tol)           return 1.-whereZero(arg,tol)
# Line 2687  def minval(arg): Line 2801  def minval(arg):
2801     @raises TypeError: if the type of the argument is not expected.     @raises TypeError: if the type of the argument is not expected.
2802     """     """
2803     if isinstance(arg,numarray.NumArray):     if isinstance(arg,numarray.NumArray):
2804        return arg.min()        if arg.rank==0:
2805             return float(arg)
2806          else:
2807             return arg.min()
2808     elif isinstance(arg,escript.Data):     elif isinstance(arg,escript.Data):
2809        return arg._minval()        return arg._minval()
2810     elif isinstance(arg,float):     elif isinstance(arg,float):
# Line 2761  def maxval(arg): Line 2878  def maxval(arg):
2878     @raises TypeError: if the type of the argument is not expected.     @raises TypeError: if the type of the argument is not expected.
2879     """     """
2880     if isinstance(arg,numarray.NumArray):     if isinstance(arg,numarray.NumArray):
2881        return arg.max()        if arg.rank==0:
2882             return float(arg)
2883          else:
2884             return arg.max()
2885     elif isinstance(arg,escript.Data):     elif isinstance(arg,escript.Data):
2886        return arg._maxval()        return arg._maxval()
2887     elif isinstance(arg,float):     elif isinstance(arg,float):
# Line 2835  def length(arg): Line 2955  def length(arg):
2955     """     """
2956     return sqrt(inner(arg,arg))     return sqrt(inner(arg,arg))
2957
2958    def trace(arg,axis_offset=0):
2959       """
2960       returns the trace of arg which the sum of arg[k,k] over k.
2961
2962       @param arg: argument
2963       @type arg: L{escript.Data}, L{Symbol}, L{numarray.NumArray}.
2964       @param axis_offset: axis_offset to components to sum over. C{axis_offset} must be non-negative and less than the rank of arg +1. The dimensions on component
2965                      axis_offset and axis_offset+1 must be equal.
2966       @type axis_offset: C{int}
2967       @return: trace of arg. The rank of the returned object is minus 2 of the rank of arg.
2968       @rtype: L{escript.Data}, L{Symbol}, L{numarray.NumArray} depending on the type of arg.
2969       """
2970       if isinstance(arg,numarray.NumArray):
2971          sh=arg.shape
2972          if len(sh)<2:
2973            raise ValueError,"trace: rank of argument must be greater than 1"
2974          if axis_offset<0 or axis_offset>len(sh)-2:
2975            raise ValueError,"trace: axis_offset must be between 0 and %s"%len(sh)-2
2976          s1=1
2977          for i in range(axis_offset): s1*=sh[i]
2978          s2=1
2979          for i in range(axis_offset+2,len(sh)): s2*=sh[i]
2980          if not sh[axis_offset] == sh[axis_offset+1]:
2981            raise ValueError,"trace: dimensions of component %s and %s must match."%(axis_offset.axis_offset+1)
2982          arg_reshaped=numarray.reshape(arg,(s1,sh[axis_offset],sh[axis_offset],s2))
2983          out=numarray.zeros([s1,s2],numarray.Float)
2984          for i1 in range(s1):
2985            for i2 in range(s2):
2986                for j in range(sh[axis_offset]): out[i1,i2]+=arg_reshaped[i1,j,j,i2]
2987          out.resize(sh[:axis_offset]+sh[axis_offset+2:])
2988          return out
2989       elif isinstance(arg,escript.Data):
2990          return escript_trace(arg,axis_offset)
2991       elif isinstance(arg,float):
2992          raise TypeError,"trace: illegal argument type float."
2993       elif isinstance(arg,int):
2994          raise TypeError,"trace: illegal argument type int."
2995       elif isinstance(arg,Symbol):
2996          return Trace_Symbol(arg,axis_offset)
2997       else:
2998          raise TypeError,"trace: Unknown argument type."
2999
3000    def escript_trace(arg,axis_offset): # this should be escript._trace
3001          "arg si a Data objects!!!"
3002          if arg.getRank()<2:
3003            raise ValueError,"escript_trace: rank of argument must be greater than 1"
3004          if axis_offset<0 or axis_offset>arg.getRank()-2:
3005            raise ValueError,"escript_trace: axis_offset must be between 0 and %s"%arg.getRank()-2
3006          s=list(arg.getShape())
3007          if not s[axis_offset] == s[axis_offset+1]:
3008            raise ValueError,"escript_trace: dimensions of component %s and %s must match."%(axis_offset.axis_offset+1)
3009          out=escript.Data(0.,tuple(s[0:axis_offset]+s[axis_offset+2:]),arg.getFunctionSpace())
3010          if arg.getRank()==2:
3011             for i0 in range(s[0]):
3012                out+=arg[i0,i0]
3013          elif arg.getRank()==3:
3014             if axis_offset==0:
3015                for i0 in range(s[0]):
3016                      for i2 in range(s[2]):
3017                             out[i2]+=arg[i0,i0,i2]
3018             elif axis_offset==1:
3019                for i0 in range(s[0]):
3020                   for i1 in range(s[1]):
3021                             out[i0]+=arg[i0,i1,i1]
3022          elif arg.getRank()==4:
3023             if axis_offset==0:
3024                for i0 in range(s[0]):
3025                      for i2 in range(s[2]):
3026                         for i3 in range(s[3]):
3027                             out[i2,i3]+=arg[i0,i0,i2,i3]
3028             elif axis_offset==1:
3029                for i0 in range(s[0]):
3030                   for i1 in range(s[1]):
3031                         for i3 in range(s[3]):
3032                             out[i0,i3]+=arg[i0,i1,i1,i3]
3033             elif axis_offset==2:
3034                for i0 in range(s[0]):
3035                   for i1 in range(s[1]):
3036                      for i2 in range(s[2]):
3037                             out[i0,i1]+=arg[i0,i1,i2,i2]
3038          return out
3039    class Trace_Symbol(DependendSymbol):
3040       """
3041       L{Symbol} representing the result of the trace function
3042       """
3043       def __init__(self,arg,axis_offset=0):
3044          """
3045          initialization of trace L{Symbol} with argument arg
3046          @param arg: argument of function
3047          @type arg: L{Symbol}.
3048          @param axis_offset: axis_offset to components to sum over. C{axis_offset} must be non-negative and less than the rank of arg +1. The dimensions on component
3049                      axis_offset and axis_offset+1 must be equal.
3050          @type axis_offset: C{int}
3051          """
3052          if arg.getRank()<2:
3053            raise ValueError,"Trace_Symbol: rank of argument must be greater than 1"
3054          if axis_offset<0 or axis_offset>arg.getRank()-2:
3055            raise ValueError,"Trace_Symbol: axis_offset must be between 0 and %s"%arg.getRank()-2
3056          s=list(arg.getShape())
3057          if not s[axis_offset] == s[axis_offset+1]:
3058            raise ValueError,"Trace_Symbol: dimensions of component %s and %s must match."%(axis_offset.axis_offset+1)
3059          super(Trace_Symbol,self).__init__(args=[arg,axis_offset],shape=tuple(s[0:axis_offset]+s[axis_offset+2:]),dim=arg.getDim())
3060
3061       def getMyCode(self,argstrs,format="escript"):
3062          """
3063          returns a program code that can be used to evaluate the symbol.
3064
3065          @param argstrs: gives for each argument a string representing the argument for the evaluation.
3066          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
3067          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
3068          @type format: C{str}
3069          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
3070          @rtype: C{str}
3071          @raise: NotImplementedError: if the requested format is not available
3072          """
3073          if format=="escript" or format=="str"  or format=="text":
3074             return "trace(%s,axis_offset=%s)"%(argstrs[0],argstrs[1])
3075          else:
3076             raise NotImplementedError,"Trace_Symbol does not provide program code for format %s."%format
3077
3078       def substitute(self,argvals):
3079          """
3080          assigns new values to symbols in the definition of the symbol.
3081          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
3082
3083          @param argvals: new values assigned to symbols
3084          @type argvals: C{dict} with keywords of type L{Symbol}.
3085          @return: result of the substitution process. Operations are executed as much as possible.
3086          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
3087          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
3088          """
3089          if argvals.has_key(self):
3090             arg=argvals[self]
3091             if self.isAppropriateValue(arg):
3092                return arg
3093             else:
3094                raise TypeError,"%s: new value is not appropriate."%str(self)
3095          else:
3096             arg=self.getSubstitutedArguments(argvals)
3097             return trace(arg[0],axis_offset=arg[1])
3098
3099       def diff(self,arg):
3100          """
3101          differential of this object
3102
3103          @param arg: the derivative is calculated with respect to arg
3104          @type arg: L{escript.Symbol}
3105          @return: derivative with respect to C{arg}
3106          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
3107          """
3108          if arg==self:
3109             return identity(self.getShape())
3110          else:
3111             return trace(self.getDifferentiatedArguments(arg)[0],axis_offset=self.getArgument()[1])
3112
3113    def transpose(arg,axis_offset=None):
3114       """
3115       returns the transpose of arg by swaping the first axis_offset and the last rank-axis_offset components.
3116
3117       @param arg: argument
3118       @type arg: L{escript.Data}, L{Symbol}, L{numarray.NumArray}, C{float}, C{int}
3119       @param axis_offset: the first axis_offset components are swapped with rest. If C{axis_offset} must be non-negative and less or equal the rank of arg.
3120                           if axis_offset is not present C{int(r/2)} where r is the rank of arg is used.
3121       @type axis_offset: C{int}
3122       @return: transpose of arg
3123       @rtype: L{escript.Data}, L{Symbol}, L{numarray.NumArray},C{float}, C{int} depending on the type of arg.
3124       """
3125       if isinstance(arg,numarray.NumArray):
3126          if axis_offset==None: axis_offset=int(arg.rank/2)
3127          return numarray.transpose(arg,axes=range(axis_offset,arg.rank)+range(0,axis_offset))
3128       elif isinstance(arg,escript.Data):
3129          if axis_offset==None: axis_offset=int(arg.getRank()/2)
3130          return escript_transpose(arg,axis_offset)
3131       elif isinstance(arg,float):
3132          if not ( axis_offset==0 or axis_offset==None):
3133            raise ValueError,"transpose: axis_offset must be 0 for float argument"
3134          return arg
3135       elif isinstance(arg,int):
3136          if not ( axis_offset==0 or axis_offset==None):
3137            raise ValueError,"transpose: axis_offset must be 0 for int argument"
3138          return float(arg)
3139       elif isinstance(arg,Symbol):
3140          if axis_offset==None: axis_offset=int(arg.getRank()/2)
3141          return Transpose_Symbol(arg,axis_offset)
3142       else:
3143          raise TypeError,"transpose: Unknown argument type."
3144
3145    def escript_transpose(arg,axis_offset): # this should be escript._transpose
3146          "arg si a Data objects!!!"
3147          r=arg.getRank()
3148          if axis_offset<0 or axis_offset>r:
3149            raise ValueError,"escript_transpose: axis_offset must be between 0 and %s"%r
3150          s=arg.getShape()
3151          s_out=s[axis_offset:]+s[:axis_offset]
3152          out=escript.Data(0.,s_out,arg.getFunctionSpace())
3153          if r==4:
3154             if axis_offset==1:
3155                for i0 in range(s_out[0]):
3156                   for i1 in range(s_out[1]):
3157                      for i2 in range(s_out[2]):
3158                         for i3 in range(s_out[3]):
3159                             out[i0,i1,i2,i3]=arg[i3,i0,i1,i2]
3160             elif axis_offset==2:
3161                for i0 in range(s_out[0]):
3162                   for i1 in range(s_out[1]):
3163                      for i2 in range(s_out[2]):
3164                         for i3 in range(s_out[3]):
3165                             out[i0,i1,i2,i3]=arg[i2,i3,i0,i1]
3166             elif axis_offset==3:
3167                for i0 in range(s_out[0]):
3168                   for i1 in range(s_out[1]):
3169                      for i2 in range(s_out[2]):
3170                         for i3 in range(s_out[3]):
3171                             out[i0,i1,i2,i3]=arg[i1,i2,i3,i0]
3172             else:
3173                for i0 in range(s_out[0]):
3174                   for i1 in range(s_out[1]):
3175                      for i2 in range(s_out[2]):
3176                         for i3 in range(s_out[3]):
3177                             out[i0,i1,i2,i3]=arg[i0,i1,i2,i3]
3178          elif r==3:
3179             if axis_offset==1:
3180                for i0 in range(s_out[0]):
3181                   for i1 in range(s_out[1]):
3182                      for i2 in range(s_out[2]):
3183                             out[i0,i1,i2]=arg[i2,i0,i1]
3184             elif axis_offset==2:
3185                for i0 in range(s_out[0]):
3186                   for i1 in range(s_out[1]):
3187                      for i2 in range(s_out[2]):
3188                             out[i0,i1,i2]=arg[i1,i2,i0]
3189             else:
3190                for i0 in range(s_out[0]):
3191                   for i1 in range(s_out[1]):
3192                      for i2 in range(s_out[2]):
3193                             out[i0,i1,i2]=arg[i0,i1,i2]
3194          elif r==2:
3195             if axis_offset==1:
3196                for i0 in range(s_out[0]):
3197                   for i1 in range(s_out[1]):
3198                             out[i0,i1]=arg[i1,i0]
3199             else:
3200                for i0 in range(s_out[0]):
3201                   for i1 in range(s_out[1]):
3202                             out[i0,i1]=arg[i0,i1]
3203          elif r==1:
3204              for i0 in range(s_out[0]):
3205                   out[i0]=arg[i0]
3206          elif r==0:
3207                 out=arg+0.
3208          return out
3209    class Transpose_Symbol(DependendSymbol):
3210       """
3211       L{Symbol} representing the result of the transpose function
3212       """
3213       def __init__(self,arg,axis_offset=None):
3214          """
3215          initialization of transpose L{Symbol} with argument arg
3216
3217          @param arg: argument of function
3218          @type arg: L{Symbol}.
3219           @param axis_offset: the first axis_offset components are swapped with rest. If C{axis_offset} must be non-negative and less or equal the rank of arg.
3220                           if axis_offset is not present C{int(r/2)} where r is the rank of arg is used.
3221          @type axis_offset: C{int}
3222          """
3223          if axis_offset==None: axis_offset=int(arg.getRank()/2)
3224          if axis_offset<0 or axis_offset>arg.getRank():
3225            raise ValueError,"escript_transpose: axis_offset must be between 0 and %s"%r
3226          s=arg.getShape()
3227          super(Transpose_Symbol,self).__init__(args=[arg,axis_offset],shape=s[axis_offset:]+s[:axis_offset],dim=arg.getDim())
3228
3229       def getMyCode(self,argstrs,format="escript"):
3230          """
3231          returns a program code that can be used to evaluate the symbol.
3232
3233          @param argstrs: gives for each argument a string representing the argument for the evaluation.
3234          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
3235          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
3236          @type format: C{str}
3237          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
3238          @rtype: C{str}
3239          @raise: NotImplementedError: if the requested format is not available
3240          """
3241          if format=="escript" or format=="str"  or format=="text":
3242             return "transpose(%s,axis_offset=%s)"%(argstrs[0],argstrs[1])
3243          else:
3244             raise NotImplementedError,"Transpose_Symbol does not provide program code for format %s."%format
3245
3246       def substitute(self,argvals):
3247          """
3248          assigns new values to symbols in the definition of the symbol.
3249          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
3250
3251          @param argvals: new values assigned to symbols
3252          @type argvals: C{dict} with keywords of type L{Symbol}.
3253          @return: result of the substitution process. Operations are executed as much as possible.
3254          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
3255          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
3256          """
3257          if argvals.has_key(self):
3258             arg=argvals[self]
3259             if self.isAppropriateValue(arg):
3260                return arg
3261             else:
3262                raise TypeError,"%s: new value is not appropriate."%str(self)
3263          else:
3264             arg=self.getSubstitutedArguments(argvals)
3265             return transpose(arg[0],axis_offset=arg[1])
3266
3267       def diff(self,arg):
3268          """
3269          differential of this object
3270
3271          @param arg: the derivative is calculated with respect to arg
3272          @type arg: L{escript.Symbol}
3273          @return: derivative with respect to C{arg}
3274          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
3275          """
3276          if arg==self:
3277             return identity(self.getShape())
3278          else:
3279             return transpose(self.getDifferentiatedArguments(arg)[0],axis_offset=self.getArgument()[1])
3280
3281    def inverse(arg):
3282        """
3283        returns the inverse of the square matrix arg.
3284
3285        @param arg: square matrix. Must have rank 2 and the first and second dimension must be equal.
3286        @type arg: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
3287        @return: inverse arg_inv of the argument. It will be matrixmul(inverse(arg),arg) almost equal to kronecker(arg.getShape()[0])
3288        @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
3289        @remark: for L{escript.Data} objects the dimension is restricted to 3.
3290        """
3291        if isinstance(arg,numarray.NumArray):
3292          return numarray.linear_algebra.inverse(arg)
3293        elif isinstance(arg,escript.Data):
3294          return escript_inverse(arg)
3295        elif isinstance(arg,float):
3296          return 1./arg
3297        elif isinstance(arg,int):
3298          return 1./float(arg)
3299        elif isinstance(arg,Symbol):
3300          return Inverse_Symbol(arg)
3301        else:
3302          raise TypeError,"inverse: Unknown argument type."
3303
3304    def escript_inverse(arg): # this should be escript._inverse and use LAPACK
3305          "arg is a Data objects!!!"
3306          if not arg.getRank()==2:
3307            raise ValueError,"escript_inverse: argument must have rank 2"
3308          s=arg.getShape()
3309          if not s[0] == s[1]:
3310            raise ValueError,"escript_inverse: argument must be a square matrix."
3311          out=escript.Data(0.,s,arg.getFunctionSpace())
3312          if s[0]==1:
3313              if inf(abs(arg[0,0]))==0: # in c this should be done point wise as abs(arg[0,0](i))<=0.
3314                  raise ZeroDivisionError,"escript_inverse: argument not invertible"
3315              out[0,0]=1./arg[0,0]
3316          elif s[0]==2:
3317              A11=arg[0,0]
3318              A12=arg[0,1]
3319              A21=arg[1,0]
3320              A22=arg[1,1]
3321              D = A11*A22-A12*A21
3322              if inf(abs(D))==0: # in c this should be done point wise as abs(D(i))<=0.
3323                  raise ZeroDivisionError,"escript_inverse: argument not invertible"
3324              D=1./D
3325              out[0,0]= A22*D
3326              out[1,0]=-A21*D
3327              out[0,1]=-A12*D
3328              out[1,1]= A11*D
3329          elif s[0]==3:
3330              A11=arg[0,0]
3331              A21=arg[1,0]
3332              A31=arg[2,0]
3333              A12=arg[0,1]
3334              A22=arg[1,1]
3335              A32=arg[2,1]
3336              A13=arg[0,2]
3337              A23=arg[1,2]
3338              A33=arg[2,2]
3339              D  =  A11*(A22*A33-A23*A32)+ A12*(A31*A23-A21*A33)+A13*(A21*A32-A31*A22)
3340              if inf(abs(D))==0: # in c this should be done point wise as abs(D(i))<=0.
3341                  raise ZeroDivisionError,"escript_inverse: argument not invertible"
3342              D=1./D
3343              out[0,0]=(A22*A33-A23*A32)*D
3344              out[1,0]=(A31*A23-A21*A33)*D
3345              out[2,0]=(A21*A32-A31*A22)*D
3346              out[0,1]=(A13*A32-A12*A33)*D
3347              out[1,1]=(A11*A33-A31*A13)*D
3348              out[2,1]=(A12*A31-A11*A32)*D
3349              out[0,2]=(A12*A23-A13*A22)*D
3350              out[1,2]=(A13*A21-A11*A23)*D
3351              out[2,2]=(A11*A22-A12*A21)*D
3352          else:
3353             raise TypeError,"escript_inverse: only matrix dimensions 1,2,3 are supported right now."
3354          return out
3355
3356    class Inverse_Symbol(DependendSymbol):
3357       """
3358       L{Symbol} representing the result of the inverse function
3359       """
3360       def __init__(self,arg):
3361          """
3362          initialization of inverse L{Symbol} with argument arg
3363          @param arg: argument of function
3364          @type arg: L{Symbol}.
3365          """
3366          if not arg.getRank()==2:
3367            raise ValueError,"Inverse_Symbol:: argument must have rank 2"
3368          s=arg.getShape()
3369          if not s[0] == s[1]:
3370            raise ValueError,"Inverse_Symbol:: argument must be a square matrix."
3371          super(Inverse_Symbol,self).__init__(args=[arg],shape=s,dim=arg.getDim())
3372
3373       def getMyCode(self,argstrs,format="escript"):
3374          """
3375          returns a program code that can be used to evaluate the symbol.
3376
3377          @param argstrs: gives for each argument a string representing the argument for the evaluation.
3378          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
3379          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
3380          @type format: C{str}
3381          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
3382          @rtype: C{str}
3383          @raise: NotImplementedError: if the requested format is not available
3384          """
3385          if format=="escript" or format=="str"  or format=="text":
3386             return "inverse(%s)"%argstrs[0]
3387          else:
3388             raise NotImplementedError,"Inverse_Symbol does not provide program code for format %s."%format
3389
3390       def substitute(self,argvals):
3391          """
3392          assigns new values to symbols in the definition of the symbol.
3393          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
3394
3395          @param argvals: new values assigned to symbols
3396          @type argvals: C{dict} with keywords of type L{Symbol}.
3397          @return: result of the substitution process. Operations are executed as much as possible.
3398          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
3399          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
3400          """
3401          if argvals.has_key(self):
3402             arg=argvals[self]
3403             if self.isAppropriateValue(arg):
3404                return arg
3405             else:
3406                raise TypeError,"%s: new value is not appropriate."%str(self)
3407          else:
3408             arg=self.getSubstitutedArguments(argvals)
3409             return inverse(arg[0])
3410
3411       def diff(self,arg):
3412          """
3413          differential of this object
3414
3415          @param arg: the derivative is calculated with respect to arg
3416          @type arg: L{escript.Symbol}
3417          @return: derivative with respect to C{arg}
3418          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
3419          """
3420          if arg==self:
3421             return identity(self.getShape())
3422          else:
3423             return -matrixmult(matrixmult(self,self.getDifferentiatedArguments(arg)[0]),self)
3424
3425    def eigenvalues(arg):
3426        """
3427        returns the eigenvalues of the square matrix arg.
3428
3429        @param arg: square matrix. Must have rank 2 and the first and second dimension must be equal.
3430                    arg must be symmetric, ie. transpose(arg)==arg (this is not checked).
3431        @type arg: L{numarray.NumArray}, L{escript.Data}, L{Symbol}
3432        @return: the eigenvalues in increasing order.
3433        @rtype: L{numarray.NumArray},L{escript.Data}, L{Symbol} depending on the input.
3434        @remark: for L{escript.Data} and L{Symbol} objects the dimension is restricted to 3.
3435        """
3436        if isinstance(arg,numarray.NumArray):
3437          if not arg.rank==2:
3438            raise ValueError,"eigenvalues: argument must have rank 2"
3439          s=arg.shape
3440          if not s[0] == s[1]:
3441            raise ValueError,"eigenvalues: argument must be a square matrix."
3442          out=numarray.linear_algebra.eigenvalues((arg+numarray.transpose(arg))/2.)
3443          out.sort()
3444          return out
3445        elif isinstance(arg,escript.Data) or isinstance(arg,Symbol):
3446          if not arg.getRank()==2:
3447            raise ValueError,"eigenvalues: argument must have rank 2"
3448          s=arg.getShape()
3449          if not s[0] == s[1]:
3450            raise ValueError,"eigenvalues: argument must be a square matrix."
3451          if s[0]==1:
3452              return arg[0]
3453          elif s[0]==2:
3454              A11=arg[0,0]
3455              A12=arg[0,1]
3456              A22=arg[1,1]
3457              trA=(A11+A22)/2.
3458              A11-=trA
3459              A22-=trA
3460              s=sqrt(A12**2-A11*A22)
3461              return trA+s*numarray.array([-1.,1.])
3462          elif s[0]==3:
3463              A11=arg[0,0]
3464              A12=arg[0,1]
3465              A22=arg[1,1]
3466              A13=arg[0,2]
3467              A23=arg[1,2]
3468              A33=arg[2,2]
3469              trA=(A11+A22+A22)/3.
3470              A11-=trA
3471              A22-=trA
3472              A33-=trA
3473              A13_2=A13**2
3474              A23_2=A23**2
3475              A12_2=A12**2
3476              p=A13_2+A23_2+A12_2+(A11**2+A22**2+A33**2)/2.
3477              q=A13_2*A22+A23_2*A11+A12_2*A33-A11*A22*A33-2*A12*A23*A13
3478              sq_p=sqrt(p/3.)
3479              alpha_3=acos(-q/sq_p**(1./3.)/2.)/3.
3480              sq_p*=2.
3481              f=cos(alpha_3)               *numarray.array([1.,0.,0.]) \
3482               -cos(alpha_3+numarray.pi/3.)*numarray.array([0.,1.,0.]) \
3483               -cos(alpha_3-numarray.pi/3.)*numarray.array([0.,0.,1.])
3484              return trA+sq_p*f
3485          else:
3486             raise TypeError,"eigenvalues: only matrix dimensions 1,2,3 are supported right now."
3487        elif isinstance(arg,float):
3488          return arg
3489        elif isinstance(arg,int):
3490          return float(arg)
3491        else:
3492          raise TypeError,"eigenvalues: Unknown argument type."
3493  #=======================================================  #=======================================================
3494  #  Binary operations:  #  Binary operations:
3495  #=======================================================  #=======================================================
# Line 3262  def maximum(*args): Line 3917  def maximum(*args):
3917         if out==None:         if out==None:
3918            out=a            out=a
3919         else:         else:
3922      return out      return out
3923
3924  def minimum(*arg):  def minimum(*args):
3925      """      """
3926      the minimum over arguments args      the minimum over arguments args
3927
# Line 3280  def minimum(*arg): Line 3935  def minimum(*arg):
3935         if out==None:         if out==None:
3936            out=a            out=a
3937         else:         else:
3940      return out      return out
3941
3942    def clip(arg,minval=0.,maxval=1.):
3943        """
3944        cuts the values of arg between minval and maxval
3945
3946        @param arg: argument
3947        @type arg: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{int} or C{float}
3948        @param minval: lower range
3949        @type arg: C{float}
3950        @param maxval: upper range
3951        @type arg: C{float}
3952        @return: is on object with all its value between minval and maxval. value of the argument that greater then minval and
3953                 less then maxval are unchanged.
3954        @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol}, C{int} or C{float} depending on the input
3955        @raise ValueError: if minval>maxval
3956        """
3957        if minval>maxval:
3958           raise ValueError,"minval = %s must be less then maxval %s"%(minval,maxval)
3959        return minimum(maximum(minval,arg),maxval)
3960
3961
3962  def inner(arg0,arg1):  def inner(arg0,arg1):
3963      """      """
# Line 3306  def inner(arg0,arg1): Line 3981  def inner(arg0,arg1):
3981      sh1=pokeShape(arg1)      sh1=pokeShape(arg1)
3982      if not sh0==sh1:      if not sh0==sh1:
3983          raise ValueError,"inner: shape of arguments does not match"          raise ValueError,"inner: shape of arguments does not match"
3984      return generalTensorProduct(arg0,arg1,offset=len(sh0))      return generalTensorProduct(arg0,arg1,axis_offset=len(sh0))
3985
3986  def matrixmult(arg0,arg1):  def matrixmult(arg0,arg1):
3987      """      """
# Line 3334  def matrixmult(arg0,arg1): Line 4009  def matrixmult(arg0,arg1):
4009          raise ValueError,"first argument must have rank 2"          raise ValueError,"first argument must have rank 2"
4010      if not len(sh1)==2 and not len(sh1)==1:      if not len(sh1)==2 and not len(sh1)==1:
4011          raise ValueError,"second argument must have rank 1 or 2"          raise ValueError,"second argument must have rank 1 or 2"
4012      return generalTensorProduct(arg0,arg1,offset=1)      return generalTensorProduct(arg0,arg1,axis_offset=1)
4013
4014  def outer(arg0,arg1):  def outer(arg0,arg1):
4015      """      """
# Line 3352  def outer(arg0,arg1): Line 4027  def outer(arg0,arg1):
4027      @return: the outer product of arg0 and arg1 at each data point      @return: the outer product of arg0 and arg1 at each data point
4028      @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input      @rtype: L{numarray.NumArray}, L{escript.Data}, L{Symbol} depending on the input
4029      """      """
4030      return generalTensorProduct(arg0,arg1,offset=0)      return generalTensorProduct(arg0,arg1,axis_offset=0)
4031
4032
4033  def tensormult(arg0,arg1):  def tensormult(arg0,arg1):
# Line 3394  def tensormult(arg0,arg1): Line 4069  def tensormult(arg0,arg1):
4069      sh0=pokeShape(arg0)      sh0=pokeShape(arg0)
4070      sh1=pokeShape(arg1)      sh1=pokeShape(arg1)
4071      if len(sh0)==2 and ( len(sh1)==2 or len(sh1)==1 ):      if len(sh0)==2 and ( len(sh1)==2 or len(sh1)==1 ):
4072         return generalTensorProduct(arg0,arg1,offset=1)         return generalTensorProduct(arg0,arg1,axis_offset=1)
4073      elif len(sh0)==4 and (len(sh1)==2 or len(sh1)==3 or len(sh1)==4):      elif len(sh0)==4 and (len(sh1)==2 or len(sh1)==3 or len(sh1)==4):
4074         return generalTensorProduct(arg0,arg1,offset=2)         return generalTensorProduct(arg0,arg1,axis_offset=2)
4075      else:      else:
4076          raise ValueError,"tensormult: first argument must have rank 2 or 4"          raise ValueError,"tensormult: first argument must have rank 2 or 4"
4077
4078  def generalTensorProduct(arg0,arg1,offset=0):  def generalTensorProduct(arg0,arg1,axis_offset=0):
4079      """      """
4080      generalized tensor product      generalized tensor product
4081
4082      out[s,t]=S{Sigma}_r arg0[s,r]*arg1[r,t]      out[s,t]=S{Sigma}_r arg0[s,r]*arg1[r,t]
4083
4084      where s runs through arg0.Shape[:arg0.Rank-offset]      where s runs through arg0.Shape[:arg0.Rank-axis_offset]
4085            r runs trough arg0.Shape[:offset]            r runs trough arg0.Shape[:axis_offset]
4086            t runs through arg1.Shape[offset:]            t runs through arg1.Shape[axis_offset:]
4087
4088      In the first case the the second dimension of arg0 and the length of arg1 must match and        In the first case the the second dimension of arg0 and the length of arg1 must match and
4089      in the second case the two last dimensions of arg0 must match the shape of arg1.      in the second case the two last dimensions of arg0 must match the shape of arg1.
# Line 3425  def generalTensorProduct(arg0,arg1,offse Line 4100  def generalTensorProduct(arg0,arg1,offse
4100      # at this stage arg0 and arg0 are both numarray.NumArray or escript.Data or Symbols      # at this stage arg0 and arg0 are both numarray.NumArray or escript.Data or Symbols
4101      if isinstance(arg0,numarray.NumArray):      if isinstance(arg0,numarray.NumArray):
4102         if isinstance(arg1,Symbol):         if isinstance(arg1,Symbol):
4103             return GeneralTensorProduct_Symbol(arg0,arg1,offset)             return GeneralTensorProduct_Symbol(arg0,arg1,axis_offset)
4104         else:         else:
4105             if not arg0.shape[arg0.rank-offset:]==arg1.shape[:offset]:             if not arg0.shape[arg0.rank-axis_offset:]==arg1.shape[:axis_offset]:
4106                 raise ValueError,"generalTensorProduct: dimensions of last %s components in left argument don't match the first %s components in the right argument."%(offset,offset)                 raise ValueError,"generalTensorProduct: dimensions of last %s components in left argument don't match the first %s components in the right argument."%(axis_offset,axis_offset)
4107             arg0_c=arg0.copy()             arg0_c=arg0.copy()
4108             arg1_c=arg1.copy()             arg1_c=arg1.copy()
4109             sh0,sh1=arg0.shape,arg1.shape             sh0,sh1=arg0.shape,arg1.shape
4110             d0,d1,d01=1,1,1             d0,d1,d01=1,1,1
4111             for i in sh0[:arg0.rank-offset]: d0*=i             for i in sh0[:arg0.rank-axis_offset]: d0*=i
4112             for i in sh1[offset:]: d1*=i             for i in sh1[axis_offset:]: d1*=i
4113             for i in sh1[:offset]: d01*=i             for i in sh1[:axis_offset]: d01*=i
4114             arg0_c.resize((d0,d01))             arg0_c.resize((d0,d01))
4115             arg1_c.resize((d01,d1))             arg1_c.resize((d01,d1))
4116             out=numarray.zeros((d0,d1),numarray.Float)             out=numarray.zeros((d0,d1),numarray.Float)
4117             for i0 in range(d0):             for i0 in range(d0):
4118                      for i1 in range(d1):                      for i1 in range(d1):
4119                           out[i0,i1]=numarray.sum(arg0_c[i0,:]*arg1_c[:,i1])                           out[i0,i1]=numarray.sum(arg0_c[i0,:]*arg1_c[:,i1])
4120             out.resize(sh0[:arg0.rank-offset]+sh1[offset:])             out.resize(sh0[:arg0.rank-axis_offset]+sh1[axis_offset:])
4121             return out             return out
4122      elif isinstance(arg0,escript.Data):      elif isinstance(arg0,escript.Data):
4123         if isinstance(arg1,Symbol):         if isinstance(arg1,Symbol):
4124             return GeneralTensorProduct_Symbol(arg0,arg1,offset)             return GeneralTensorProduct_Symbol(arg0,arg1,axis_offset)
4125         else:         else:
4126             return escript_generalTensorProduct(arg0,arg1,offset) # this calls has to be replaced by escript._generalTensorProduct(arg0,arg1,offset)             return escript_generalTensorProduct(arg0,arg1,axis_offset) # this calls has to be replaced by escript._generalTensorProduct(arg0,arg1,axis_offset)
4127      else:            else:
4128         return GeneralTensorProduct_Symbol(arg0,arg1,offset)         return GeneralTensorProduct_Symbol(arg0,arg1,axis_offset)
4129
4130  class GeneralTensorProduct_Symbol(DependendSymbol):  class GeneralTensorProduct_Symbol(DependendSymbol):
4131     """     """
4132     Symbol representing the quotient of two arguments.     Symbol representing the quotient of two arguments.
4133     """     """
4134     def __init__(self,arg0,arg1,offset=0):     def __init__(self,arg0,arg1,axis_offset=0):
4135         """         """
4136         initialization of L{Symbol} representing the quotient of two arguments         initialization of L{Symbol} representing the quotient of two arguments
4137
# Line 3469  class GeneralTensorProduct_Symbol(Depend Line 4144  class GeneralTensorProduct_Symbol(Depend
4144         """         """
4145         sh_arg0=pokeShape(arg0)         sh_arg0=pokeShape(arg0)
4146         sh_arg1=pokeShape(arg1)         sh_arg1=pokeShape(arg1)
4147         sh0=sh_arg0[:len(sh_arg0)-offset]         sh0=sh_arg0[:len(sh_arg0)-axis_offset]
4148         sh01=sh_arg0[len(sh_arg0)-offset:]         sh01=sh_arg0[len(sh_arg0)-axis_offset:]
4149         sh10=sh_arg1[:offset]         sh10=sh_arg1[:axis_offset]
4150         sh1=sh_arg1[offset:]         sh1=sh_arg1[axis_offset:]
4151         if not sh01==sh10:         if not sh01==sh10:
4152             raise ValueError,"dimensions of last %s components in left argument don't match the first %s components in the right argument."%(offset,offset)             raise ValueError,"dimensions of last %s components in left argument don't match the first %s components in the right argument."%(axis_offset,axis_offset)
4153         DependendSymbol.__init__(self,dim=commonDim(arg0,arg1),shape=sh0+sh1,args=[arg0,arg1,offset])         DependendSymbol.__init__(self,dim=commonDim(arg0,arg1),shape=sh0+sh1,args=[arg0,arg1,axis_offset])
4154
4155     def getMyCode(self,argstrs,format="escript"):     def getMyCode(self,argstrs,format="escript"):
4156        """        """
# Line 3490  class GeneralTensorProduct_Symbol(Depend Line 4165  class GeneralTensorProduct_Symbol(Depend
4165        @raise: NotImplementedError: if the requested format is not available        @raise: NotImplementedError: if the requested format is not available
4166        """        """
4167        if format=="escript" or format=="str" or format=="text":        if format=="escript" or format=="str" or format=="text":
4168           return "generalTensorProduct(%s,%s,offset=%s)"%(argstrs[0],argstrs[1],argstrs[2])           return "generalTensorProduct(%s,%s,axis_offset=%s)"%(argstrs[0],argstrs[1],argstrs[2])
4169        else:        else:
4170           raise NotImplementedError,"%s does not provide program code for format %s."%(str(self),format)           raise NotImplementedError,"%s does not provide program code for format %s."%(str(self),format)
4171
# Line 3515  class GeneralTensorProduct_Symbol(Depend Line 4190  class GeneralTensorProduct_Symbol(Depend
4190           args=self.getSubstitutedArguments(argvals)           args=self.getSubstitutedArguments(argvals)
4191           return generalTensorProduct(args[0],args[1],args[2])           return generalTensorProduct(args[0],args[1],args[2])
4192
4193  def escript_generalTensorProduct(arg0,arg1,offset): # this should be escript._generalTensorProduct  def escript_generalTensorProduct(arg0,arg1,axis_offset): # this should be escript._generalTensorProduct
4194      "arg0 and arg1 are both Data objects but not neccesrily on the same function space. they could be identical!!!"      "arg0 and arg1 are both Data objects but not neccesrily on the same function space. they could be identical!!!"
4195      # calculate the return shape:      # calculate the return shape:
4196      shape0=arg0.getShape()[:arg0.getRank()-offset]      shape0=arg0.getShape()[:arg0.getRank()-axis_offset]
4197      shape01=arg0.getShape()[arg0.getRank()-offset:]      shape01=arg0.getShape()[arg0.getRank()-axis_offset:]
4198      shape10=arg1.getShape()[:offset]      shape10=arg1.getShape()[:axis_offset]
4199      shape1=arg1.getShape()[offset:]      shape1=arg1.getShape()[axis_offset:]
4200      if not shape01==shape10:      if not shape01==shape10:
4201          raise ValueError,"dimensions of last %s components in left argument don't match the first %s components in the right argument."%(offset,offset)          raise ValueError,"dimensions of last %s components in left argument don't match the first %s components in the right argument."%(axis_offset,axis_offset)
4202
4203        # whatr function space should be used? (this here is not good!)
4204        fs=(escript.Scalar(0.,arg0.getFunctionSpace())+escript.Scalar(0.,arg1.getFunctionSpace())).getFunctionSpace()
4205      # create return value:      # create return value:
4206      out=escript.Data(0.,tuple(shape0+shape1),arg0.getFunctionSpace())      out=escript.Data(0.,tuple(shape0+shape1),fs)
4207      #      #
4208      s0=[[]]      s0=[[]]
4209      for k in shape0:      for k in shape0:
# Line 3549  def escript_generalTensorProduct(arg0,ar Line 4226  def escript_generalTensorProduct(arg0,ar
4226
4227      for i0 in s0:      for i0 in s0:
4228         for i1 in s1:         for i1 in s1:
4229           s=escript.Scalar(0.,arg0.getFunctionSpace())           s=escript.Scalar(0.,fs)
4230           for i01 in s01:           for i01 in s01:
4231              s+=arg0.__getitem__(tuple(i0+i01))*arg1.__getitem__(tuple(i01+i1))              s+=arg0.__getitem__(tuple(i0+i01))*arg1.__getitem__(tuple(i01+i1))
4232           out.__setitem__(tuple(i0+i1),s)           out.__setitem__(tuple(i0+i1),s)
4233      return out      return out
4234
4235
4236  #=========================================================  #=========================================================
4237  #   some little helpers  #  functions dealing with spatial dependency
4238  #=========================================================  #=========================================================
4240      """      """
4241      Returns the spatial gradient of arg at where.      Returns the spatial gradient of arg at where.
4242
4243        If C{g} is the returned object, then
4244
4245      @param arg:   Data object representing the function which gradient        - if C{arg} is rank 0 C{g[s]} is the derivative of C{arg} with respect to the C{s}-th spatial dimension.
4246                    to be calculated.        - if C{arg} is rank 1 C{g[i,s]} is the derivative of C{arg[i]} with respect to the C{s}-th spatial dimension.
4247          - if C{arg} is rank 2 C{g[i,j,s]} is the derivative of C{arg[i,j]} with respect to the C{s}-th spatial dimension.
4248          - if C{arg} is rank 3 C{g[i,j,k,s]} is the derivative of C{arg[i,j,k]} with respect to the C{s}-th spatial dimension.
4249
4250        @param arg: function which gradient to be calculated. Its rank has to be less than 3.
4251        @type arg: L{escript.Data} or L{Symbol}
4252      @param where: FunctionSpace in which the gradient will be calculated.      @param where: FunctionSpace in which the gradient will be calculated.
4253                    If not present or C{None} an appropriate default is used.                    If not present or C{None} an appropriate default is used.
4254        @type where: C{None} or L{escript.FunctionSpace}
4256        @rtype:  L{escript.Data} or L{Symbol}
4257      """      """
4258      if isinstance(arg,Symbol):      if isinstance(arg,Symbol):
4263         else:         else:
4265      else:      else:
4267
4269       """
4270       L{Symbol} representing the result of the gradient operator
4271       """
4272       def __init__(self,arg,where=None):
4273          """
4274          initialization of gradient L{Symbol} with argument arg
4275          @param arg: argument of function
4276          @type arg: L{Symbol}.
4277          @param where: FunctionSpace in which the gradient will be calculated.
4278                      If not present or C{None} an appropriate default is used.
4279          @type where: C{None} or L{escript.FunctionSpace}
4280          """
4281          d=arg.getDim()
4282          if d==None:
4283             raise ValueError,"argument must have a spatial dimension"
4285
4286       def getMyCode(self,argstrs,format="escript"):
4287          """
4288          returns a program code that can be used to evaluate the symbol.
4289
4290          @param argstrs: gives for each argument a string representing the argument for the evaluation.
4291          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
4292          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
4293          @type format: C{str}
4294          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
4295          @rtype: C{str}
4296          @raise: NotImplementedError: if the requested format is not available
4297          """
4298          if format=="escript" or format=="str"  or format=="text":
4300          else:
4301             raise NotImplementedError,"Trace_Symbol does not provide program code for format %s."%format
4302
4303       def substitute(self,argvals):
4304          """
4305          assigns new values to symbols in the definition of the symbol.
4306          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
4307
4308          @param argvals: new values assigned to symbols
4309          @type argvals: C{dict} with keywords of type L{Symbol}.
4310          @return: result of the substitution process. Operations are executed as much as possible.
4311          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
4312          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
4313          """
4314          if argvals.has_key(self):
4315             arg=argvals[self]
4316             if self.isAppropriateValue(arg):
4317                return arg
4318             else:
4319                raise TypeError,"%s: new value is not appropriate."%str(self)
4320          else:
4321             arg=self.getSubstitutedArguments(argvals)
4323
4324       def diff(self,arg):
4325          """
4326          differential of this object
4327
4328          @param arg: the derivative is calculated with respect to arg
4329          @type arg: L{escript.Symbol}
4330          @return: derivative with respect to C{arg}
4331          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
4332          """
4333          if arg==self:
4334             return identity(self.getShape())
4335          else:
4337
4338  def integrate(arg,where=None):  def integrate(arg,where=None):
4339      """      """
4340      Return the integral if the function represented by Data object arg over      Return the integral of the function C{arg} over its domain. If C{where} is present C{arg} is interpolated to C{where}
4341      its domain.      before integration.
4342
4343      @param arg:   Data object representing the function which is integrated.      @param arg:   the function which is integrated.
4344        @type arg: L{escript.Data} or L{Symbol}
4345      @param where: FunctionSpace in which the integral is calculated.      @param where: FunctionSpace in which the integral is calculated.
4346                    If not present or C{None} an appropriate default is used.                    If not present or C{None} an appropriate default is used.
4347        @type where: C{None} or L{escript.FunctionSpace}
4348        @return: integral of arg.
4349        @rtype:  C{float}, C{numarray.NumArray} or L{Symbol}
4350      """      """
4351      if isinstance(arg,numarray.NumArray):      if isinstance(arg,Symbol):
if checkForZero(arg):
return arg
else:
raise TypeError,"integrate: cannot intergrate argument"
elif isinstance(arg,float):
if checkForZero(arg):
return arg
else:
raise TypeError,"integrate: cannot intergrate argument"
elif isinstance(arg,int):
if checkForZero(arg):
return float(arg)
else:
raise TypeError,"integrate: cannot intergrate argument"
elif isinstance(arg,Symbol):
4352         return Integrate_Symbol(arg,where)         return Integrate_Symbol(arg,where)
4353      elif isinstance(arg,escript.Data):      elif isinstance(arg,escript.Data):
4354         if not where==None: arg=escript.Data(arg,where)         if not where==None: arg=escript.Data(arg,where)
# Line 3612  def integrate(arg,where=None): Line 4359  def integrate(arg,where=None):
4359      else:      else:
4360        raise TypeError,"integrate: Unknown argument type."        raise TypeError,"integrate: Unknown argument type."
4361
4362    class Integrate_Symbol(DependendSymbol):
4363       """
4364       L{Symbol} representing the result of the spatial integration operator
4365       """
4366       def __init__(self,arg,where=None):
4367          """
4368          initialization of integration L{Symbol} with argument arg
4369          @param arg: argument of the integration
4370          @type arg: L{Symbol}.
4371          @param where: FunctionSpace in which the integration will be calculated.
4372                      If not present or C{None} an appropriate default is used.
4373          @type where: C{None} or L{escript.FunctionSpace}
4374          """
4375          super(Integrate_Symbol,self).__init__(args=[arg,where],shape=arg.getShape(),dim=arg.getDim())
4376
4377       def getMyCode(self,argstrs,format="escript"):
4378          """
4379          returns a program code that can be used to evaluate the symbol.
4380
4381          @param argstrs: gives for each argument a string representing the argument for the evaluation.
4382          @type argstrs: C{str} or a C{list} of length 1 of C{str}.
4383          @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
4384          @type format: C{str}
4385          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
4386          @rtype: C{str}
4387          @raise: NotImplementedError: if the requested format is not available
4388          """
4389          if format=="escript" or format=="str"  or format=="text":
4390             return "integrate(%s,where=%s)"%(argstrs[0],argstrs[1])
4391          else:
4392             raise NotImplementedError,"Trace_Symbol does not provide program code for format %s."%format
4393
4394       def substitute(self,argvals):
4395          """
4396          assigns new values to symbols in the definition of the symbol.
4397          The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
4398
4399          @param argvals: new values assigned to symbols
4400          @type argvals: C{dict} with keywords of type L{Symbol}.
4401          @return: result of the substitution process. Operations are executed as much as possible.
4402          @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
4403          @raise TypeError: if a value for a L{Symbol} cannot be substituted.
4404          """
4405          if argvals.has_key(self):
4406             arg=argvals[self]
4407             if self.isAppropriateValue(arg):
4408                return arg
4409             else:
4410                raise TypeError,"%s: new value is not appropriate."%str(self)
4411          else:
4412             arg=self.getSubstitutedArguments(argvals)
4413             return integrate(arg[0],where=arg[1])
4414
4415       def diff(self,arg):
4416          """
4417          differential of this object
4418
4419          @param arg: the derivative is calculated with respect to arg
4420          @type arg: L{escript.Symbol}
4421          @return: derivative with respect to C{arg}
4422          @rtype: typically L{Symbol} but other types such as C{float}, L{escript.Data}, L{numarray.NumArray}  are possible.
4423          """
4424          if arg==self:
4425             return identity(self.getShape())
4426          else:
4427             return integrate(self.getDifferentiatedArguments(arg)[0],where=self.getArgument()[1])
4428
4429
4430  def interpolate(arg,where):  def interpolate(arg,where):
4431      """      """
4432      Interpolates the function into the FunctionSpace where.      interpolates the function into the FunctionSpace where.
4433
4434      @param arg:    interpolant      @param arg: interpolant
4435      @param where:  FunctionSpace to interpolate to      @type arg: L{escript.Data} or L{Symbol}
4436        @param where: FunctionSpace to be interpolated to
4437        @type where: L{escript.FunctionSpace}
4438        @return: interpolated argument
4439        @rtype:  C{escript.Data} or L{Symbol}
4440      """      """
4441      if testForZero(arg):      if isinstance(arg,Symbol):
4442        return 0         return Interpolate_Symbol(arg,where)
elif isinstance(arg,Symbol):
return Interpolated_Symbol(arg,where)
4443      else:      else:
4444         return escript.Data(arg,where)         return escript.Data(arg,where)
4445
4446  def div(arg,where=None):  class Interpolate_Symbol(DependendSymbol):
4447      """     """
4448      Returns the divergence of arg at where.     L{Symbol} representing the result of the interpolation operator
4449       """
4450       def __init__(self,arg,where):
4451          """
4452          initialization of interpolation L{Symbol} with argument arg
4453          @param arg: argument of the interpolation
4454          @type arg: L{Symbol}.
4455          @param where: FunctionSpace into which the argument is interpolated.
4456          @type where: L{escript.FunctionSpace}
4457          """
4458          super(Interpolate_Symbol,self).__init__(args=[arg,where],shape=arg.getShape(),dim=arg.getDim())
4459
4460      @param arg:   Data object representing the function which gradient to     def getMyCode(self,argstrs,format="escript"):
4461                    be calculated.        """
4462      @param where: FunctionSpace in which the gradient will be calculated.        returns a program code that can be used to evaluate the symbol.
If not present or C{None} an appropriate default is used.
"""
return trace(g,axis0=g.getRank()-2,axis1=g.getRank()-1)
4463
4464  def jump(arg):        @param argstrs: gives for each argument a string representing the argument for the evaluation.
4465      """        @type argstrs: C{str} or a C{list} of length 1 of C{str}.
4466      Returns the jump of arg across a continuity.        @param format: specifies the format to be used. At the moment only "escript" ,"text" and "str" are supported.
4467          @type format: C{str}
4468          @return: a piece of program code which can be used to evaluate the expression assuming the values for the arguments are available.
4469          @rtype: C{str}
4470          @raise: NotImplementedError: if the requested format is not available
4471          """
4472          if format=="escript" or format=="str"  or format=="text":
4473             return "interpolate(%s,where=%s)"%(argstrs[0],argstrs[1])
4474          else:
4475             raise NotImplementedError,"Trace_Symbol does not provide program code for format %s."%format
4476
4477      @param arg:   Data object representing the function which gradient     def substitute(self,argvals):
4478                    to be calculated.        """
4479      """        assigns new values to symbols in the definition of the symbol.
4480      d=arg.getDomain()        The method replaces the L{Symbol} u by argvals[u] in the expression defining this object.
return arg.interpolate(escript.FunctionOnContactOne())-arg.interpolate(escript.FunctionOnContactZero())
4481
4482  #=============================        @param argvals: new values assigned to symbols
4483  #        @type argvals: C{dict} with keywords of type L{Symbol}.
4484  # wrapper for various functions: if the argument has attribute the function name        @return: result of the substitution process. Operations are executed as much as possible.
4485  # as an argument it calls the corresponding methods. Otherwise the corresponding        @rtype: L{escript.Symbol}, C{float}, L{escript.Data}, L{numarray.NumArray} depending on the degree of substitution
4486  # numarray function is called.        @raise TypeError: if a value for a L{Symbol} cannot be substituted.
4487          """
4488          if argvals.has_key(self):
4489             arg=argvals[self]
4490             if self.isAppropriateValue(arg):
4491                return arg
4492             else:
4493                raise TypeError,"%s: new value is not appropriate."%str(self)
4494          else:
4495             arg=self.getSubstitutedArguments(argvals)
4496             return interpolate(arg[0],where=arg[1])
4497
4498  # functions involving the underlying Domain:     def diff(self,arg):
4499          """
4500          differential of this object
4501
4502  def transpose(arg,axis=None):        @param arg: the derivative is calculated with respect to arg
4503          @type arg: L{escript.Symbol}
4504          @return: derivative with respect to C{arg}
4505          @rtype: L{Symbol} but other types such as L{escript.Data}, L{numarray.NumArray}  are possible.
4506          """
4507          if arg==self:
4508             return identity(self.getShape())
4509          else:
4510             return interpolate(self.getDifferentiatedArguments(arg)[0],where=self.getArgument()[1])
4511
4512
4513    def div(arg,where=None):
4514      """      """
4515      Returns the transpose of the Data object arg.      returns the divergence of arg at where.
4516
4517      @param arg:      @param arg: function which divergence to be calculated. Its shape has to be (d,) where d is the spatial dimension.
4518        @type arg: L{escript.Data} or L{Symbol}
4519        @param where: FunctionSpace in which the divergence will be calculated.
4520                      If not present or C{None} an appropriate default is used.
4521        @type where: C{None} or L{escript.FunctionSpace}
4522        @return: divergence of arg.
4523        @rtype:  L{escript.Data} or L{Symbol}
4524      """      """
if axis==None:
r=0
if hasattr(arg,"getRank"): r=arg.getRank()
if hasattr(arg,"rank"): r=arg.rank
axis=r/2
4525      if isinstance(arg,Symbol):      if isinstance(arg,Symbol):
4526         return Transpose_Symbol(arg,axis=r)          dim=arg.getDim()
4527      if isinstance(arg,escript.Data):      elif isinstance(arg,escript.Data):
4528         # hack for transpose          dim=arg.getDomain().getDim()
r=arg.getRank()
if r!=2: raise ValueError,"Tranpose only avalaible for rank 2 objects"
s=arg.getShape()
out=escript.Data(0.,(s[1],s[0]),arg.getFunctionSpace())
for i in range(s[0]):
for j in range(s[1]):
out[j,i]=arg[i,j]
return out
# end hack for transpose
return arg.transpose(axis)
4529      else:      else:
4530         return numarray.transpose(arg,axis=axis)          raise TypeError,"div: argument type not supported"
4531        if not arg.getShape()==(dim,):
4532          raise ValueError,"div: expected shape is (%s,)"%dim
4534
4535  def trace(arg,axis0=0,axis1=1):  def jump(arg,domain=None):
4536      """      """
4537      Return      returns the jump of arg across the continuity of the domain
4538
4539      @param arg:      @param arg: argument
4540        @type arg: L{escript.Data} or L{Symbol}
4541        @param domain: the domain where the discontinuity is located. If domain is not present or equal to C{None}
4542                       the domain of arg is used. If arg is a L{Symbol} the domain must be present.
4543        @type domain: C{None} or L{escript.Domain}
4544        @return: jump of arg
4545        @rtype:  L{escript.Data} or L{Symbol}
4546      """      """
4547      if isinstance(arg,Symbol):      if domain==None: domain=arg.getDomain()
4548         s=list(arg.getShape())              return interpolate(arg,escript.FunctionOnContactOne(domain))-interpolate(arg,escript.FunctionOnContactZero(domain))
s=tuple(s[0:axis0]+s[axis0+1:axis1]+s[axis1+1:])
return Trace_Symbol(arg,axis0=axis0,axis1=axis1)
elif isinstance(arg,escript.Data):
# hack for trace
s=arg.getShape()
if s[axis0]!=s[axis1]:
raise ValueError,"illegal axis in trace"
out=escript.Scalar(0.,arg.getFunctionSpace())
for i in range(s[axis0]):
out+=arg[i,i]
return out
# end hack for trace
else:
return numarray.trace(arg,axis0=axis0,axis1=axis1)
4549
4550    def L2(arg):
4551        """
4552        returns the L2 norm of arg at where
4553
4554        @param arg: function which L2 to be calculated.
4555        @type arg: L{escript.Data} or L{Symbol}
4556        @return: L2 norm of arg.
4557        @rtype:  L{float} or L{Symbol}
4558        @note: L2(arg) is equivalent to sqrt(integrate(inner(arg,arg)))
4559        """
4560        return sqrt(integrate(inner(arg,arg)))
4561    #=============================
4562    #
4563
4564  def reorderComponents(arg,index):  def reorderComponents(arg,index):
4565      """      """
4566      resorts the component of arg according to index      resorts the component of arg according to index
4567
4568      """      """
4569      pass      raise NotImplementedError
4570  #  #
4571  # \$Log: util.py,v \$  # \$Log: util.py,v \$
4572  # Revision 1.14.2.16  2005/10/19 06:09:57  gross  # Revision 1.14.2.16  2005/10/19 06:09:57  gross

Legend:
 Removed from v.329 changed lines Added in v.529