• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package org.apache.commons.math.analysis.interpolation;
18 
19 import org.apache.commons.math.exception.DimensionMismatchException;
20 import org.apache.commons.math.exception.NoDataException;
21 import org.apache.commons.math.MathException;
22 import org.apache.commons.math.util.MathUtils;
23 
24 /**
25  * Generates a tricubic interpolating function.
26  *
27  * @version $Revision$ $Date$
28  * @since 2.2
29  */
30 public class TricubicSplineInterpolator
31     implements TrivariateRealGridInterpolator {
32     /**
33      * {@inheritDoc}
34      */
interpolate(final double[] xval, final double[] yval, final double[] zval, final double[][][] fval)35     public TricubicSplineInterpolatingFunction interpolate(final double[] xval,
36                                                            final double[] yval,
37                                                            final double[] zval,
38                                                            final double[][][] fval)
39         throws MathException {
40         if (xval.length == 0 || yval.length == 0 || zval.length == 0 || fval.length == 0) {
41             throw new NoDataException();
42         }
43         if (xval.length != fval.length) {
44             throw new DimensionMismatchException(xval.length, fval.length);
45         }
46 
47         MathUtils.checkOrder(xval);
48         MathUtils.checkOrder(yval);
49         MathUtils.checkOrder(zval);
50 
51         final int xLen = xval.length;
52         final int yLen = yval.length;
53         final int zLen = zval.length;
54 
55         // Samples, re-ordered as (z, x, y) and (y, z, x) tuplets
56         // fvalXY[k][i][j] = f(xval[i], yval[j], zval[k])
57         // fvalZX[j][k][i] = f(xval[i], yval[j], zval[k])
58         final double[][][] fvalXY = new double[zLen][xLen][yLen];
59         final double[][][] fvalZX = new double[yLen][zLen][xLen];
60         for (int i = 0; i < xLen; i++) {
61             if (fval[i].length != yLen) {
62                 throw new DimensionMismatchException(fval[i].length, yLen);
63             }
64 
65             for (int j = 0; j < yLen; j++) {
66                 if (fval[i][j].length != zLen) {
67                     throw new DimensionMismatchException(fval[i][j].length, zLen);
68                 }
69 
70                 for (int k = 0; k < zLen; k++) {
71                     final double v = fval[i][j][k];
72                     fvalXY[k][i][j] = v;
73                     fvalZX[j][k][i] = v;
74                 }
75             }
76         }
77 
78         final BicubicSplineInterpolator bsi = new BicubicSplineInterpolator();
79 
80         // For each line x[i] (0 <= i < xLen), construct a 2D spline in y and z
81         final BicubicSplineInterpolatingFunction[] xSplineYZ
82             = new BicubicSplineInterpolatingFunction[xLen];
83         for (int i = 0; i < xLen; i++) {
84             xSplineYZ[i] = bsi.interpolate(yval, zval, fval[i]);
85         }
86 
87         // For each line y[j] (0 <= j < yLen), construct a 2D spline in z and x
88         final BicubicSplineInterpolatingFunction[] ySplineZX
89             = new BicubicSplineInterpolatingFunction[yLen];
90         for (int j = 0; j < yLen; j++) {
91             ySplineZX[j] = bsi.interpolate(zval, xval, fvalZX[j]);
92         }
93 
94         // For each line z[k] (0 <= k < zLen), construct a 2D spline in x and y
95         final BicubicSplineInterpolatingFunction[] zSplineXY
96             = new BicubicSplineInterpolatingFunction[zLen];
97         for (int k = 0; k < zLen; k++) {
98             zSplineXY[k] = bsi.interpolate(xval, yval, fvalXY[k]);
99         }
100 
101         // Partial derivatives wrt x and wrt y
102         final double[][][] dFdX = new double[xLen][yLen][zLen];
103         final double[][][] dFdY = new double[xLen][yLen][zLen];
104         final double[][][] d2FdXdY = new double[xLen][yLen][zLen];
105         for (int k = 0; k < zLen; k++) {
106             final BicubicSplineInterpolatingFunction f = zSplineXY[k];
107             for (int i = 0; i < xLen; i++) {
108                 final double x = xval[i];
109                 for (int j = 0; j < yLen; j++) {
110                     final double y = yval[j];
111                     dFdX[i][j][k] = f.partialDerivativeX(x, y);
112                     dFdY[i][j][k] = f.partialDerivativeY(x, y);
113                     d2FdXdY[i][j][k] = f.partialDerivativeXY(x, y);
114                 }
115             }
116         }
117 
118         // Partial derivatives wrt y and wrt z
119         final double[][][] dFdZ = new double[xLen][yLen][zLen];
120         final double[][][] d2FdYdZ = new double[xLen][yLen][zLen];
121         for (int i = 0; i < xLen; i++) {
122             final BicubicSplineInterpolatingFunction f = xSplineYZ[i];
123             for (int j = 0; j < yLen; j++) {
124                 final double y = yval[j];
125                 for (int k = 0; k < zLen; k++) {
126                     final double z = zval[k];
127                     dFdZ[i][j][k] = f.partialDerivativeY(y, z);
128                     d2FdYdZ[i][j][k] = f.partialDerivativeXY(y, z);
129                 }
130             }
131         }
132 
133         // Partial derivatives wrt x and wrt z
134         final double[][][] d2FdZdX = new double[xLen][yLen][zLen];
135         for (int j = 0; j < yLen; j++) {
136             final BicubicSplineInterpolatingFunction f = ySplineZX[j];
137             for (int k = 0; k < zLen; k++) {
138                 final double z = zval[k];
139                 for (int i = 0; i < xLen; i++) {
140                     final double x = xval[i];
141                     d2FdZdX[i][j][k] = f.partialDerivativeXY(z, x);
142                 }
143             }
144         }
145 
146         // Third partial cross-derivatives
147         final double[][][] d3FdXdYdZ = new double[xLen][yLen][zLen];
148         for (int i = 0; i < xLen ; i++) {
149             final int nI = nextIndex(i, xLen);
150             final int pI = previousIndex(i);
151             for (int j = 0; j < yLen; j++) {
152                 final int nJ = nextIndex(j, yLen);
153                 final int pJ = previousIndex(j);
154                 for (int k = 0; k < zLen; k++) {
155                     final int nK = nextIndex(k, zLen);
156                     final int pK = previousIndex(k);
157 
158                     // XXX Not sure about this formula
159                     d3FdXdYdZ[i][j][k] = (fval[nI][nJ][nK] - fval[nI][pJ][nK] -
160                                           fval[pI][nJ][nK] + fval[pI][pJ][nK] -
161                                           fval[nI][nJ][pK] + fval[nI][pJ][pK] +
162                                           fval[pI][nJ][pK] - fval[pI][pJ][pK]) /
163                         ((xval[nI] - xval[pI]) * (yval[nJ] - yval[pJ]) * (zval[nK] - zval[pK])) ;
164                 }
165             }
166         }
167 
168         // Create the interpolating splines
169         return new TricubicSplineInterpolatingFunction(xval, yval, zval, fval,
170                                                        dFdX, dFdY, dFdZ,
171                                                        d2FdXdY, d2FdZdX, d2FdYdZ,
172                                                        d3FdXdYdZ);
173     }
174 
175     /**
176      * Compute the next index of an array, clipping if necessary.
177      * It is assumed (but not checked) that {@code i} is larger than or equal to 0}.
178      *
179      * @param i Index
180      * @param max Upper limit of the array
181      * @return the next index
182      */
nextIndex(int i, int max)183     private int nextIndex(int i, int max) {
184         final int index = i + 1;
185         return index < max ? index : index - 1;
186     }
187     /**
188      * Compute the previous index of an array, clipping if necessary.
189      * It is assumed (but not checked) that {@code i} is smaller than the size of the array.
190      *
191      * @param i Index
192      * @return the previous index
193      */
previousIndex(int i)194     private int previousIndex(int i) {
195         final int index = i - 1;
196         return index >= 0 ? index : 0;
197     }
198 }
199