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