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.analysis.TrivariateRealFunction; 20 import org.apache.commons.math.exception.DimensionMismatchException; 21 import org.apache.commons.math.exception.NoDataException; 22 import org.apache.commons.math.exception.OutOfRangeException; 23 import org.apache.commons.math.util.MathUtils; 24 25 /** 26 * Function that implements the 27 * <a href="http://en.wikipedia.org/wiki/Tricubic_interpolation"> 28 * tricubic spline interpolation</a>, as proposed in 29 * <quote> 30 * Tricubic interpolation in three dimensions<br/> 31 * F. Lekien and J. Marsden<br/> 32 * <em>Int. J. Numer. Meth. Engng</em> 2005; <b>63</b>:455-471 33 * </quote> 34 * 35 * @version $Revision$ $Date$ 36 * @since 2.2 37 */ 38 public class TricubicSplineInterpolatingFunction 39 implements TrivariateRealFunction { 40 /** 41 * Matrix to compute the spline coefficients from the function values 42 * and function derivatives values 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 /** Samples x-coordinates */ 112 private final double[] xval; 113 /** Samples y-coordinates */ 114 private final double[] yval; 115 /** Samples z-coordinates */ 116 private final double[] zval; 117 /** Set of cubic splines pacthing the whole data grid */ 118 private final TricubicSplineFunction[][][] splines; 119 120 /** 121 * @param x Sample values of the x-coordinate, in increasing order. 122 * @param y Sample values of the y-coordinate, in increasing order. 123 * @param z Sample values of the y-coordinate, in increasing order. 124 * @param f Values of the function on every grid point. 125 * @param dFdX Values of the partial derivative of function with respect 126 * to x on every grid point. 127 * @param dFdY Values of the partial derivative of function with respect 128 * to y on every grid point. 129 * @param dFdZ Values of the partial derivative of function with respect 130 * to z on every grid point. 131 * @param d2FdXdY Values of the cross partial derivative of function on 132 * every grid point. 133 * @param d2FdXdZ Values of the cross partial derivative of function on 134 * every grid point. 135 * @param d2FdYdZ Values of the cross partial derivative of function on 136 * every grid point. 137 * @param d3FdXdYdZ Values of the cross partial derivative of function on 138 * every grid point. 139 * @throws NoDataException if any of the arrays has zero length. 140 * @throws DimensionMismatchException if the various arrays do not contain 141 * the expected number of elements. 142 * @throws IllegalArgumentException if {@code x}, {@code y} or {@code z} 143 * are not strictly increasing. 144 */ TricubicSplineInterpolatingFunction(double[] x, double[] y, double[] z, double[][][] f, double[][][] dFdX, double[][][] dFdY, double[][][] dFdZ, double[][][] d2FdXdY, double[][][] d2FdXdZ, double[][][] d2FdYdZ, double[][][] d3FdXdYdZ)145 public TricubicSplineInterpolatingFunction(double[] x, 146 double[] y, 147 double[] z, 148 double[][][] f, 149 double[][][] dFdX, 150 double[][][] dFdY, 151 double[][][] dFdZ, 152 double[][][] d2FdXdY, 153 double[][][] d2FdXdZ, 154 double[][][] d2FdYdZ, 155 double[][][] d3FdXdYdZ) { 156 final int xLen = x.length; 157 final int yLen = y.length; 158 final int zLen = z.length; 159 160 if (xLen == 0 || yLen == 0 || z.length == 0 || f.length == 0 || f[0].length == 0) { 161 throw new NoDataException(); 162 } 163 if (xLen != f.length) { 164 throw new DimensionMismatchException(xLen, f.length); 165 } 166 if (xLen != dFdX.length) { 167 throw new DimensionMismatchException(xLen, dFdX.length); 168 } 169 if (xLen != dFdY.length) { 170 throw new DimensionMismatchException(xLen, dFdY.length); 171 } 172 if (xLen != dFdZ.length) { 173 throw new DimensionMismatchException(xLen, dFdZ.length); 174 } 175 if (xLen != d2FdXdY.length) { 176 throw new DimensionMismatchException(xLen, d2FdXdY.length); 177 } 178 if (xLen != d2FdXdZ.length) { 179 throw new DimensionMismatchException(xLen, d2FdXdZ.length); 180 } 181 if (xLen != d2FdYdZ.length) { 182 throw new DimensionMismatchException(xLen, d2FdYdZ.length); 183 } 184 if (xLen != d3FdXdYdZ.length) { 185 throw new DimensionMismatchException(xLen, d3FdXdYdZ.length); 186 } 187 188 MathUtils.checkOrder(x); 189 MathUtils.checkOrder(y); 190 MathUtils.checkOrder(z); 191 192 xval = x.clone(); 193 yval = y.clone(); 194 zval = z.clone(); 195 196 final int lastI = xLen - 1; 197 final int lastJ = yLen - 1; 198 final int lastK = zLen - 1; 199 splines = new TricubicSplineFunction[lastI][lastJ][lastK]; 200 201 for (int i = 0; i < lastI; i++) { 202 if (f[i].length != yLen) { 203 throw new DimensionMismatchException(f[i].length, yLen); 204 } 205 if (dFdX[i].length != yLen) { 206 throw new DimensionMismatchException(dFdX[i].length, yLen); 207 } 208 if (dFdY[i].length != yLen) { 209 throw new DimensionMismatchException(dFdY[i].length, yLen); 210 } 211 if (dFdZ[i].length != yLen) { 212 throw new DimensionMismatchException(dFdZ[i].length, yLen); 213 } 214 if (d2FdXdY[i].length != yLen) { 215 throw new DimensionMismatchException(d2FdXdY[i].length, yLen); 216 } 217 if (d2FdXdZ[i].length != yLen) { 218 throw new DimensionMismatchException(d2FdXdZ[i].length, yLen); 219 } 220 if (d2FdYdZ[i].length != yLen) { 221 throw new DimensionMismatchException(d2FdYdZ[i].length, yLen); 222 } 223 if (d3FdXdYdZ[i].length != yLen) { 224 throw new DimensionMismatchException(d3FdXdYdZ[i].length, yLen); 225 } 226 227 final int ip1 = i + 1; 228 for (int j = 0; j < lastJ; j++) { 229 if (f[i][j].length != zLen) { 230 throw new DimensionMismatchException(f[i][j].length, zLen); 231 } 232 if (dFdX[i][j].length != zLen) { 233 throw new DimensionMismatchException(dFdX[i][j].length, zLen); 234 } 235 if (dFdY[i][j].length != zLen) { 236 throw new DimensionMismatchException(dFdY[i][j].length, zLen); 237 } 238 if (dFdZ[i][j].length != zLen) { 239 throw new DimensionMismatchException(dFdZ[i][j].length, zLen); 240 } 241 if (d2FdXdY[i][j].length != zLen) { 242 throw new DimensionMismatchException(d2FdXdY[i][j].length, zLen); 243 } 244 if (d2FdXdZ[i][j].length != zLen) { 245 throw new DimensionMismatchException(d2FdXdZ[i][j].length, zLen); 246 } 247 if (d2FdYdZ[i][j].length != zLen) { 248 throw new DimensionMismatchException(d2FdYdZ[i][j].length, zLen); 249 } 250 if (d3FdXdYdZ[i][j].length != zLen) { 251 throw new DimensionMismatchException(d3FdXdYdZ[i][j].length, zLen); 252 } 253 254 final int jp1 = j + 1; 255 for (int k = 0; k < lastK; k++) { 256 final int kp1 = k + 1; 257 258 final double[] beta = new double[] { 259 f[i][j][k], f[ip1][j][k], 260 f[i][jp1][k], f[ip1][jp1][k], 261 f[i][j][kp1], f[ip1][j][kp1], 262 f[i][jp1][kp1], f[ip1][jp1][kp1], 263 264 dFdX[i][j][k], dFdX[ip1][j][k], 265 dFdX[i][jp1][k], dFdX[ip1][jp1][k], 266 dFdX[i][j][kp1], dFdX[ip1][j][kp1], 267 dFdX[i][jp1][kp1], dFdX[ip1][jp1][kp1], 268 269 dFdY[i][j][k], dFdY[ip1][j][k], 270 dFdY[i][jp1][k], dFdY[ip1][jp1][k], 271 dFdY[i][j][kp1], dFdY[ip1][j][kp1], 272 dFdY[i][jp1][kp1], dFdY[ip1][jp1][kp1], 273 274 dFdZ[i][j][k], dFdZ[ip1][j][k], 275 dFdZ[i][jp1][k], dFdZ[ip1][jp1][k], 276 dFdZ[i][j][kp1], dFdZ[ip1][j][kp1], 277 dFdZ[i][jp1][kp1], dFdZ[ip1][jp1][kp1], 278 279 d2FdXdY[i][j][k], d2FdXdY[ip1][j][k], 280 d2FdXdY[i][jp1][k], d2FdXdY[ip1][jp1][k], 281 d2FdXdY[i][j][kp1], d2FdXdY[ip1][j][kp1], 282 d2FdXdY[i][jp1][kp1], d2FdXdY[ip1][jp1][kp1], 283 284 d2FdXdZ[i][j][k], d2FdXdZ[ip1][j][k], 285 d2FdXdZ[i][jp1][k], d2FdXdZ[ip1][jp1][k], 286 d2FdXdZ[i][j][kp1], d2FdXdZ[ip1][j][kp1], 287 d2FdXdZ[i][jp1][kp1], d2FdXdZ[ip1][jp1][kp1], 288 289 d2FdYdZ[i][j][k], d2FdYdZ[ip1][j][k], 290 d2FdYdZ[i][jp1][k], d2FdYdZ[ip1][jp1][k], 291 d2FdYdZ[i][j][kp1], d2FdYdZ[ip1][j][kp1], 292 d2FdYdZ[i][jp1][kp1], d2FdYdZ[ip1][jp1][kp1], 293 294 d3FdXdYdZ[i][j][k], d3FdXdYdZ[ip1][j][k], 295 d3FdXdYdZ[i][jp1][k], d3FdXdYdZ[ip1][jp1][k], 296 d3FdXdYdZ[i][j][kp1], d3FdXdYdZ[ip1][j][kp1], 297 d3FdXdYdZ[i][jp1][kp1], d3FdXdYdZ[ip1][jp1][kp1], 298 }; 299 300 splines[i][j][k] = new TricubicSplineFunction(computeSplineCoefficients(beta)); 301 } 302 } 303 } 304 } 305 306 /** 307 * {@inheritDoc} 308 */ value(double x, double y, double z)309 public double value(double x, double y, double z) { 310 final int i = searchIndex(x, xval); 311 if (i == -1) { 312 throw new OutOfRangeException(x, xval[0], xval[xval.length - 1]); 313 } 314 final int j = searchIndex(y, yval); 315 if (j == -1) { 316 throw new OutOfRangeException(y, yval[0], yval[yval.length - 1]); 317 } 318 final int k = searchIndex(z, zval); 319 if (k == -1) { 320 throw new OutOfRangeException(z, zval[0], zval[zval.length - 1]); 321 } 322 323 final double xN = (x - xval[i]) / (xval[i + 1] - xval[i]); 324 final double yN = (y - yval[j]) / (yval[j + 1] - yval[j]); 325 final double zN = (z - zval[k]) / (zval[k + 1] - zval[k]); 326 327 return splines[i][j][k].value(xN, yN, zN); 328 } 329 330 /** 331 * @param c Coordinate. 332 * @param val Coordinate samples. 333 * @return the index in {@code val} corresponding to the interval 334 * containing {@code c}, or {@code -1} if {@code c} is out of the 335 * range defined by the end values of {@code val}. 336 */ searchIndex(double c, double[] val)337 private int searchIndex(double c, double[] val) { 338 if (c < val[0]) { 339 return -1; 340 } 341 342 final int max = val.length; 343 for (int i = 1; i < max; i++) { 344 if (c <= val[i]) { 345 return i - 1; 346 } 347 } 348 349 return -1; 350 } 351 352 /** 353 * Compute the spline coefficients from the list of function values and 354 * function partial derivatives values at the four corners of a grid 355 * element. They must be specified in the following order: 356 * <ul> 357 * <li>f(0,0,0)</li> 358 * <li>f(1,0,0)</li> 359 * <li>f(0,1,0)</li> 360 * <li>f(1,1,0)</li> 361 * <li>f(0,0,1)</li> 362 * <li>f(1,0,1)</li> 363 * <li>f(0,1,1)</li> 364 * <li>f(1,1,1)</li> 365 * 366 * <li>f<sub>x</sub>(0,0,0)</li> 367 * <li>... <em>(same order as above)</em></li> 368 * <li>f<sub>x</sub>(1,1,1)</li> 369 * 370 * <li>f<sub>y</sub>(0,0,0)</li> 371 * <li>... <em>(same order as above)</em></li> 372 * <li>f<sub>y</sub>(1,1,1)</li> 373 * 374 * <li>f<sub>z</sub>(0,0,0)</li> 375 * <li>... <em>(same order as above)</em></li> 376 * <li>f<sub>z</sub>(1,1,1)</li> 377 * 378 * <li>f<sub>xy</sub>(0,0,0)</li> 379 * <li>... <em>(same order as above)</em></li> 380 * <li>f<sub>xy</sub>(1,1,1)</li> 381 * 382 * <li>f<sub>xz</sub>(0,0,0)</li> 383 * <li>... <em>(same order as above)</em></li> 384 * <li>f<sub>xz</sub>(1,1,1)</li> 385 * 386 * <li>f<sub>yz</sub>(0,0,0)</li> 387 * <li>... <em>(same order as above)</em></li> 388 * <li>f<sub>yz</sub>(1,1,1)</li> 389 * 390 * <li>f<sub>xyz</sub>(0,0,0)</li> 391 * <li>... <em>(same order as above)</em></li> 392 * <li>f<sub>xyz</sub>(1,1,1)</li> 393 * </ul> 394 * where the subscripts indicate the partial derivative with respect to 395 * the corresponding variable(s). 396 * 397 * @param beta List of function values and function partial derivatives 398 * values. 399 * @return the spline coefficients. 400 */ computeSplineCoefficients(double[] beta)401 private double[] computeSplineCoefficients(double[] beta) { 402 final int sz = 64; 403 final double[] a = new double[sz]; 404 405 for (int i = 0; i < sz; i++) { 406 double result = 0; 407 final double[] row = AINV[i]; 408 for (int j = 0; j < sz; j++) { 409 result += row[j] * beta[j]; 410 } 411 a[i] = result; 412 } 413 414 return a; 415 } 416 } 417 418 /** 419 * 3D-spline function. 420 * 421 * @version $Revision$ $Date$ 422 */ 423 class TricubicSplineFunction 424 implements TrivariateRealFunction { 425 /** Number of points. */ 426 private static final short N = 4; 427 /** Coefficients */ 428 private final double[][][] a = new double[N][N][N]; 429 430 /** 431 * @param aV List of spline coefficients. 432 */ TricubicSplineFunction(double[] aV)433 public TricubicSplineFunction(double[] aV) { 434 for (int i = 0; i < N; i++) { 435 for (int j = 0; j < N; j++) { 436 for (int k = 0; k < N; k++) { 437 a[i][j][k] = aV[i + N * (j + N * k)]; 438 } 439 } 440 } 441 } 442 443 /** 444 * @param x x-coordinate of the interpolation point. 445 * @param y y-coordinate of the interpolation point. 446 * @param z z-coordinate of the interpolation point. 447 * @return the interpolated value. 448 */ value(double x, double y, double z)449 public double value(double x, double y, double z) { 450 if (x < 0 || x > 1) { 451 throw new OutOfRangeException(x, 0, 1); 452 } 453 if (y < 0 || y > 1) { 454 throw new OutOfRangeException(y, 0, 1); 455 } 456 if (z < 0 || z > 1) { 457 throw new OutOfRangeException(z, 0, 1); 458 } 459 460 final double x2 = x * x; 461 final double x3 = x2 * x; 462 final double[] pX = { 1, x, x2, x3 }; 463 464 final double y2 = y * y; 465 final double y3 = y2 * y; 466 final double[] pY = { 1, y, y2, y3 }; 467 468 final double z2 = z * z; 469 final double z3 = z2 * z; 470 final double[] pZ = { 1, z, z2, z3 }; 471 472 double result = 0; 473 for (int i = 0; i < N; i++) { 474 for (int j = 0; j < N; j++) { 475 for (int k = 0; k < N; k++) { 476 result += a[i][j][k] * pX[i] * pY[j] * pZ[k]; 477 } 478 } 479 } 480 481 return result; 482 } 483 } 484