source: inundation/utilities/numerical_tools.py @ 2612

Last change on this file since 2612 was 2573, checked in by duncan, 19 years ago

bug fixing, adding infinite variable to use with Numeric

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