View Javadoc

1   /*
2    * BilinearInterpolator.java
3    *
4    * Created on June 3, 2008, 4:04 PM
5    *
6    * $Id: BilinearInterpolator.java,v 1.1.1.1 2010/11/30 21:32:00 jeremy Exp $
7    */
8   //
9   package org.lcsim.math.interpolation;
10  
11  import static java.lang.Math.abs;
12  
13  /**
14   * A class to provide interpolated values for values determined at discrete points
15   * on a 2D grid
16   *
17   * @author Norman Graf
18   */
19  public class BilinearInterpolator
20  {
21      private double[] _x;
22      private double _xmin;
23      private double _xmax;
24      private int _xDim;
25      private double[] _y;
26      private double _ymin;
27      private double _ymax;
28      private int _yDim;
29      private double[][] _val;
30      /**
31       * Creates a new instance of BilinearInterpolator
32       * @param x Array of first independent variable at which values are known
33       * @param y Array of second independent variable at which values are known
34       * @param z Array of values at the (x,y) points
35       */
36      public BilinearInterpolator(double[] x, double[] y, double[][] z)
37      {
38          _x = new double[x.length];;
39          System.arraycopy(x,0,_x,0, x.length);
40          _xDim = _x.length;
41          _xmin = _x[0];
42          _xmax = _x[_xDim-1];
43          
44          _y = new double[y.length];
45          System.arraycopy(y,0,_y,0, y.length);
46          _yDim = _y.length;
47          _ymin = _y[0];
48          _ymax = _y[_yDim-1];
49          
50   
51          
52          _val = new double[z.length][z[0].length];
53          for(int i=0; i< z.length; ++i)
54          {
55              System.arraycopy(z[i],0,_val[i],0,z[i].length);
56          }
57      }
58      
59      //TODO add protection for values out of range
60      /**
61       * Return the value at an arbitrary x,y point, using bilinear interpolation
62       * @param x the first independent variable
63       * @param y the second independent variable
64       * @return the interpolated value at (x,y)
65       */
66      public double interpolateValueAt(double x, double y)
67      {
68          return trueBilinear( x, y );
69  //        return polin2(_x, _y, _val, x, y);
70      }
71      
72      /*
73       * Given arrays x1a[1..m] and x2a[1..n] of independent variables, and a submatrix of function
74       *  values ya[1..m][1..n], tabulated at the grid points defined by x1a and x2a; and given values
75       * x1 and x2 of the independent variables; this routine returns an interpolated function value y.
76       */
77      double  polin2(double[] x1a, double[] x2a, double[][] ya, double x1, double x2)
78      {
79          int m = x1a.length;
80          int n = x2a.length;
81          double[] ymtmp = new double[m];
82          double[] yntmp = new double[n];
83          for (int j=0; j<m; ++j) //Loop over rows.
84          {
85              // copy the row into temporary storage
86              for(int k = 0; k<n; ++k)
87              {
88                  yntmp[k] = ya[j][k];
89              }
90              ymtmp[j] = polint(x2a, yntmp, x2 ); //Interpolate answer into temporary storage.
91          }
92          return polint(x1a, ymtmp, x1); //Do the final interpolation.
93      }
94      
95      /*
96       * Given arrays xa[1..n] and ya[1..n], and given a value x, this routine returns a value y.
97       * If P(x) is the polynomial of degree N -1 such that P(xai) = ya,  i ; i = 1... n, then
98       * the returned value y = P(x).
99       */
100     double polint( double[] xa, double[] ya, double x)
101     {
102         int ns=0;
103         int n = xa.length;
104         double den,dif,dift,ho,hp,w;
105         double dy;
106         double[] c = new double[n];
107         double[] d = new double[n];
108         dif=abs(x-xa[0]);
109         
110         for (int i=0;i<n;++i)
111         {	//Here we find the index ns of the closest table entry,
112             dift = abs(x-xa[i]);
113             if ( dift < dif)
114             {
115                 ns=i;
116                 dif=dift;
117             }
118             c[i]=ya[i];	// and initialize the table of c's and d's.
119             d[i]=ya[i];
120         }
121         double y = ya[ns--];	// This is the initial approximation to y.
122 //        ns = ns-1;
123         for (int m=1; m<n ; ++m)
124         {
125             //For each column of the table,
126             for (int i=0; i<n-m;++i)
127             {	//we loop over the current c's and d's and update them.
128                 ho=xa[i]-x;
129                 hp=xa[i+m]-x;
130                 w=c[i+1]-d[i];
131                 den = ho-hp;
132                 if (den == 0.0) System.err.println("Error in routine polint");
133                 //This error can occur only if two input xa's are (to within roundo) identical.
134                 den=w/den;
135                 d[i]=hp*den;	//Here the c's and d's are updated.
136                 c[i]=ho*den;
137             }
138             if(2*ns < (n-m))
139             {
140                 dy = c[ns+1];
141             }
142             else
143             {
144                 dy = d[ns];
145                 ns = ns-1;
146             }
147             y += dy;
148             //After each column in the tableau is completed, we decide which correction, c or d,
149             //we want to add to our accumulating value of y, i.e., which path to take through the
150             //tableau|forking up or down. We do this in such a way as to take the most \straight
151             //line" route through the tableau to its apex, updating ns accordingly to keep track of
152             //where we are. This route keeps the partial approximations centered (insofar as possible)
153             //on the target x. The last dy added is thus the error indication.
154         }
155         return y;
156     }
157     
158     double trueBilinear(double x, double y)
159     {
160         // find bin for x
161         int ixlo = 0;
162         int ixhi = 0;
163         for(int i=0; i<_xDim-1; ++i)
164         {
165             if(x>=_x[i] && x<=_x[i+1])
166             {
167                 ixlo = i;
168                 ixhi = i+1;
169                 break;
170             }
171         }
172         
173         // find bin for y
174         int iylo = 0;
175         int iyhi = 0;
176         for(int i=0; i<_yDim-1; ++i)
177         {
178             if(y>=_y[i] && y<=_y[i+1])
179             {
180                 iylo = i;
181                 iyhi = i+1;
182                 break;
183             }
184         }
185         double v1 = _val[ixlo][iylo];
186         double v2 = _val[ixhi][iylo];
187         double v3 = _val[ixhi][iyhi];
188         double v4 = _val[ixlo][iyhi];
189         
190         double t = (x - _x[ixlo])/(_x[ixhi] - _x[ixlo]);
191         double u = (y - _y[iylo])/(_y[iyhi] - _y[iylo]);
192         
193         return (1-t)*(1-u)*v1 +t*(1-u)*v2+t*u*v3+(1-t)*u*v4;
194     }
195 }