TricubicSplineInterpolatingFunction.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.  *      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.math3.analysis.interpolation;

  18. import org.apache.commons.math3.analysis.TrivariateFunction;
  19. import org.apache.commons.math3.exception.DimensionMismatchException;
  20. import org.apache.commons.math3.exception.NoDataException;
  21. import org.apache.commons.math3.exception.OutOfRangeException;
  22. import org.apache.commons.math3.exception.NonMonotonicSequenceException;
  23. import org.apache.commons.math3.util.MathArrays;

  24. /**
  25.  * Function that implements the
  26.  * <a href="http://en.wikipedia.org/wiki/Tricubic_interpolation">
  27.  * tricubic spline interpolation</a>, as proposed in
  28.  * <quote>
  29.  *  Tricubic interpolation in three dimensions<br/>
  30.  *  F. Lekien and J. Marsden<br/>
  31.  *  <em>Int. J. Numer. Meth. Engng</em> 2005; <b>63</b>:455-471
  32.  * </quote>
  33.  *
  34.  * @since 2.2
  35.  * @deprecated To be removed in 4.0 (see MATH-1166).
  36.  */
  37. @Deprecated
  38. public class TricubicSplineInterpolatingFunction
  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 TricubicSplineFunction[][][] splines;

  118.     /**
  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 NoDataException if any of the arrays has zero length.
  131.      * @throws DimensionMismatchException if the various arrays do not contain the expected number of elements.
  132.      * @throws NonMonotonicSequenceException if {@code x}, {@code y} or {@code z} are not strictly increasing.
  133.      */
  134.     public TricubicSplineInterpolatingFunction(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 NoDataException,
  146.                DimensionMismatchException,
  147.                NonMonotonicSequenceException {
  148.         final int xLen = x.length;
  149.         final int yLen = y.length;
  150.         final int zLen = z.length;

  151.         if (xLen == 0 || yLen == 0 || z.length == 0 || f.length == 0 || f[0].length == 0) {
  152.             throw new NoDataException();
  153.         }
  154.         if (xLen != f.length) {
  155.             throw new DimensionMismatchException(xLen, f.length);
  156.         }
  157.         if (xLen != dFdX.length) {
  158.             throw new DimensionMismatchException(xLen, dFdX.length);
  159.         }
  160.         if (xLen != dFdY.length) {
  161.             throw new DimensionMismatchException(xLen, dFdY.length);
  162.         }
  163.         if (xLen != dFdZ.length) {
  164.             throw new DimensionMismatchException(xLen, dFdZ.length);
  165.         }
  166.         if (xLen != d2FdXdY.length) {
  167.             throw new DimensionMismatchException(xLen, d2FdXdY.length);
  168.         }
  169.         if (xLen != d2FdXdZ.length) {
  170.             throw new DimensionMismatchException(xLen, d2FdXdZ.length);
  171.         }
  172.         if (xLen != d2FdYdZ.length) {
  173.             throw new DimensionMismatchException(xLen, d2FdYdZ.length);
  174.         }
  175.         if (xLen != d3FdXdYdZ.length) {
  176.             throw new DimensionMismatchException(xLen, d3FdXdYdZ.length);
  177.         }

  178.         MathArrays.checkOrder(x);
  179.         MathArrays.checkOrder(y);
  180.         MathArrays.checkOrder(z);

  181.         xval = x.clone();
  182.         yval = y.clone();
  183.         zval = z.clone();

  184.         final int lastI = xLen - 1;
  185.         final int lastJ = yLen - 1;
  186.         final int lastK = zLen - 1;
  187.         splines = new TricubicSplineFunction[lastI][lastJ][lastK];

  188.         for (int i = 0; i < lastI; i++) {
  189.             if (f[i].length != yLen) {
  190.                 throw new DimensionMismatchException(f[i].length, yLen);
  191.             }
  192.             if (dFdX[i].length != yLen) {
  193.                 throw new DimensionMismatchException(dFdX[i].length, yLen);
  194.             }
  195.             if (dFdY[i].length != yLen) {
  196.                 throw new DimensionMismatchException(dFdY[i].length, yLen);
  197.             }
  198.             if (dFdZ[i].length != yLen) {
  199.                 throw new DimensionMismatchException(dFdZ[i].length, yLen);
  200.             }
  201.             if (d2FdXdY[i].length != yLen) {
  202.                 throw new DimensionMismatchException(d2FdXdY[i].length, yLen);
  203.             }
  204.             if (d2FdXdZ[i].length != yLen) {
  205.                 throw new DimensionMismatchException(d2FdXdZ[i].length, yLen);
  206.             }
  207.             if (d2FdYdZ[i].length != yLen) {
  208.                 throw new DimensionMismatchException(d2FdYdZ[i].length, yLen);
  209.             }
  210.             if (d3FdXdYdZ[i].length != yLen) {
  211.                 throw new DimensionMismatchException(d3FdXdYdZ[i].length, yLen);
  212.             }

  213.             final int ip1 = i + 1;
  214.             for (int j = 0; j < lastJ; j++) {
  215.                 if (f[i][j].length != zLen) {
  216.                     throw new DimensionMismatchException(f[i][j].length, zLen);
  217.                 }
  218.                 if (dFdX[i][j].length != zLen) {
  219.                     throw new DimensionMismatchException(dFdX[i][j].length, zLen);
  220.                 }
  221.                 if (dFdY[i][j].length != zLen) {
  222.                     throw new DimensionMismatchException(dFdY[i][j].length, zLen);
  223.                 }
  224.                 if (dFdZ[i][j].length != zLen) {
  225.                     throw new DimensionMismatchException(dFdZ[i][j].length, zLen);
  226.                 }
  227.                 if (d2FdXdY[i][j].length != zLen) {
  228.                     throw new DimensionMismatchException(d2FdXdY[i][j].length, zLen);
  229.                 }
  230.                 if (d2FdXdZ[i][j].length != zLen) {
  231.                     throw new DimensionMismatchException(d2FdXdZ[i][j].length, zLen);
  232.                 }
  233.                 if (d2FdYdZ[i][j].length != zLen) {
  234.                     throw new DimensionMismatchException(d2FdYdZ[i][j].length, zLen);
  235.                 }
  236.                 if (d3FdXdYdZ[i][j].length != zLen) {
  237.                     throw new DimensionMismatchException(d3FdXdYdZ[i][j].length, zLen);
  238.                 }

  239.                 final int jp1 = j + 1;
  240.                 for (int k = 0; k < lastK; k++) {
  241.                     final int kp1 = k + 1;

  242.                     final double[] beta = new double[] {
  243.                         f[i][j][k], f[ip1][j][k],
  244.                         f[i][jp1][k], f[ip1][jp1][k],
  245.                         f[i][j][kp1], f[ip1][j][kp1],
  246.                         f[i][jp1][kp1], f[ip1][jp1][kp1],

  247.                         dFdX[i][j][k], dFdX[ip1][j][k],
  248.                         dFdX[i][jp1][k], dFdX[ip1][jp1][k],
  249.                         dFdX[i][j][kp1], dFdX[ip1][j][kp1],
  250.                         dFdX[i][jp1][kp1], dFdX[ip1][jp1][kp1],

  251.                         dFdY[i][j][k], dFdY[ip1][j][k],
  252.                         dFdY[i][jp1][k], dFdY[ip1][jp1][k],
  253.                         dFdY[i][j][kp1], dFdY[ip1][j][kp1],
  254.                         dFdY[i][jp1][kp1], dFdY[ip1][jp1][kp1],

  255.                         dFdZ[i][j][k], dFdZ[ip1][j][k],
  256.                         dFdZ[i][jp1][k], dFdZ[ip1][jp1][k],
  257.                         dFdZ[i][j][kp1], dFdZ[ip1][j][kp1],
  258.                         dFdZ[i][jp1][kp1], dFdZ[ip1][jp1][kp1],

  259.                         d2FdXdY[i][j][k], d2FdXdY[ip1][j][k],
  260.                         d2FdXdY[i][jp1][k], d2FdXdY[ip1][jp1][k],
  261.                         d2FdXdY[i][j][kp1], d2FdXdY[ip1][j][kp1],
  262.                         d2FdXdY[i][jp1][kp1], d2FdXdY[ip1][jp1][kp1],

  263.                         d2FdXdZ[i][j][k], d2FdXdZ[ip1][j][k],
  264.                         d2FdXdZ[i][jp1][k], d2FdXdZ[ip1][jp1][k],
  265.                         d2FdXdZ[i][j][kp1], d2FdXdZ[ip1][j][kp1],
  266.                         d2FdXdZ[i][jp1][kp1], d2FdXdZ[ip1][jp1][kp1],

  267.                         d2FdYdZ[i][j][k], d2FdYdZ[ip1][j][k],
  268.                         d2FdYdZ[i][jp1][k], d2FdYdZ[ip1][jp1][k],
  269.                         d2FdYdZ[i][j][kp1], d2FdYdZ[ip1][j][kp1],
  270.                         d2FdYdZ[i][jp1][kp1], d2FdYdZ[ip1][jp1][kp1],

  271.                         d3FdXdYdZ[i][j][k], d3FdXdYdZ[ip1][j][k],
  272.                         d3FdXdYdZ[i][jp1][k], d3FdXdYdZ[ip1][jp1][k],
  273.                         d3FdXdYdZ[i][j][kp1], d3FdXdYdZ[ip1][j][kp1],
  274.                         d3FdXdYdZ[i][jp1][kp1], d3FdXdYdZ[ip1][jp1][kp1],
  275.                     };

  276.                     splines[i][j][k] = new TricubicSplineFunction(computeSplineCoefficients(beta));
  277.                 }
  278.             }
  279.         }
  280.     }

  281.     /**
  282.      * {@inheritDoc}
  283.      *
  284.      * @throws OutOfRangeException if any of the variables is outside its interpolation range.
  285.      */
  286.     public double value(double x, double y, double z)
  287.         throws OutOfRangeException {
  288.         final int i = searchIndex(x, xval);
  289.         if (i == -1) {
  290.             throw new OutOfRangeException(x, xval[0], xval[xval.length - 1]);
  291.         }
  292.         final int j = searchIndex(y, yval);
  293.         if (j == -1) {
  294.             throw new OutOfRangeException(y, yval[0], yval[yval.length - 1]);
  295.         }
  296.         final int k = searchIndex(z, zval);
  297.         if (k == -1) {
  298.             throw new OutOfRangeException(z, zval[0], zval[zval.length - 1]);
  299.         }

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

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

  305.     /**
  306.      * @param c Coordinate.
  307.      * @param val Coordinate samples.
  308.      * @return the index in {@code val} corresponding to the interval containing {@code c}, or {@code -1}
  309.      *   if {@code c} is out of the range defined by the end values of {@code val}.
  310.      */
  311.     private int searchIndex(double c, double[] val) {
  312.         if (c < val[0]) {
  313.             return -1;
  314.         }

  315.         final int max = val.length;
  316.         for (int i = 1; i < max; i++) {
  317.             if (c <= val[i]) {
  318.                 return i - 1;
  319.             }
  320.         }

  321.         return -1;
  322.     }

  323.     /**
  324.      * Compute the spline coefficients from the list of function values and
  325.      * function partial derivatives values at the four corners of a grid
  326.      * element. They must be specified in the following order:
  327.      * <ul>
  328.      *  <li>f(0,0,0)</li>
  329.      *  <li>f(1,0,0)</li>
  330.      *  <li>f(0,1,0)</li>
  331.      *  <li>f(1,1,0)</li>
  332.      *  <li>f(0,0,1)</li>
  333.      *  <li>f(1,0,1)</li>
  334.      *  <li>f(0,1,1)</li>
  335.      *  <li>f(1,1,1)</li>
  336.      *
  337.      *  <li>f<sub>x</sub>(0,0,0)</li>
  338.      *  <li>... <em>(same order as above)</em></li>
  339.      *  <li>f<sub>x</sub>(1,1,1)</li>
  340.      *
  341.      *  <li>f<sub>y</sub>(0,0,0)</li>
  342.      *  <li>... <em>(same order as above)</em></li>
  343.      *  <li>f<sub>y</sub>(1,1,1)</li>
  344.      *
  345.      *  <li>f<sub>z</sub>(0,0,0)</li>
  346.      *  <li>... <em>(same order as above)</em></li>
  347.      *  <li>f<sub>z</sub>(1,1,1)</li>
  348.      *
  349.      *  <li>f<sub>xy</sub>(0,0,0)</li>
  350.      *  <li>... <em>(same order as above)</em></li>
  351.      *  <li>f<sub>xy</sub>(1,1,1)</li>
  352.      *
  353.      *  <li>f<sub>xz</sub>(0,0,0)</li>
  354.      *  <li>... <em>(same order as above)</em></li>
  355.      *  <li>f<sub>xz</sub>(1,1,1)</li>
  356.      *
  357.      *  <li>f<sub>yz</sub>(0,0,0)</li>
  358.      *  <li>... <em>(same order as above)</em></li>
  359.      *  <li>f<sub>yz</sub>(1,1,1)</li>
  360.      *
  361.      *  <li>f<sub>xyz</sub>(0,0,0)</li>
  362.      *  <li>... <em>(same order as above)</em></li>
  363.      *  <li>f<sub>xyz</sub>(1,1,1)</li>
  364.      * </ul>
  365.      * where the subscripts indicate the partial derivative with respect to
  366.      * the corresponding variable(s).
  367.      *
  368.      * @param beta List of function values and function partial derivatives values.
  369.      * @return the spline coefficients.
  370.      */
  371.     private double[] computeSplineCoefficients(double[] beta) {
  372.         final int sz = 64;
  373.         final double[] a = new double[sz];

  374.         for (int i = 0; i < sz; i++) {
  375.             double result = 0;
  376.             final double[] row = AINV[i];
  377.             for (int j = 0; j < sz; j++) {
  378.                 result += row[j] * beta[j];
  379.             }
  380.             a[i] = result;
  381.         }

  382.         return a;
  383.     }
  384. }

  385. /**
  386.  * 3D-spline function.
  387.  *
  388.  */
  389. class TricubicSplineFunction
  390.     implements TrivariateFunction {
  391.     /** Number of points. */
  392.     private static final short N = 4;
  393.     /** Coefficients */
  394.     private final double[][][] a = new double[N][N][N];

  395.     /**
  396.      * @param aV List of spline coefficients.
  397.      */
  398.     public TricubicSplineFunction(double[] aV) {
  399.         for (int i = 0; i < N; i++) {
  400.             for (int j = 0; j < N; j++) {
  401.                 for (int k = 0; k < N; k++) {
  402.                     a[i][j][k] = aV[i + N * (j + N * k)];
  403.                 }
  404.             }
  405.         }
  406.     }

  407.     /**
  408.      * @param x x-coordinate of the interpolation point.
  409.      * @param y y-coordinate of the interpolation point.
  410.      * @param z z-coordinate of the interpolation point.
  411.      * @return the interpolated value.
  412.      * @throws OutOfRangeException if {@code x}, {@code y} or
  413.      * {@code z} are not in the interval {@code [0, 1]}.
  414.      */
  415.     public double value(double x, double y, double z)
  416.         throws OutOfRangeException {
  417.         if (x < 0 || x > 1) {
  418.             throw new OutOfRangeException(x, 0, 1);
  419.         }
  420.         if (y < 0 || y > 1) {
  421.             throw new OutOfRangeException(y, 0, 1);
  422.         }
  423.         if (z < 0 || z > 1) {
  424.             throw new OutOfRangeException(z, 0, 1);
  425.         }

  426.         final double x2 = x * x;
  427.         final double x3 = x2 * x;
  428.         final double[] pX = { 1, x, x2, x3 };

  429.         final double y2 = y * y;
  430.         final double y3 = y2 * y;
  431.         final double[] pY = { 1, y, y2, y3 };

  432.         final double z2 = z * z;
  433.         final double z3 = z2 * z;
  434.         final double[] pZ = { 1, z, z2, z3 };

  435.         double result = 0;
  436.         for (int i = 0; i < N; i++) {
  437.             for (int j = 0; j < N; j++) {
  438.                 for (int k = 0; k < N; k++) {
  439.                     result += a[i][j][k] * pX[i] * pY[j] * pZ[k];
  440.                 }
  441.             }
  442.         }

  443.         return result;
  444.     }
  445. }