TricubicInterpolatingFunction.java

  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.  *      https://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. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.analysis.interpolation;

  22. import org.hipparchus.analysis.TrivariateFunction;
  23. import org.hipparchus.exception.LocalizedCoreFormats;
  24. import org.hipparchus.exception.MathIllegalArgumentException;
  25. import org.hipparchus.util.MathArrays;
  26. import org.hipparchus.util.MathUtils;

  27. /**
  28.  * Function that implements the
  29.  * <a href="http://en.wikipedia.org/wiki/Tricubic_interpolation">
  30.  * tricubic spline interpolation</a>, as proposed in
  31.  * <blockquote>
  32.  *  Tricubic interpolation in three dimensions<br>
  33.  *  F. Lekien and J. Marsden<br>
  34.  *  <em>Int. J. Numer. Meth. Eng</em> 2005; <b>63</b>:455-471<br>
  35.  * </blockquote>
  36.  *
  37.  */
  38. public class TricubicInterpolatingFunction
  39.     implements TrivariateFunction {
  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.     /** Samples x-coordinates */
  111.     private final double[] xval;
  112.     /** Samples y-coordinates */
  113.     private final double[] yval;
  114.     /** Samples z-coordinates */
  115.     private final double[] zval;
  116.     /** Set of cubic splines pacthing the whole data grid */
  117.     private final TricubicFunction[][][] splines;

  118.     /** Simple constructor.
  119.      * @param x Sample values of the x-coordinate, in increasing order.
  120.      * @param y Sample values of the y-coordinate, in increasing order.
  121.      * @param z Sample values of the y-coordinate, in increasing order.
  122.      * @param f Values of the function on every grid point.
  123.      * @param dFdX Values of the partial derivative of function with respect to x on every grid point.
  124.      * @param dFdY Values of the partial derivative of function with respect to y on every grid point.
  125.      * @param dFdZ Values of the partial derivative of function with respect to z on every grid point.
  126.      * @param d2FdXdY Values of the cross partial derivative of function on every grid point.
  127.      * @param d2FdXdZ Values of the cross partial derivative of function on every grid point.
  128.      * @param d2FdYdZ Values of the cross partial derivative of function on every grid point.
  129.      * @param d3FdXdYdZ Values of the cross partial derivative of function on every grid point.
  130.      * @throws MathIllegalArgumentException if any of the arrays has zero length.
  131.      * @throws MathIllegalArgumentException if the various arrays do not contain the expected number of elements.
  132.      * @throws MathIllegalArgumentException if {@code x}, {@code y} or {@code z} are not strictly increasing.
  133.      */
  134.     public TricubicInterpolatingFunction(double[] x,
  135.                                          double[] y,
  136.                                          double[] z,
  137.                                          double[][][] f,
  138.                                          double[][][] dFdX,
  139.                                          double[][][] dFdY,
  140.                                          double[][][] dFdZ,
  141.                                          double[][][] d2FdXdY,
  142.                                          double[][][] d2FdXdZ,
  143.                                          double[][][] d2FdYdZ,
  144.                                          double[][][] d3FdXdYdZ)
  145.         throws MathIllegalArgumentException {
  146.         final int xLen = x.length;
  147.         final int yLen = y.length;
  148.         final int zLen = z.length;

  149.         if (xLen == 0 || yLen == 0 || z.length == 0 || f.length == 0 || f[0].length == 0) {
  150.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NO_DATA);
  151.         }
  152.         if (xLen != f.length) {
  153.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  154.                                                    xLen, f.length);
  155.         }
  156.         if (xLen != dFdX.length) {
  157.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  158.                                                    xLen, dFdX.length);
  159.         }
  160.         if (xLen != dFdY.length) {
  161.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  162.                                                    xLen, dFdY.length);
  163.         }
  164.         if (xLen != dFdZ.length) {
  165.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  166.                                                    xLen, dFdZ.length);
  167.         }
  168.         if (xLen != d2FdXdY.length) {
  169.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  170.                                                    xLen, d2FdXdY.length);
  171.         }
  172.         if (xLen != d2FdXdZ.length) {
  173.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  174.                                                    xLen, d2FdXdZ.length);
  175.         }
  176.         if (xLen != d2FdYdZ.length) {
  177.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  178.                                                    xLen, d2FdYdZ.length);
  179.         }
  180.         if (xLen != d3FdXdYdZ.length) {
  181.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  182.                                                    xLen, d3FdXdYdZ.length);
  183.         }

  184.         MathArrays.checkOrder(x);
  185.         MathArrays.checkOrder(y);
  186.         MathArrays.checkOrder(z);

  187.         xval = x.clone();
  188.         yval = y.clone();
  189.         zval = z.clone();

  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.         for (int i = 0; i < lastI; i++) {
  195.             if (f[i].length != yLen) {
  196.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  197.                                                        f[i].length, yLen);
  198.             }
  199.             if (dFdX[i].length != yLen) {
  200.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  201.                                                        dFdX[i].length, yLen);
  202.             }
  203.             if (dFdY[i].length != yLen) {
  204.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  205.                                                        dFdY[i].length, yLen);
  206.             }
  207.             if (dFdZ[i].length != yLen) {
  208.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  209.                                                        dFdZ[i].length, yLen);
  210.             }
  211.             if (d2FdXdY[i].length != yLen) {
  212.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  213.                                                        d2FdXdY[i].length, yLen);
  214.             }
  215.             if (d2FdXdZ[i].length != yLen) {
  216.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  217.                                                        d2FdXdZ[i].length, yLen);
  218.             }
  219.             if (d2FdYdZ[i].length != yLen) {
  220.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  221.                                                        d2FdYdZ[i].length, yLen);
  222.             }
  223.             if (d3FdXdYdZ[i].length != yLen) {
  224.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  225.                                                        d3FdXdYdZ[i].length, yLen);
  226.             }

  227.             final int ip1 = i + 1;
  228.             final double xR = xval[ip1] - xval[i];
  229.             for (int j = 0; j < lastJ; j++) {
  230.                 if (f[i][j].length != zLen) {
  231.                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  232.                                                            f[i][j].length, zLen);
  233.                 }
  234.                 if (dFdX[i][j].length != zLen) {
  235.                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  236.                                                            dFdX[i][j].length, zLen);
  237.                 }
  238.                 if (dFdY[i][j].length != zLen) {
  239.                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  240.                                                            dFdY[i][j].length, zLen);
  241.                 }
  242.                 if (dFdZ[i][j].length != zLen) {
  243.                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  244.                                                            dFdZ[i][j].length, zLen);
  245.                 }
  246.                 if (d2FdXdY[i][j].length != zLen) {
  247.                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  248.                                                            d2FdXdY[i][j].length, zLen);
  249.                 }
  250.                 if (d2FdXdZ[i][j].length != zLen) {
  251.                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  252.                                                            d2FdXdZ[i][j].length, zLen);
  253.                 }
  254.                 if (d2FdYdZ[i][j].length != zLen) {
  255.                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  256.                                                            d2FdYdZ[i][j].length, zLen);
  257.                 }
  258.                 if (d3FdXdYdZ[i][j].length != zLen) {
  259.                     throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  260.                                                            d3FdXdYdZ[i][j].length, zLen);
  261.                 }

  262.                 final int jp1 = j + 1;
  263.                 final double yR = yval[jp1] - yval[j];
  264.                 final double xRyR = xR * yR;
  265.                 for (int k = 0; k < lastK; k++) {
  266.                     final int kp1 = k + 1;
  267.                     final double zR = zval[kp1] - zval[k];
  268.                     final double xRzR = xR * zR;
  269.                     final double yRzR = yR * zR;
  270.                     final double xRyRzR = xR * yRzR;

  271.                     final double[] beta = {
  272.                         f[i][j][k], f[ip1][j][k],
  273.                         f[i][jp1][k], f[ip1][jp1][k],
  274.                         f[i][j][kp1], f[ip1][j][kp1],
  275.                         f[i][jp1][kp1], f[ip1][jp1][kp1],

  276.                         dFdX[i][j][k] * xR, dFdX[ip1][j][k] * xR,
  277.                         dFdX[i][jp1][k] * xR, dFdX[ip1][jp1][k] * xR,
  278.                         dFdX[i][j][kp1] * xR, dFdX[ip1][j][kp1] * xR,
  279.                         dFdX[i][jp1][kp1] * xR, dFdX[ip1][jp1][kp1] * xR,

  280.                         dFdY[i][j][k] * yR, dFdY[ip1][j][k] * yR,
  281.                         dFdY[i][jp1][k] * yR, dFdY[ip1][jp1][k] * yR,
  282.                         dFdY[i][j][kp1] * yR, dFdY[ip1][j][kp1] * yR,
  283.                         dFdY[i][jp1][kp1] * yR, dFdY[ip1][jp1][kp1] * yR,

  284.                         dFdZ[i][j][k] * zR, dFdZ[ip1][j][k] * zR,
  285.                         dFdZ[i][jp1][k] * zR, dFdZ[ip1][jp1][k] * zR,
  286.                         dFdZ[i][j][kp1] * zR, dFdZ[ip1][j][kp1] * zR,
  287.                         dFdZ[i][jp1][kp1] * zR, dFdZ[ip1][jp1][kp1] * zR,

  288.                         d2FdXdY[i][j][k] * xRyR, d2FdXdY[ip1][j][k] * xRyR,
  289.                         d2FdXdY[i][jp1][k] * xRyR, d2FdXdY[ip1][jp1][k] * xRyR,
  290.                         d2FdXdY[i][j][kp1] * xRyR, d2FdXdY[ip1][j][kp1] * xRyR,
  291.                         d2FdXdY[i][jp1][kp1] * xRyR, d2FdXdY[ip1][jp1][kp1] * xRyR,

  292.                         d2FdXdZ[i][j][k] * xRzR, d2FdXdZ[ip1][j][k] * xRzR,
  293.                         d2FdXdZ[i][jp1][k] * xRzR, d2FdXdZ[ip1][jp1][k] * xRzR,
  294.                         d2FdXdZ[i][j][kp1] * xRzR, d2FdXdZ[ip1][j][kp1] * xRzR,
  295.                         d2FdXdZ[i][jp1][kp1] * xRzR, d2FdXdZ[ip1][jp1][kp1] * xRzR,

  296.                         d2FdYdZ[i][j][k] * yRzR, d2FdYdZ[ip1][j][k] * yRzR,
  297.                         d2FdYdZ[i][jp1][k] * yRzR, d2FdYdZ[ip1][jp1][k] * yRzR,
  298.                         d2FdYdZ[i][j][kp1] * yRzR, d2FdYdZ[ip1][j][kp1] * yRzR,
  299.                         d2FdYdZ[i][jp1][kp1] * yRzR, d2FdYdZ[ip1][jp1][kp1] * yRzR,

  300.                         d3FdXdYdZ[i][j][k] * xRyRzR, d3FdXdYdZ[ip1][j][k] * xRyRzR,
  301.                         d3FdXdYdZ[i][jp1][k] * xRyRzR, d3FdXdYdZ[ip1][jp1][k] * xRyRzR,
  302.                         d3FdXdYdZ[i][j][kp1] * xRyRzR, d3FdXdYdZ[ip1][j][kp1] * xRyRzR,
  303.                         d3FdXdYdZ[i][jp1][kp1] * xRyRzR, d3FdXdYdZ[ip1][jp1][kp1] * xRyRzR,
  304.                     };

  305.                     splines[i][j][k] = new TricubicFunction(computeCoefficients(beta));
  306.                 }
  307.             }
  308.         }
  309.     }

  310.     /**
  311.      * {@inheritDoc}
  312.      *
  313.      * @throws MathIllegalArgumentException if any of the variables is outside its interpolation range.
  314.      */
  315.     @Override
  316.     public double value(double x, double y, double z)
  317.         throws MathIllegalArgumentException {
  318.         final int i = searchIndex(x, xval);
  319.         if (i == -1) {
  320.             throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE,
  321.                                                    x, xval[0], xval[xval.length - 1]);
  322.         }
  323.         final int j = searchIndex(y, yval);
  324.         if (j == -1) {
  325.             throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE,
  326.                                                    y, yval[0], yval[yval.length - 1]);
  327.         }
  328.         final int k = searchIndex(z, zval);
  329.         if (k == -1) {
  330.             throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE,
  331.                                                    z, zval[0], zval[zval.length - 1]);
  332.         }

  333.         final double xN = (x - xval[i]) / (xval[i + 1] - xval[i]);
  334.         final double yN = (y - yval[j]) / (yval[j + 1] - yval[j]);
  335.         final double zN = (z - zval[k]) / (zval[k + 1] - zval[k]);

  336.         return splines[i][j][k].value(xN, yN, zN);
  337.     }

  338.     /**
  339.      * Indicates whether a point is within the interpolation range.
  340.      *
  341.      * @param x First coordinate.
  342.      * @param y Second coordinate.
  343.      * @param z Third coordinate.
  344.      * @return {@code true} if (x, y, z) is a valid point.
  345.      */
  346.     public boolean isValidPoint(double x, double y, double z) {
  347.         if (x < xval[0] ||
  348.             x > xval[xval.length - 1] ||
  349.             y < yval[0] ||
  350.             y > yval[yval.length - 1] ||
  351.             z < zval[0] ||
  352.             z > zval[zval.length - 1]) {
  353.             return false;
  354.         } else {
  355.             return true;
  356.         }
  357.     }

  358.     /**
  359.      * @param c Coordinate.
  360.      * @param val Coordinate samples.
  361.      * @return the index in {@code val} corresponding to the interval containing {@code c}, or {@code -1}
  362.      *   if {@code c} is out of the range defined by the end values of {@code val}.
  363.      */
  364.     private int searchIndex(double c, double[] val) {
  365.         if (c < val[0]) {
  366.             return -1;
  367.         }

  368.         final int max = val.length;
  369.         for (int i = 1; i < max; i++) {
  370.             if (c <= val[i]) {
  371.                 return i - 1;
  372.             }
  373.         }

  374.         return -1;
  375.     }

  376.     /**
  377.      * Compute the spline coefficients from the list of function values and
  378.      * function partial derivatives values at the four corners of a grid
  379.      * element. They must be specified in the following order:
  380.      * <ul>
  381.      *  <li>f(0,0,0)</li>
  382.      *  <li>f(1,0,0)</li>
  383.      *  <li>f(0,1,0)</li>
  384.      *  <li>f(1,1,0)</li>
  385.      *  <li>f(0,0,1)</li>
  386.      *  <li>f(1,0,1)</li>
  387.      *  <li>f(0,1,1)</li>
  388.      *  <li>f(1,1,1)</li>
  389.      *
  390.      *  <li>f<sub>x</sub>(0,0,0)</li>
  391.      *  <li>... <em>(same order as above)</em></li>
  392.      *  <li>f<sub>x</sub>(1,1,1)</li>
  393.      *
  394.      *  <li>f<sub>y</sub>(0,0,0)</li>
  395.      *  <li>... <em>(same order as above)</em></li>
  396.      *  <li>f<sub>y</sub>(1,1,1)</li>
  397.      *
  398.      *  <li>f<sub>z</sub>(0,0,0)</li>
  399.      *  <li>... <em>(same order as above)</em></li>
  400.      *  <li>f<sub>z</sub>(1,1,1)</li>
  401.      *
  402.      *  <li>f<sub>xy</sub>(0,0,0)</li>
  403.      *  <li>... <em>(same order as above)</em></li>
  404.      *  <li>f<sub>xy</sub>(1,1,1)</li>
  405.      *
  406.      *  <li>f<sub>xz</sub>(0,0,0)</li>
  407.      *  <li>... <em>(same order as above)</em></li>
  408.      *  <li>f<sub>xz</sub>(1,1,1)</li>
  409.      *
  410.      *  <li>f<sub>yz</sub>(0,0,0)</li>
  411.      *  <li>... <em>(same order as above)</em></li>
  412.      *  <li>f<sub>yz</sub>(1,1,1)</li>
  413.      *
  414.      *  <li>f<sub>xyz</sub>(0,0,0)</li>
  415.      *  <li>... <em>(same order as above)</em></li>
  416.      *  <li>f<sub>xyz</sub>(1,1,1)</li>
  417.      * </ul>
  418.      * where the subscripts indicate the partial derivative with respect to
  419.      * the corresponding variable(s).
  420.      *
  421.      * @param beta List of function values and function partial derivatives values.
  422.      * @return the spline coefficients.
  423.      */
  424.     private double[] computeCoefficients(double[] beta) {
  425.         final int sz = 64;
  426.         final double[] a = new double[sz];

  427.         for (int i = 0; i < sz; i++) {
  428.             double result = 0;
  429.             final double[] row = AINV[i];
  430.             for (int j = 0; j < sz; j++) {
  431.                 result += row[j] * beta[j];
  432.             }
  433.             a[i] = result;
  434.         }

  435.         return a;
  436.     }
  437. }

  438. /**
  439.  * 3D-spline function.
  440.  *
  441.  */
  442. class TricubicFunction
  443.     implements TrivariateFunction {
  444.     /** Number of points. */
  445.     private static final short N = 4;
  446.     /** Coefficients */
  447.     private final double[][][] a = new double[N][N][N];

  448.     /**
  449.      * @param aV List of spline coefficients.
  450.      */
  451.     TricubicFunction(double[] aV) {
  452.         for (int i = 0; i < N; i++) {
  453.             for (int j = 0; j < N; j++) {
  454.                 for (int k = 0; k < N; k++) {
  455.                     a[i][j][k] = aV[i + N * (j + N * k)];
  456.                 }
  457.             }
  458.         }
  459.     }

  460.     /**
  461.      * @param x x-coordinate of the interpolation point.
  462.      * @param y y-coordinate of the interpolation point.
  463.      * @param z z-coordinate of the interpolation point.
  464.      * @return the interpolated value.
  465.      * @throws MathIllegalArgumentException if {@code x}, {@code y} or
  466.      * {@code z} are not in the interval {@code [0, 1]}.
  467.      */
  468.     @Override
  469.     public double value(double x, double y, double z) throws MathIllegalArgumentException {
  470.         MathUtils.checkRangeInclusive(x, 0, 1);
  471.         MathUtils.checkRangeInclusive(y, 0, 1);
  472.         MathUtils.checkRangeInclusive(z, 0, 1);

  473.         final double x2 = x * x;
  474.         final double x3 = x2 * x;
  475.         final double[] pX = { 1, x, x2, x3 };

  476.         final double y2 = y * y;
  477.         final double y3 = y2 * y;
  478.         final double[] pY = { 1, y, y2, y3 };

  479.         final double z2 = z * z;
  480.         final double z3 = z2 * z;
  481.         final double[] pZ = { 1, z, z2, z3 };

  482.         double result = 0;
  483.         for (int i = 0; i < N; i++) {
  484.             for (int j = 0; j < N; j++) {
  485.                 for (int k = 0; k < N; k++) {
  486.                     result += a[i][j][k] * pX[i] * pY[j] * pZ[k];
  487.                 }
  488.             }
  489.         }

  490.         return result;
  491.     }
  492. }