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