1 /***************************************************************************
2 interpolate.cpp - all things related to interpol command
3 -------------------
4 begin : Mar 30 2021
5 copyright : (C) 2004 by Joel Gales
6 : (C) 2018 G. Duvert
7 email : see https://github.com/gnudatalanguage/gdl
8 ***************************************************************************/
9
10 /***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
19 #include "includefirst.hpp"
20
21 #include "datatypes.hpp"
22 #include "envt.hpp"
23 #include "dinterpreter.hpp"
24
25 #ifdef _MSC_VER
26 #define isfinite _finite
27 #endif
28
29 //interpolate
30 #include <gsl/gsl_errno.h>
31 #include <gsl/gsl_interp.h>
32 #include <gsl/gsl_spline.h>
33 #include <gsl/gsl_nan.h>
34
35 using std::isfinite;
36
37 /* convolutions available */
linConv(double d,double x0,double x1)38 inline double linConv(double d, double x0, double x1) {
39 return (1. - d)*x0 + d*x1;
40 }
41
42 typedef struct {
43 const char* name;
44 unsigned int min_size;
45 void* (*alloc)(ssize_t size);
46 int (*init)(void*, const double xa[], const double ta[], ssize_t xsize);
47 int (*eval)(const void*, const double xa[], const double ta[], ssize_t xsize, double x, gsl_interp_accel*, ssize_t *lastval, double* lastCoefs, double *t);
48 void (*free)(void*);
49 } gdl_interpol_type;
50
51 typedef struct {
52 const gdl_interpol_type* type;
53 double xmin;
54 double xmax;
55 ssize_t xsize;
56 void* state;
57 ssize_t * lastval;
58 double * lastCoefs; //if last index is same, use last coefs
59 } gdl_interpol;
60
gdl_interpol_type_min_size(const gdl_interpol_type * T)61 ssize_t gdl_interpol_type_min_size(const gdl_interpol_type* T) {
62 return T->min_size;
63 }
64
gdl_interpol_min_size(const gdl_interpol * interp)65 ssize_t gdl_interpol_min_size(const gdl_interpol* interp) {
66 return interp->type->min_size;
67 }
68
gdl_interpol_name(const gdl_interpol * interp)69 const char* gdl_interpol_name(const gdl_interpol* interp) {
70 return interp->type->name;
71 }
72
73 GSL_VAR const gdl_interpol_type* gdl_interpol_linear;
74 GSL_VAR const gdl_interpol_type* gdl_interpol_quadratic;
75 GSL_VAR const gdl_interpol_type* gdl_interpol_spline;
76
77 double gdl_interpol_eval(const gdl_interpol* interp, const double xarr[], const double tarr[], const double x, gsl_interp_accel* xa);
78
gdl_interpol_alloc(const gdl_interpol_type * T,ssize_t xsize)79 gdl_interpol* gdl_interpol_alloc(const gdl_interpol_type* T, ssize_t xsize) {
80 gdl_interpol* interp;
81 interp = (gdl_interpol*) malloc(sizeof (gdl_interpol));
82 if (interp == NULL) {
83 GSL_ERROR_NULL("failed to allocate space for gdl_interpol struct", GSL_ENOMEM);
84 }
85 interp->type = T;
86 interp->xsize = xsize;
87 if (interp->type->alloc == NULL) {
88 interp->state = NULL;
89 return interp;
90 }
91 interp->state = interp->type->alloc(xsize);
92 if (interp->state == NULL) {
93 free(interp);
94 GSL_ERROR_NULL("failed to allocate space for gdl_interpol state", GSL_ENOMEM);
95 }
96 return interp;
97 }
98
gdl_interpol_init(gdl_interpol * interp,const double xarr[],const double tarr[],ssize_t xsize)99 int gdl_interpol_init(gdl_interpol* interp, const double xarr[], const double tarr[], ssize_t xsize) {
100 ssize_t i;
101 if (xsize != interp->xsize) {
102 GSL_ERROR("data must match size of interpolation object", GSL_EINVAL);
103 }
104 for (i = 1; i < xsize; i++) {
105 if (xarr[i - 1] >= xarr[i]) {
106 // GSL_ERROR("x values must be strictly increasing", GSL_EINVAL);
107 Message ("X values are not strictly increasing, INTERPOL may give incorrect results");
108 break;
109 }
110 }
111 interp->xmin = xarr[0];
112 interp->xmax = xarr[xsize - 1];
113 int status = interp->type->init(interp->state, xarr, tarr, xsize);
114 //allocate lastCoefs and set lastval to -1:
115 interp->lastval=(ssize_t*)malloc(1*sizeof(ssize_t));
116 interp->lastval[0]=-1;
117 interp->lastCoefs=(double*)malloc(2*interp->type->min_size*sizeof(double)); //overkill in most cases.
118 return status;
119 }
gdl_interpol_free(gdl_interpol * interp)120 void gdl_interpol_free(gdl_interpol* interp) {
121 if (!interp) {
122 return;
123 }
124 if (interp->type->free) {
125 interp->type->free(interp->state);
126 }
127 free(interp->lastval);
128 free(interp->lastCoefs);
129 free(interp);
130 }
131
gdl_interpol_eval(const gdl_interpol * interp,const double xarr[],const double tarr[],const double x,gsl_interp_accel * xa)132 double gdl_interpol_eval(const gdl_interpol* interp, const double xarr[], const double tarr[], const double x, gsl_interp_accel* xa) {
133 double xx, t;
134 xx = x;
135 int status;
136 status = interp->type->eval(interp->state, xarr, tarr, interp->xsize, xx, xa, interp->lastval, interp->lastCoefs, &t);
137 if ((status) != GSL_SUCCESS) GSL_ERROR_VAL("interpolation error", (status), GSL_NAN);
138
139 return t;
140 }
linear_init(void * state,const double xa[],const double ta[],ssize_t xsize)141 static int linear_init(void* state, const double xa[], const double ta[], ssize_t xsize) {
142 return GSL_SUCCESS;
143 }
quadratic_init(void * state,const double xa[],const double ta[],ssize_t xsize)144 static int quadratic_init(void* state, const double xa[], const double ta[], ssize_t xsize) {
145 return GSL_SUCCESS;
146 }
147
linear_eval(const void * state,const double xarr[],const double tarr[],ssize_t xsize,double x,gsl_interp_accel * xa,ssize_t * lastval,double * C,double * t)148 static int linear_eval(const void* state, const double xarr[], const double tarr[], ssize_t xsize, double x, gsl_interp_accel* xa, ssize_t* lastval, double* C, double *t) {
149 ssize_t xi = gsl_interp_accel_find(xa, xarr, xsize, x); //xa must be ALWAYS defined for GDL
150 if (xi != *lastval) {
151 *lastval = xi;
152 ssize_t xp = (xi + 1 < xsize) ? xi + 1 : xi;
153 C[0] = tarr[xi];
154 C[1] = tarr[xp];
155 C[2] = xarr[xi];
156 C[3] = xarr[xp]-xarr[xi];
157 }
158 double u = (C[3] > 0.0) ? (x - C[2]) / C[3] : 0.0;
159 *t = linConv(u, C[0], C[1]);
160 return GSL_SUCCESS;
161 }
162
quadratic_eval(const void * state,const double xarr[],const double tarr[],ssize_t xsize,double x,gsl_interp_accel * xa,ssize_t * lastval,double * C,double * t)163 static int quadratic_eval(const void* state, const double xarr[], const double tarr[], ssize_t xsize, double x, gsl_interp_accel* xa, ssize_t* lastval, double* C, double *t) {
164 ssize_t xi = gsl_interp_accel_find(xa, xarr, xsize, x);//xa must be ALWAYS defined for GDL
165 if (xi != *lastval) {
166 *lastval = xi;
167 ssize_t xp, xm;
168 if ( xi+1 >= xsize ) { xp = xsize-1; xi = xsize-2; xm=xsize-3;}
169 else if ( xi-1 < 0 ) { xm = 0; xi = 1; xp=2; }
170 else { xm=xi-1; xp=xi+1;}
171 C[3] = tarr[xm];
172 C[4] = tarr[xi];
173 C[5] = tarr[xp];
174 C[0] = xarr[xm];
175 C[1] = xarr[xi];
176 C[2] = xarr[xp];
177 }
178 *t = (C[3] * (x-C[1]) * (x-C[2]) / ((C[0]-C[1]) * (C[0]-C[2]))) + (C[4] * (x-C[0]) * (x-C[2]) / ((C[1]-C[0]) * (C[1]-C[2])))+ (C[5] * (x-C[0]) * (x-C[1]) / ((C[2]-C[0]) * (C[2]-C[1])));
179 return GSL_SUCCESS;
180 }
181
182 static const gdl_interpol_type linear_type = {
183 "linear",
184 2,
185 NULL,
186 &linear_init,
187 &linear_eval
188 };
189
190 static const gdl_interpol_type quadratic_type = {
191 "quadratic",
192 3,
193 NULL,
194 &quadratic_init,
195 &quadratic_eval
196 };
197
198 const gdl_interpol_type* gdl_interpol_linear = &linear_type;
199 const gdl_interpol_type* gdl_interpol_quadratic = &quadratic_type;
200
201 #if defined(USE_EIGEN)
202 GSL_VAR const gdl_interpol_type* gdl_interpol_lsquadratic;
lsquadratic_init(void * state,const double xa[],const double ta[],ssize_t xsize)203 static int lsquadratic_init(void* state, const double xa[], const double ta[], ssize_t xsize) {
204 return GSL_SUCCESS;
205 }
206
207 #include <Eigen/LU>
208 #include <Eigen/Eigenvalues>
209 #include <Eigen/Core>
210 //no need to use another complicated general GSL solution -- just the same as IDL's procedure.
lsquadratic_eval(const void * state,const double xarr[],const double tarr[],ssize_t xsize,double pos,gsl_interp_accel * xa,ssize_t * lastval,double * C,double * t)211 static int lsquadratic_eval(const void* state, const double xarr[], const double tarr[], ssize_t xsize, double pos, gsl_interp_accel* xa, ssize_t* lastval, double* C, double *t) {
212 ssize_t xi = gsl_interp_accel_find(xa, xarr, xsize, pos);//xa must be ALWAYS defined for GDL
213 if (xi != *lastval) {
214 *lastval = xi;
215 ssize_t x[4];
216 //make in range
217 if ( xi+2 >= xsize ) { x[0]=xsize-4; x[1]=xsize-3; x[2] = xsize-2; x[3] = xsize-1;}
218 else if ( xi-1 < 0 ) { x[0] = 0; x[1] = 1; x[2]=2; x[3]=3;}
219 else { x[0]=xi-1; x[1]= xi; x[2]=xi+1; x[3]=xi+2;}
220 // least_square fit of a 2nd degree polynomial on these 4 points:
221 double matrix[]={xarr[x[0]]*xarr[x[0]],xarr[x[0]],1.0,xarr[x[1]]*xarr[x[1]],xarr[x[1]],
222 1.0,xarr[x[2]]*xarr[x[2]],xarr[x[2]],1.0,xarr[x[3]]*xarr[x[3]],xarr[x[3]],1.0};
223 Eigen::MatrixXd A(4,3) ; //<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> > A(matrix, 3,4);
224 for (int i=0; i< 3; ++i) for (int j=0; j<4; ++j) A(j,i)=matrix[j*3+i];
225 Eigen::Vector4d b(tarr[x[0]],tarr[x[1]],tarr[x[2]],tarr[x[3]]);
226 Eigen::MatrixXd r=(A.transpose() * A).ldlt().solve(A.transpose() * b);
227 C[0] = r.coeff(0);
228 C[1] = r.coeff(1);
229 C[2] = r.coeff(2);
230 }
231 *t= C[2] + C[1]* pos + C[0] * pos*pos;
232 return GSL_SUCCESS;
233 }
234 static const gdl_interpol_type lsquadratic_type = {
235 "lsquadratic",
236 4,
237 NULL,
238 &lsquadratic_init,
239 &lsquadratic_eval
240 };
241 const gdl_interpol_type* gdl_interpol_lsquadratic = &lsquadratic_type;
242 #endif
243
244 #if defined(USE_EIGEN)
245 GSL_VAR const gdl_interpol_type* gdl_interpol_cspline;
cspline_init(void * state,const double xa[],const double ta[],ssize_t xsize)246 static int cspline_init(void* state, const double xa[], const double ta[], ssize_t xsize) {
247 return GSL_SUCCESS;
248 }
249
250 #include <Eigen/LU>
251 #include <Eigen/Eigenvalues>
252 #include <Eigen/Core>
cspline_eval(const void * state,const double xarr[],const double tarr[],ssize_t xsize,double pos,gsl_interp_accel * xa,ssize_t * lastval,double * C,double * t)253 static int cspline_eval(const void* state, const double xarr[], const double tarr[], ssize_t xsize, double pos, gsl_interp_accel* xa, ssize_t* lastval, double* C, double *t) {
254 ssize_t xii = gsl_interp_accel_find(xa, xarr, xsize, pos); //xa must be ALWAYS defined for GDL
255 //xii in range [0: xsize-2]--> the real index, produces 4 derivatives C[0..3], but we save the 2 to be used.
256 //use xi to select the good 4 points on either end, and the good C[] to be used afterwards.
257 ssize_t xi=xii;
258 if ( xi == xsize-2 ) xi=xsize-3; else if ( xi == 0 ) xi=1;
259 double dx=xarr[xii+1]-xarr[xii];
260 //acceleration: do not recompute.
261 if (xii != *lastval) {
262 *lastval = xii;
263 double dx0 = 1 / (xarr[xi] - xarr[xi-1]);
264 double dx1 = 1 / (xarr[xi+1] - xarr[xi]);
265 double dx2 = 1 / (xarr[xi + 2] - xarr[xi + 1]);
266 double b0 = 3 * dx0 * dx0 * (tarr[xi] - tarr[xi-1]);
267 double b1 = 3 * dx1 * dx1 * (tarr[xi+1] - tarr[xi]);
268 double b2 = 3 * dx2 * dx2 * (tarr[xi + 2] - tarr[xi + 1]);
269 // cspline solution on these 4 points:
270 double matrix[] = {2 * dx0, dx0, 0, 0, dx0, 2 * (dx0 + dx1), dx1, 0, 0, dx1, 2 * (dx1+dx2),dx2,0,0,dx2,2*dx2};
271 Eigen::MatrixXd A(4, 4);
272 for (int i = 0; i < 4; ++i) for (int j = 0; j < 4; ++j) A(j, i) = matrix[j * 4 + i];
273 Eigen::Vector4d b(b0, b0+b1, b1+b2, b2);
274 Eigen::MatrixXd r = (A.transpose() * A).ldlt().solve(A.transpose() * b);
275 if (xii == 0) {C[0] = r.coeff(0); C[1] = r.coeff(1); }
276 else if (xii == xsize-2) {C[0] = r.coeff(2); C[1] = r.coeff(3); }
277 else {C[0] = r.coeff(1); C[1] = r.coeff(2); }
278 double dy=tarr[xii+1]-tarr[xii];
279 C[0] = C[0]*dx-dy;
280 C[1] = C[1]*-dx+dy;
281 }
282 double dpos=(pos-xarr[xii])/dx;
283 *t= (1-dpos)*tarr[xii]+dpos*tarr[xii+1]+dpos*(1-dpos)*((1-dpos)*C[0]+dpos*C[1]);
284 // double dpos=pos-xarr[xii]; double dpos3=dpos*dpos*dpos; double dpos2=dpos*dpos;
285 // *t=(2*dpos3-3*dpos2+1)*tarr[xii]+(dpos3-2*dpos2+dpos)*C[0]+(-2*dpos3+3*dpos2)*tarr[xii+1]+(dpos3-dpos2)*C[1];
286 //Catmull-Rom Spline (not the good one!) : double u=pos-xarr[xi]; *t=0.5*(((-tarr[xi-1]+3*tarr[xi]-3*tarr[xi+1]+tarr[xi+2])*u+(2*tarr[xi-1]-5*tarr[xi]+4*tarr[xi+1]-tarr[xi+2]))*u+(-tarr[xi-1]+tarr[xi+1]))*u+tarr[xi];
287 return GSL_SUCCESS;
288 }
289 static const gdl_interpol_type cspline_type = {
290 "cspline",
291 4,
292 NULL,
293 &cspline_init,
294 &cspline_eval
295 };
296 const gdl_interpol_type* gdl_interpol_cspline = &cspline_type;
297 #endif
298
spline_init(void * state,const double xa[],const double ta[],ssize_t xsize)299 static int spline_init(void* state, const double xa[], const double ta[], ssize_t xsize) {
300 return GSL_SUCCESS;
301 }
spline_eval(const void * state,const double xarr[],const double tarr[],ssize_t xsize,double pos,gsl_interp_accel * xa,ssize_t * lastval,double * C,double * t)302 static int spline_eval(const void* state, const double xarr[], const double tarr[], ssize_t xsize, double pos, gsl_interp_accel* xa, ssize_t* lastval, double* C, double *t) {
303 static DIntGDL One=DIntGDL(1);
304 ssize_t xi = gsl_interp_accel_find(xa, xarr, xsize, pos);//xa must be ALWAYS defined for GDL
305 DDoubleGDL* P=new DDoubleGDL(pos);
306 DDoubleGDL* X;
307 DDoubleGDL* Y;
308
309 *lastval = xi;
310 ssize_t x[4];
311 //make in range
312 if ( xi+2 >= xsize ) { x[0]=xsize-4; x[1]=xsize-3; x[2] = xsize-2; x[3] = xsize-1;}
313 else if ( xi-1 < 0 ) { x[0] = 0; x[1] = 1; x[2]=2; x[3]=3;}
314 else { x[0]=xi-1; x[1]= xi; x[2]=xi+1; x[3]=xi+2;}
315 C[0]=xarr[x[0]];C[1]=xarr[x[1]];C[2]=xarr[x[2]];C[3]=xarr[x[3]];
316 C[4]=tarr[x[0]];C[5]=tarr[x[1]];C[6]=tarr[x[2]];C[7]=tarr[x[3]];
317 X=new DDoubleGDL(dimension(4),BaseGDL::NOZERO); for(int i=0; i<4; ++i) (*X)[i]=C[i];
318 Y=new DDoubleGDL(dimension(4),BaseGDL::NOZERO); for(int i=0; i<4; ++i) (*Y)[i]=C[i+4];
319
320 static int splinitIx = LibFunIx( "SPL_INIT" );
321 EnvT* newEnv = new EnvT(NULL, libFunList[ splinitIx]);
322 newEnv->SetNextPar( X ); // pass as local
323 newEnv->SetNextPar( Y ); // pass as local
324 newEnv->SetKeyword("DOUBLE",&One);
325 DDoubleGDL* Q = static_cast<DDoubleGDL*>(static_cast<DLibFun*>(newEnv->GetPro())->Fun()(static_cast<EnvT*>(newEnv)));
326
327 static int splinterpIx = LibFunIx( "SPL_INTERP" );
328 EnvT* newEnv1 = new EnvT(NULL, libFunList[ splinterpIx]);
329 newEnv1->SetNextPar( X ); // pass as local
330 newEnv1->SetNextPar( Y ); // pass as local
331 newEnv1->SetNextPar( Q ); // pass as local
332 newEnv1->SetNextPar( P ); // pass as local
333 newEnv1->SetKeyword("DOUBLE",&One);
334 DDoubleGDL* res =static_cast<DDoubleGDL*>( static_cast<DLibFun*>(newEnv1->GetPro())->Fun()(static_cast<EnvT*>(newEnv1)));
335 *t=(*res)[0];
336 return GSL_SUCCESS;
337 }
338 static const gdl_interpol_type spline_type = {
339 "spline",
340 4,
341 NULL,
342 &spline_init,
343 &spline_eval
344 };
345 const gdl_interpol_type* gdl_interpol_spline = &spline_type;
346
347 namespace lib {
348
interpol_fun(EnvT * e)349 BaseGDL* interpol_fun(EnvT* e){
350 SizeT nParam = e->NParam();
351 if (nParam < 2 || nParam > 3) e->Throw("Incorrect number of arguments.");
352
353 const gdl_interpol_type* interpol=gdl_interpol_linear;
354 // options
355 static int LSQUADRATIC = e->KeywordIx("LSQUADRATIC");
356 #if defined(USE_EIGEN)
357 if (e->KeywordSet(LSQUADRATIC)) interpol=gdl_interpol_lsquadratic;
358 #else
359 if (e->KeywordSet(LSQUADRATIC)) interpol=gdl_interpol_quadratic;
360 #endif
361 static int QUADRATIC = e->KeywordIx("QUADRATIC");
362 if (e->KeywordSet(QUADRATIC)) interpol=gdl_interpol_quadratic;
363 static int SPLINE = e->KeywordIx("SPLINE");
364 #if defined(USE_EIGEN)
365 if (e->KeywordSet(SPLINE)) interpol=gdl_interpol_cspline;
366 #else
367 if (e->KeywordSet(SPLINE)) interpol=gdl_interpol_spline;
368 #endif
369 static int NANIx = e->KeywordIx("NAN");
370 bool doNan=e->KeywordSet(NANIx);
371 unsigned int nmin=gdl_interpol_type_min_size(interpol);
372
373 //dimensions
374 BaseGDL* p0 = e->GetParDefined(0);
375 DType type=p0->Type();
376 SizeT nV=p0->N_Elements();
377 SizeT orig_nV=nV;
378 if (nV <nmin) e->Throw("V has too few elements for this kind of interpolation.");
379
380 DDoubleGDL* V; Guard<BaseGDL> guardV; //used when noNan
381 if (doNan) {
382 V=e->GetParAs<DDoubleGDL>(0)->Dup();guardV.Reset(V);
383 } else {
384 V=e->GetParAs<DDoubleGDL>(0);
385 }
386 //X and its guard
387 DDoubleGDL* X; Guard<BaseGDL> guardX;
388 //Xout and its guard
389 DDoubleGDL* Xout; Guard<BaseGDL> guardXout;
390 // the type of output.
391 DType t=type; //V's type by default.
392 //size of the out value
393 SizeT nout=0;
394 //type of output
395 bool isDouble = false;
396
397 if (nParam==2) { // we make X, only V has to be chacked for Nan
398 BaseGDL* p1 = e->GetParDefined(1);
399 if (p1->N_Elements() >1) e->Throw("N must be one positive integer");
400 DLongGDL* n1gdl=e->GetParAs<DLongGDL>(1);
401 nout=(*n1gdl)[0];
402 if (nout < 1) e->Throw("N must be one positive integer");
403 // check V for Nans, error if size is not good enough
404 X=new DDoubleGDL(nV,BaseGDL::INDGEN); //easy
405 guardX.Reset(X);//X will be destroyed on exit
406 if (doNan) {
407 SizeT k =0;
408 for (SizeT i = 0; i < nV; i++) {
409 if (isfinite((*V)[i])) {
410 (*V)[k] = (*V)[i];
411 (*X)[k++] = (*X)[i];
412 }
413 }
414 nV=k;
415 if (nV <nmin) e->Throw("too few non-NAN elements left for this kind of interpolation.");
416 }
417 Xout=new DDoubleGDL(nout,BaseGDL::INDGEN);
418 guardXout.Reset(Xout);//Xout will be destroyed on exit
419 (*Xout)[0]=0; //to not divide by 0 in following loop if nout=1
420
421 for (SizeT i = 1; i < nout; ++i) {
422 (*Xout)[i] = double(i)*(orig_nV - 1) / (nout - 1);
423 }
424 //is any arg DOUBLE ?
425 isDouble = (p0->Type() == GDL_DOUBLE);
426 } else {
427 BaseGDL* p1 = e->GetParDefined(1);
428 if (p1->N_Elements() != nV) e->Throw("V and X arrays must have same # of elements");
429
430 // check V and X for Nans, error if size is not good enough
431 if (doNan) {
432 X = e->GetParAs<DDoubleGDL>(1)->Dup(); guardX.Reset(X);//X will be destroyed on exit
433 SizeT k =0;
434 for (SizeT i = 0; i < nV; i++) {
435 if (isfinite((*V)[i]) && isfinite((*X)[i])) {
436 (*V)[k] = (*V)[i];
437 (*X)[k++] = (*X)[i];
438 }
439 }
440 nV=k;
441 if (nV <nmin) e->Throw("too few non-NAN elements left for this kind of interpolation.");
442 } else {
443 X = e->GetParAs<DDoubleGDL>(1);
444 }
445 BaseGDL* p2 = e->GetParDefined(2);
446 nout = p2->N_Elements();
447 DType t = (DTypeOrder[ p0->Type()] > DTypeOrder[ p1->Type()]) ? p0->Type() : p1->Type();
448 t = (DTypeOrder[t] > DTypeOrder[ p2->Type()]) ? t : p2->Type();
449 Xout=e->GetParAs<DDoubleGDL>(2);
450 //is any arg DOUBLE ?
451 isDouble = (p0->Type() == GDL_DOUBLE || p1->Type() == GDL_DOUBLE || p2->Type() == GDL_DOUBLE);
452 }
453 //alloc interpolant object & guard NOW that everything is fine with Arrays!
454 gdl_interpol * myinterp = gdl_interpol_alloc(interpol, nV);
455 GDLGuard<gdl_interpol> ginterpol(myinterp, gdl_interpol_free);
456 //alloc accelerator & guard
457 gsl_interp_accel * acc = gsl_interp_accel_alloc();
458 GDLGuard<gsl_interp_accel> g1(acc, gsl_interp_accel_free);
459 int status=gdl_interpol_init (myinterp, (const double*)X->DataAddr(), (const double*)V->DataAddr() , nV);
460 //allocate result
461 DDoubleGDL* res=new DDoubleGDL(nout,BaseGDL::NOZERO);
462
463 //compute
464 for (SizeT i=0; i< nout; ++i) {
465 (*res)[i]=gdl_interpol_eval(myinterp, (const double*)X->DataAddr() , (const double*) V->DataAddr(), (*Xout)[i] , acc);
466 }
467 // if we generated only 1 value, return a scalar instead of an array (IDL behaviour)
468 if(nout == 1) res = new DDoubleGDL((*res)[0]);
469
470 if (isDouble) return res;
471 else return res->Convert2(GDL_FLOAT, BaseGDL::CONVERT);
472 }
473 }