1 """
2 Non-standard interpolation methods.
3 """
4 import numpy as np
5 from scipy import ndimage
6 from astropy.io import fits as pf
7 import time
8 import itertools
9
10 -def __df_dx(oldx,oldy,index,sharp=False):
11 """
12 Preliminary estimation of df/dx
13 """
14 xm1,fm1 = oldx[index-1],oldy[index-1]
15 x ,f = oldx[index] ,oldy[index]
16 xp1,fp1 = oldx[index+1],oldy[index+1]
17
18 if not sharp:
19 df_dx = 1./(xp1-xm1) * ( fp1*(x-xm1)/(xp1-x) - fm1*(xp1-x)/(x-xm1)) + \
20 f*(xp1-2*x+xm1) / ( (x-xm1)*(xp1-x))
21 else:
22 df_dx = min( (fp1-f)/(xp1-x), (f-fm1)/(x-xm1) )
23 return df_dx
24
25
26 -def __P1(x,x0,x1): return (x-x1)**2 * (2*x-3*x0+x1) / (x1-x0)**3
27 -def __P2(x,x0,x1): return -(x-x0)**2 * (2*x-3*x1+x0) / (x1-x0)**3
28 -def __P3(x,x0,x1): return (x-x0) * (x-x1)**2 / (x1-x0)**2
29 -def __P4(x,x0,x1): return (x-x0)**2 * (x-x1) / (x1-x0)**2
30
32 """
33 A local interpolation method by a polynomial of degree 3.
34
35 After Marc-Antoine Dupret, 2002 (extended version of PhD thesis).
36
37 Cannot extrapolate!
38
39 >>> np.random.seed(1114)
40 >>> oldx = np.sort(np.random.uniform(size=10))
41 >>> oldy = oldx**2#np.random.uniform(size=10)
42 >>> oldy[5:] = -oldx[5:]**2
43 >>> newx = np.linspace(oldx.min(),oldx.max(),1000)
44 >>> newy,disconts = local_interpolation(newx,oldx,oldy,full_output=True)
45 >>> newy_ = local_interpolation(newx,oldx,oldy)
46
47 >>> sharpy = newy.copy()
48 >>> sharpy[disconts] = np.nan
49 >>> smoothy = newy.copy()
50 >>> smoothy[-disconts] = np.nan
51 >>> p = pl.figure()
52 >>> p = pl.plot(oldx,oldy,'ks-',ms=10)
53 >>> p = pl.plot(newx,smoothy,'go-',lw=2,ms=2,mec='g')
54 >>> p = pl.plot(newx,sharpy,'ro-',lw=2,ms=2,mec='r')
55 >>> p = pl.plot(newx,newy_,'bo--',lw=2,ms=2,mec='b')
56
57 @param newx: new x-array to interpolate on
58 @type newx: ndarray
59 @param oldx: old x-array to interpolate from
60 @type oldx: ndarray
61 @param oldy: old y-array to interpolate from
62 @type oldy: ndarray
63 @param full_output: also return points where discontinuities were detected
64 @type full_output: boolean
65 @return: interpolated array(, discontinuities)
66 @rtype: ndarray(,ndarray)
67 """
68
69
70 lastx = 2*oldx[-1]-oldx[-2]
71 lasty = (oldy[-1]-oldy[-2])/(oldx[-1]-oldx[-2])*(oldx[-1]-lastx) + oldy[-1]
72 oldy = np.hstack([oldy,lasty])
73 oldx = np.hstack([oldx,lastx])
74
75 newy = np.zeros_like(newx)
76
77 if full_output:
78 disconts = np.zeros(len(newx),bool)
79
80
81 index = -1
82 for i,x in enumerate(newx):
83 index = oldx.searchsorted(x)
84
85
86 x0,f0 = oldx[index-1],oldy[index-1]
87 x1,f1 = oldx[index],oldy[index]
88 x2,f2 = oldx[index-2],oldy[index-2]
89
90
91
92 numerator = ((x1-x0)*(f1-f2))
93 denominator = ((f1-f0)*(x1-x2))
94
95 if denominator==0:
96 sharpness = 0.
97 else:
98 sharpness = numerator/denominator
99 sharp = (0.2<=sharpness<=0.5)
100 if full_output:
101 disconts[i] = sharp
102
103 dfdx0 = __df_dx(oldx,oldy,index-1,sharp=sharp)
104 dfdx1 = __df_dx(oldx,oldy,index,sharp=sharp)
105
106
107
108 P1 = (x-x1)**2 * (2*x-3*x0+x1) / (x1-x0)**3
109 P2 = -(x-x0)**2 * (2*x-3*x1+x0) / (x1-x0)**3
110 P3 = (x-x0) * (x-x1)**2 / (x1-x0)**2
111 P4 = (x-x0)**2 * (x-x1) / (x1-x0)**2
112
113
114 Px = f0*P1 + f1*P2 + dfdx0*P3 + dfdx1*P4
115 newy[i] = Px
116 if full_output:
117 return newy,disconts
118 else:
119 return newy
120
121
123
124
125 points = np.zeros((len(args),3))
126 for _x in args:
127 index = oldx.searchsorted(_x)
128 x0,f0 = oldx[index-1],oldy[index-1]
129 x1,f1 = oldx[index],oldy[index]
130 x2,f2 = oldx[index-2],oldy[index-2]
131
132 polynomials = []
133
134
136 """
137 Creates pixelgrid and arrays of axis values.
138
139 Starting from:
140 * grid_pars: 2D numpy array, 1 column per parameter, unlimited number of cols
141 * grid_data: 2D numpy array, 1 column per variable, data corresponding to the rows in grid_pars
142
143 The grid should be rectangular and complete, i.e. every combination of the unique values in the
144 parameter columns should exist. If not, a nan value will be inserted.
145
146 @param grid_pars: Npar x Ngrid array of parameters
147 @type grid_pars: array
148 @param grid_data: Ndata x Ngrid array of data
149 @type grid_data:array
150 @return: axis values and pixelgrid
151 @rtype: array, array
152 """
153
154 uniques = [np.unique(column, return_inverse=True) for column in grid_pars]
155
156
157 axis_values = [uniques_[0] for uniques_ in uniques]
158 unique_val_indices = [uniques_[1] for uniques_ in uniques]
159
160 data_dim = np.shape(grid_data)[0]
161
162 par_dims = [len(uv[0]) for uv in uniques]
163
164 par_dims.append(data_dim)
165 pixelgrid = np.ones(par_dims)
166
167
168
169 pixelgrid[pixelgrid==1] = np.inf
170
171
172 indices = [uv[1] for uv in uniques]
173 pixelgrid[indices] = grid_data.T
174 return axis_values, pixelgrid
175
177 """
178 Interpolates in a grid prepared by create_pixeltypegrid().
179
180 p is an array of parameter arrays
181
182 @param p: Npar x Ninterpolate array
183 @type p: array
184 @return: Ndata x Ninterpolate array
185 @rtype: array
186 """
187
188
189
190
191
192
193 p_ = []
194 for av_,val in zip(axis_values,p):
195 indices = np.searchsorted(av_,val)
196 indices[indices==len(av_)] = len(av_)-1
197 p_.append(indices)
198
199
200
201
202 for i, ax in enumerate(axis_values):
203 p[i] = np.array(p[i], dtype = ax.dtype)
204
205
206 p_ = np.array([np.searchsorted(av_,val) for av_, val in zip(axis_values,p)])
207 lowervals_stepsize = np.array([[av_[p__-1], av_[p__]-av_[p__-1]] \
208 for av_, p__ in zip(axis_values,p_)])
209 p_coord = (p-lowervals_stepsize[:,0])/lowervals_stepsize[:,1] + np.array(p_)-1
210
211
212 return np.array([ndimage.map_coordinates(pixelgrid[...,i],p_coord, order=1, prefilter=False) \
213 for i in range(np.shape(pixelgrid)[-1])])
214
215
216
217
218 if __name__=='__main__':
219 import pylab as pl
220
221
222
223
224 np.random.seed(1114)
225 oldx = np.sort(np.random.uniform(size=10))
226 oldy = oldx**2
227 oldy[5:] = -oldx[5:]**2
228 newx = np.linspace(oldx.min(),oldx.max(),1000)
229 newy,disconts = local_interpolation(newx,oldx,oldy,full_output=True)
230 newy_ = local_interpolation(newx,oldx,oldy)
231
232 sharpy = newy.copy()
233 sharpy[disconts] = np.nan
234 smoothy = newy.copy()
235 smoothy[-disconts] = np.nan
236 p = pl.figure()
237 p = pl.plot(oldx,oldy,'ks-',ms=10)
238 p = pl.plot(newx,smoothy,'go-',lw=2,ms=2,mec='g')
239 p = pl.plot(newx,sharpy,'ro-',lw=2,ms=2,mec='r')
240 p = pl.plot(newx,newy_,'bo--',lw=2,ms=2,mec='b')
241
242 pl.show()
243