1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math3.analysis.interpolation;
18
19 import org.apache.commons.math3.analysis.BivariateFunction;
20 import org.apache.commons.math3.exception.DimensionMismatchException;
21 import org.apache.commons.math3.exception.NoDataException;
22 import org.apache.commons.math3.exception.OutOfRangeException;
23 import org.apache.commons.math3.exception.NonMonotonicSequenceException;
24 import org.apache.commons.math3.util.MathArrays;
25
26
27
28
29
30
31
32
33
34 public class BicubicSplineInterpolatingFunction
35 implements BivariateFunction {
36
37
38
39
40 private static final double[][] AINV = {
41 { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
42 { 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 },
43 { -3,3,0,0,-2,-1,0,0,0,0,0,0,0,0,0,0 },
44 { 2,-2,0,0,1,1,0,0,0,0,0,0,0,0,0,0 },
45 { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 },
46 { 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 },
47 { 0,0,0,0,0,0,0,0,-3,3,0,0,-2,-1,0,0 },
48 { 0,0,0,0,0,0,0,0,2,-2,0,0,1,1,0,0 },
49 { -3,0,3,0,0,0,0,0,-2,0,-1,0,0,0,0,0 },
50 { 0,0,0,0,-3,0,3,0,0,0,0,0,-2,0,-1,0 },
51 { 9,-9,-9,9,6,3,-6,-3,6,-6,3,-3,4,2,2,1 },
52 { -6,6,6,-6,-3,-3,3,3,-4,4,-2,2,-2,-2,-1,-1 },
53 { 2,0,-2,0,0,0,0,0,1,0,1,0,0,0,0,0 },
54 { 0,0,0,0,2,0,-2,0,0,0,0,0,1,0,1,0 },
55 { -6,6,6,-6,-4,-2,4,2,-3,3,-3,3,-2,-1,-2,-1 },
56 { 4,-4,-4,4,2,2,-2,-2,2,-2,2,-2,1,1,1,1 }
57 };
58
59
60 private final double[] xval;
61
62 private final double[] yval;
63
64 private final BicubicSplineFunction[][] splines;
65
66
67
68
69
70
71
72
73
74 private BivariateFunction[][][] partialDerivatives = null;
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 public BicubicSplineInterpolatingFunction(double[] x,
93 double[] y,
94 double[][] f,
95 double[][] dFdX,
96 double[][] dFdY,
97 double[][] d2FdXdY)
98 throws DimensionMismatchException,
99 NoDataException,
100 NonMonotonicSequenceException {
101 final int xLen = x.length;
102 final int yLen = y.length;
103
104 if (xLen == 0 || yLen == 0 || f.length == 0 || f[0].length == 0) {
105 throw new NoDataException();
106 }
107 if (xLen != f.length) {
108 throw new DimensionMismatchException(xLen, f.length);
109 }
110 if (xLen != dFdX.length) {
111 throw new DimensionMismatchException(xLen, dFdX.length);
112 }
113 if (xLen != dFdY.length) {
114 throw new DimensionMismatchException(xLen, dFdY.length);
115 }
116 if (xLen != d2FdXdY.length) {
117 throw new DimensionMismatchException(xLen, d2FdXdY.length);
118 }
119
120 MathArrays.checkOrder(x);
121 MathArrays.checkOrder(y);
122
123 xval = x.clone();
124 yval = y.clone();
125
126 final int lastI = xLen - 1;
127 final int lastJ = yLen - 1;
128 splines = new BicubicSplineFunction[lastI][lastJ];
129
130 for (int i = 0; i < lastI; i++) {
131 if (f[i].length != yLen) {
132 throw new DimensionMismatchException(f[i].length, yLen);
133 }
134 if (dFdX[i].length != yLen) {
135 throw new DimensionMismatchException(dFdX[i].length, yLen);
136 }
137 if (dFdY[i].length != yLen) {
138 throw new DimensionMismatchException(dFdY[i].length, yLen);
139 }
140 if (d2FdXdY[i].length != yLen) {
141 throw new DimensionMismatchException(d2FdXdY[i].length, yLen);
142 }
143 final int ip1 = i + 1;
144 for (int j = 0; j < lastJ; j++) {
145 final int jp1 = j + 1;
146 final double[] beta = new double[] {
147 f[i][j], f[ip1][j], f[i][jp1], f[ip1][jp1],
148 dFdX[i][j], dFdX[ip1][j], dFdX[i][jp1], dFdX[ip1][jp1],
149 dFdY[i][j], dFdY[ip1][j], dFdY[i][jp1], dFdY[ip1][jp1],
150 d2FdXdY[i][j], d2FdXdY[ip1][j], d2FdXdY[i][jp1], d2FdXdY[ip1][jp1]
151 };
152
153 splines[i][j] = new BicubicSplineFunction(computeSplineCoefficients(beta));
154 }
155 }
156 }
157
158
159
160
161 public double value(double x, double y)
162 throws OutOfRangeException {
163 final int i = searchIndex(x, xval);
164 if (i == -1) {
165 throw new OutOfRangeException(x, xval[0], xval[xval.length - 1]);
166 }
167 final int j = searchIndex(y, yval);
168 if (j == -1) {
169 throw new OutOfRangeException(y, yval[0], yval[yval.length - 1]);
170 }
171
172 final double xN = (x - xval[i]) / (xval[i + 1] - xval[i]);
173 final double yN = (y - yval[j]) / (yval[j + 1] - yval[j]);
174
175 return splines[i][j].value(xN, yN);
176 }
177
178
179
180
181
182
183
184
185
186
187 public double partialDerivativeX(double x, double y)
188 throws OutOfRangeException {
189 return partialDerivative(0, x, y);
190 }
191
192
193
194
195
196
197
198
199
200 public double partialDerivativeY(double x, double y)
201 throws OutOfRangeException {
202 return partialDerivative(1, x, y);
203 }
204
205
206
207
208
209
210
211
212
213 public double partialDerivativeXX(double x, double y)
214 throws OutOfRangeException {
215 return partialDerivative(2, x, y);
216 }
217
218
219
220
221
222
223
224
225
226 public double partialDerivativeYY(double x, double y)
227 throws OutOfRangeException {
228 return partialDerivative(3, x, y);
229 }
230
231
232
233
234
235
236
237
238 public double partialDerivativeXY(double x, double y)
239 throws OutOfRangeException {
240 return partialDerivative(4, x, y);
241 }
242
243
244
245
246
247
248
249
250
251
252 private double partialDerivative(int which, double x, double y)
253 throws OutOfRangeException {
254 if (partialDerivatives == null) {
255 computePartialDerivatives();
256 }
257
258 final int i = searchIndex(x, xval);
259 if (i == -1) {
260 throw new OutOfRangeException(x, xval[0], xval[xval.length - 1]);
261 }
262 final int j = searchIndex(y, yval);
263 if (j == -1) {
264 throw new OutOfRangeException(y, yval[0], yval[yval.length - 1]);
265 }
266
267 final double xN = (x - xval[i]) / (xval[i + 1] - xval[i]);
268 final double yN = (y - yval[j]) / (yval[j + 1] - yval[j]);
269
270 return partialDerivatives[which][i][j].value(xN, yN);
271 }
272
273
274
275
276 private void computePartialDerivatives() {
277 final int lastI = xval.length - 1;
278 final int lastJ = yval.length - 1;
279 partialDerivatives = new BivariateFunction[5][lastI][lastJ];
280
281 for (int i = 0; i < lastI; i++) {
282 for (int j = 0; j < lastJ; j++) {
283 final BicubicSplineFunction f = splines[i][j];
284 partialDerivatives[0][i][j] = f.partialDerivativeX();
285 partialDerivatives[1][i][j] = f.partialDerivativeY();
286 partialDerivatives[2][i][j] = f.partialDerivativeXX();
287 partialDerivatives[3][i][j] = f.partialDerivativeYY();
288 partialDerivatives[4][i][j] = f.partialDerivativeXY();
289 }
290 }
291 }
292
293
294
295
296
297
298
299
300 private int searchIndex(double c, double[] val) {
301 if (c < val[0]) {
302 return -1;
303 }
304
305 final int max = val.length;
306 for (int i = 1; i < max; i++) {
307 if (c <= val[i]) {
308 return i - 1;
309 }
310 }
311
312 return -1;
313 }
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344 private double[] computeSplineCoefficients(double[] beta) {
345 final double[] a = new double[16];
346
347 for (int i = 0; i < 16; i++) {
348 double result = 0;
349 final double[] row = AINV[i];
350 for (int j = 0; j < 16; j++) {
351 result += row[j] * beta[j];
352 }
353 a[i] = result;
354 }
355
356 return a;
357 }
358 }
359
360
361
362
363
364
365 class BicubicSplineFunction
366 implements BivariateFunction {
367
368
369 private static final short N = 4;
370
371
372 private final double[][] a;
373
374
375 private BivariateFunction partialDerivativeX;
376
377
378 private BivariateFunction partialDerivativeY;
379
380
381 private BivariateFunction partialDerivativeXX;
382
383
384 private BivariateFunction partialDerivativeYY;
385
386
387 private BivariateFunction partialDerivativeXY;
388
389
390
391
392
393 public BicubicSplineFunction(double[] a) {
394 this.a = new double[N][N];
395 for (int i = 0; i < N; i++) {
396 for (int j = 0; j < N; j++) {
397 this.a[i][j] = a[i + N * j];
398 }
399 }
400 }
401
402
403
404
405 public double value(double x, double y) {
406 if (x < 0 || x > 1) {
407 throw new OutOfRangeException(x, 0, 1);
408 }
409 if (y < 0 || y > 1) {
410 throw new OutOfRangeException(y, 0, 1);
411 }
412
413 final double x2 = x * x;
414 final double x3 = x2 * x;
415 final double[] pX = {1, x, x2, x3};
416
417 final double y2 = y * y;
418 final double y3 = y2 * y;
419 final double[] pY = {1, y, y2, y3};
420
421 return apply(pX, pY, a);
422 }
423
424
425
426
427
428
429
430
431
432 private double apply(double[] pX, double[] pY, double[][] coeff) {
433 double result = 0;
434 for (int i = 0; i < N; i++) {
435 for (int j = 0; j < N; j++) {
436 result += coeff[i][j] * pX[i] * pY[j];
437 }
438 }
439
440 return result;
441 }
442
443
444
445
446 public BivariateFunction partialDerivativeX() {
447 if (partialDerivativeX == null) {
448 computePartialDerivatives();
449 }
450
451 return partialDerivativeX;
452 }
453
454
455
456 public BivariateFunction partialDerivativeY() {
457 if (partialDerivativeY == null) {
458 computePartialDerivatives();
459 }
460
461 return partialDerivativeY;
462 }
463
464
465
466 public BivariateFunction partialDerivativeXX() {
467 if (partialDerivativeXX == null) {
468 computePartialDerivatives();
469 }
470
471 return partialDerivativeXX;
472 }
473
474
475
476 public BivariateFunction partialDerivativeYY() {
477 if (partialDerivativeYY == null) {
478 computePartialDerivatives();
479 }
480
481 return partialDerivativeYY;
482 }
483
484
485
486 public BivariateFunction partialDerivativeXY() {
487 if (partialDerivativeXY == null) {
488 computePartialDerivatives();
489 }
490
491 return partialDerivativeXY;
492 }
493
494
495
496
497 private void computePartialDerivatives() {
498 final double[][] aX = new double[N][N];
499 final double[][] aY = new double[N][N];
500 final double[][] aXX = new double[N][N];
501 final double[][] aYY = new double[N][N];
502 final double[][] aXY = new double[N][N];
503
504 for (int i = 0; i < N; i++) {
505 for (int j = 0; j < N; j++) {
506 final double c = a[i][j];
507 aX[i][j] = i * c;
508 aY[i][j] = j * c;
509 aXX[i][j] = (i - 1) * aX[i][j];
510 aYY[i][j] = (j - 1) * aY[i][j];
511 aXY[i][j] = j * aX[i][j];
512 }
513 }
514
515 partialDerivativeX = new BivariateFunction() {
516 public double value(double x, double y) {
517 final double x2 = x * x;
518 final double[] pX = {0, 1, x, x2};
519
520 final double y2 = y * y;
521 final double y3 = y2 * y;
522 final double[] pY = {1, y, y2, y3};
523
524 return apply(pX, pY, aX);
525 }
526 };
527 partialDerivativeY = new BivariateFunction() {
528 public double value(double x, double y) {
529 final double x2 = x * x;
530 final double x3 = x2 * x;
531 final double[] pX = {1, x, x2, x3};
532
533 final double y2 = y * y;
534 final double[] pY = {0, 1, y, y2};
535
536 return apply(pX, pY, aY);
537 }
538 };
539 partialDerivativeXX = new BivariateFunction() {
540 public double value(double x, double y) {
541 final double[] pX = {0, 0, 1, x};
542
543 final double y2 = y * y;
544 final double y3 = y2 * y;
545 final double[] pY = {1, y, y2, y3};
546
547 return apply(pX, pY, aXX);
548 }
549 };
550 partialDerivativeYY = new BivariateFunction() {
551 public double value(double x, double y) {
552 final double x2 = x * x;
553 final double x3 = x2 * x;
554 final double[] pX = {1, x, x2, x3};
555
556 final double[] pY = {0, 0, 1, y};
557
558 return apply(pX, pY, aYY);
559 }
560 };
561 partialDerivativeXY = new BivariateFunction() {
562 public double value(double x, double y) {
563 final double x2 = x * x;
564 final double[] pX = {0, 1, x, x2};
565
566 final double y2 = y * y;
567 final double[] pY = {0, 1, y, y2};
568
569 return apply(pX, pY, aXY);
570 }
571 };
572 }
573 }