File: spline.py

package info (click to toggle)
sixpack 1%3A0.64-2
  • links: PTS
  • area: contrib
  • in suites: lenny
  • size: 1,280 kB
  • ctags: 584
  • sloc: python: 10,175; makefile: 64
file content (154 lines) | stat: -rw-r--r-- 3,930 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import func
from Numeric import *

BadInput = "Bad xa input to routine splint."

class Spline(func.FuncOps):
    def __init__(self, x_array, y_array, low_slope=None, high_slope=None):
	self.x_vals = x_array
	self.y_vals = y_array
	self.low_slope  = low_slope
	self.high_slope = high_slope
	# must be careful, so that a slope of 0 still works...
	if low_slope is not None:
	    self.use_low_slope  = 1
	else:
	    self.use_low_slope  = 0   # i.e. false
	if high_slope is not None:
	    self.use_high_slope = 1
	else:
	    self.use_high_slope = 0
	self.calc_ypp()
   
    def calc_ypp(self):
	x_vals = self.x_vals
	y_vals = self.y_vals
	n = len(x_vals)
	y2_vals  = zeros(n, Float)
	u        = zeros(n-1, Float)
	
	if self.use_low_slope:
	    u[0] = (3.0/(x_vals[1]-x_vals[0])) * \
		   ((y_vals[1]-y_vals[0])/
		    (x_vals[1]-x_vals[0])-self.low_slope)
	    y2_vals[0] = -0.5
	else:
	    u[0] = 0.0
	    y2_vals[0] = 0.0   # natural spline
	    
	for i in range(1, n-1):
	    sig = (x_vals[i]-x_vals[i-1]) / \
		  (x_vals[i+1]-x_vals[i-1])
	    p   = sig*y2_vals[i-1]+2.0
	    y2_vals[i] = (sig-1.0)/p
	    u[i] = (y_vals[i+1]-y_vals[i]) / \
		   (x_vals[i+1]-x_vals[i]) - \
		   (y_vals[i]-y_vals[i-1])/ \
		   (x_vals[i]-x_vals[i-1])
	    u[i] = (6.0*u[i]/(x_vals[i+1]-x_vals[i-1]) - 
		    sig*u[i-1]) / p
	    
	if self.use_high_slope:
	    qn = 0.5
	    un = (3.0/(x_vals[n-1]-x_vals[n-2])) * \
		 (self.high_slope - (y_vals[n-1]-y_vals[n-2]) /
		  (x_vals[n-1]-x_vals[n-2]))
	else:
	    qn = 0.0
	    un = 0.0    # natural spline
      
	y2_vals[n-1] = (un-qn*u[n-2])/(qn*y2_vals[n-1]+1.0)

	rng = range(n-1)
	rng.reverse()
	for k in rng:         # backsubstitution step
	    y2_vals[k] = y2_vals[k]*y2_vals[k+1]+u[k]
	self.y2_vals = y2_vals
      
      
    # compute approximation
    def __call__(self, arg):
	"Simulate a ufunc; handle being called on an array."
	if type(arg) == func.ArrayType:
	    return func.array_map(self.call, arg)
	else:
	    return self.call(arg)

    def call(self, x):
	"Evaluate the spline, assuming x is a scalar."

	# if out of range, return endpoint
	if x <= self.x_vals[0]:
	    return self.y_vals[0]
	if x >= self.x_vals[-1]:
	    return self.y_vals[-1]

	pos = searchsorted(self.x_vals, x)
      
	h = self.x_vals[pos]-self.x_vals[pos-1]
	if h == 0.0:
	    raise BadInput
      
	a = (self.x_vals[pos] - x) / h
	b = (x - self.x_vals[pos-1]) / h
	return (a*self.y_vals[pos-1] + b*self.y_vals[pos] + \
		((a*a*a - a)*self.y2_vals[pos-1] + \
		 (b*b*b - b)*self.y2_vals[pos]) * h*h/6.0)


class LinInt(func.FuncOps):
    def __init__(self, x_array, y_array):
	self.x_vals = x_array
	self.y_vals = y_array
      
    # compute approximation
    def __call__(self, arg):
	"Simulate a ufunc; handle being called on an array."
	if type(arg) == func.ArrayType:
	    return func.array_map(self.call, arg)
	else:
	    return self.call(arg)

    def call(self, x):
	"Evaluate the interpolant, assuming x is a scalar."

	# if out of range, return endpoint
	if x <= self.x_vals[0]:
	    return self.y_vals[0]
	if x >= self.x_vals[-1]:
	    return self.y_vals[-1]

	pos = searchsorted(self.x_vals, x)
      
	h = self.x_vals[pos]-self.x_vals[pos-1]
	if h == 0.0:
	    raise BadInput
      
	a = (self.x_vals[pos] - x) / h
	b = (x - self.x_vals[pos-1]) / h
	return a*self.y_vals[pos-1] + b*self.y_vals[pos]

def spline_interpolate(x1, y1, x2):
    """
    Given a function at a set of points (x1, y1), interpolate to
    evaluate it at points x2.
    """
    sp = Spline(x1, y1)
    return sp(x2)

def logspline_interpolate(x1, y1, x2):
    """
    Given a function at a set of points (x1, y1), interpolate to
    evaluate it at points x2.
    """
    sp = Spline(log(x1), log(y1))
    return exp(sp(log(x2)))


def linear_interpolate(x1, y1, x2):
    """
    Given a function at a set of points (x1, y1), interpolate to
    evaluate it at points x2.
    """
    li = LinInt(x1, y1)
    return li(x2)