source: inundation-numpy-branch/utilities/numerical_tools.py @ 2546

Last change on this file since 2546 was 2545, checked in by ole, 19 years ago

Got utilities to compile and pass all tests using numpy

File size: 5.5 KB
Line 
1#!/usr/bin/env python
2"""Auxiliary numerical tools
3
4"""
5
6
7#Establish which Numeric package to use
8#(this should move to somewhere central)
9try:
10    from numpy import ArrayType, array, sum, innerproduct, ravel, sqrt, searchsorted, sort, concatenate   
11except:
12    print 'Could not find numpy - using Numeric'
13    from Numeric import ArrayType, array, sum, innerproduct, ravel, sqrt, searchsorted, sort, concatenate   
14   
15
16def angle(v):
17    """Compute angle between e1 (the unit vector in the x-direction)
18    and the specified vector
19    """
20
21    from math import acos, pi, sqrt
22
23    l = sqrt( sum (array(v)**2))
24    v1 = v[0]/l
25    v2 = v[1]/l
26
27
28    theta = acos(v1)
29   
30    #try:
31    #   theta = acos(v1)
32    #except ValueError, e:
33    #    print 'WARNING (util.py): Angle acos(%s) failed: %s' %(str(v1), e)
34    #
35    #    #FIXME, hack to avoid acos(1.0) Value error
36    #    # why is it happening?
37    #    # is it catching something we should avoid?
38    #    #FIXME (Ole): When did this happen? We need a unit test to
39    #    #reveal this condition or otherwise remove the hack
40    #   
41    #    s = 1e-6
42    #    if (v1+s >  1.0) and (v1-s < 1.0) :
43    #        theta = 0.0
44    #    elif (v1+s >  -1.0) and (v1-s < -1.0):
45    #        theta = 3.1415926535897931
46    #    print 'WARNING (util.py): angle v1 is %f, setting acos to %f '\
47    #          %(v1, theta)
48
49    if v2 < 0:
50        #Quadrant 3 or 4
51        theta = 2*pi-theta
52
53    return theta
54
55
56def anglediff(v0, v1):
57    """Compute difference between angle of vector x0, y0 and x1, y1.
58    This is used for determining the ordering of vertices,
59    e.g. for checking if they are counter clockwise.
60
61    Always return a positive value
62    """
63
64    from math import pi
65
66    a0 = angle(v0)
67    a1 = angle(v1)
68
69    #Ensure that difference will be positive
70    if a0 < a1:
71        a0 += 2*pi
72
73    return a0-a1
74
75
76def mean(x):
77    """Mean value of a vector
78    """
79    return(float(sum(x))/len(x))
80
81
82def cov(x, y=None):
83    """Covariance of vectors x and y.
84
85    If y is None: return cov(x, x)
86    """
87   
88    if y is None:
89        y = x
90
91    assert(len(x)==len(y))
92    N = len(x)
93 
94    cx = x - mean(x) 
95    cy = y - mean(y) 
96
97    p = innerproduct(cx,cy)/N
98    return(p)
99
100
101def err(x, y=0, n=2, relative=True):
102    """Relative error of ||x-y|| to ||y||
103       n = 2:    Two norm
104       n = None: Max norm
105
106       If denominator evaluates to zero or if y is omitted,
107       absolute error is returned
108    """
109
110    x = ensure_numeric(x)
111    if y:
112        y = ensure_numeric(y)       
113
114    if n == 2:
115        err = norm(x-y)
116        if relative is True:
117            try:
118                err = err/norm(y)
119            except:
120                pass
121
122    else:
123        err = max(abs(x-y))
124        if relative is True:
125            try:
126                err = err/max(abs(y))   
127            except:
128                pass
129         
130    return err
131 
132
133def norm(x):
134    """2-norm of x
135    """
136 
137    y = ravel(x)
138    p = sqrt(innerproduct(y,y))
139    return p
140   
141 
142def corr(x, y=None):
143    """Correlation of x and y
144    If y is None return autocorrelation of x
145    """
146
147    from math import sqrt
148    if y is None:
149        y = x
150
151    varx = cov(x)
152    vary = cov(y)
153
154    if varx == 0 or vary == 0:
155        C = 0
156    else: 
157        C = cov(x,y)/sqrt(varx * vary)   
158
159    return(C)
160
161
162       
163def ensure_numeric(A, typecode = None):
164    """Ensure that sequence is a Numeric array.
165    Inputs:
166        A: Sequence. If A is already a Numeric array it will be returned
167                     unaltered
168                     If not, an attempt is made to convert it to a Numeric
169                     array
170        typecode: Numeric type. If specified, use this in the conversion.
171                                If not, let Numeric decide
172
173    This function is necessary as array(A) can cause memory overflow.
174    """
175
176    if typecode is None:
177        if type(A) == ArrayType:
178            return A
179        else:
180            return array(A)
181    else:
182        if type(A) == ArrayType:
183            if A.dtype.char == typecode:
184                return array(A)  #FIXME: Shouldn't this just return A?
185            else:
186                return A.astype(typecode)
187        else:
188            return array(A).astype(typecode)
189
190
191
192
193def histogram(a, bins):
194    """Standard histogram straight from the Numeric manual
195    """
196
197    n = searchsorted(sort(a), bins)
198    n = concatenate( [n, [len(a)]] )
199    return n[1:]-n[:-1]
200
201
202
203####################################################################
204#Python versions of function that are also implemented in numerical_tools_ext.c
205#
206
207def gradient_python(x0, y0, x1, y1, x2, y2, q0, q1, q2):
208    """
209    """
210
211    det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0)
212    a = (y2-y0)*(q1-q0) - (y1-y0)*(q2-q0)
213    a /= det
214
215    b = (x1-x0)*(q2-q0) - (x2-x0)*(q1-q0)
216    b /= det
217
218    return a, b
219
220
221def gradient2_python(x0, y0, x1, y1, q0, q1):
222    """Compute radient based on two points and enforce zero gradient
223    in the direction orthogonal to (x1-x0), (y1-y0)
224    """
225
226    #Old code
227    #det = x0*y1 - x1*y0
228    #if det != 0.0:
229    #    a = (y1*q0 - y0*q1)/det
230    #    b = (x0*q1 - x1*q0)/det
231
232    #Correct code (ON)
233    det = (x1-x0)**2 + (y1-y0)**2
234    if det != 0.0:
235        a = (x1-x0)*(q1-q0)/det
236        b = (y1-y0)*(q1-q0)/det
237       
238    return a, b       
239
240
241##############################################
242#Initialise module
243
244#from utilities import compile
245import compile
246if compile.can_use_C_extension('util_ext.c'):
247    from util_ext import gradient, gradient2
248else:
249    gradient = gradient_python
250    gradient2 = gradient2_python   
251
252
253if __name__ == "__main__":
254    pass
255
Note: See TracBrowser for help on using the repository browser.