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.  *      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.math4.legacy.analysis.interpolation;

  18. import org.apache.commons.math4.legacy.analysis.TrivariateFunction;
  19. import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
  20. import org.apache.commons.math4.legacy.exception.NoDataException;
  21. import org.apache.commons.math4.legacy.exception.NonMonotonicSequenceException;
  22. import org.apache.commons.math4.legacy.exception.OutOfRangeException;
  23. import org.apache.commons.math4.legacy.core.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.  * <blockquote>
  29.  *  Tricubic interpolation in three dimensions<br>
  30.  *  F. Lekien and J. Marsden<br>
  31.  *  <em>Int. J. Numer. Meth. Eng</em> 2005; <b>63</b>:455-471<br>
  32.  * </blockquote>
  33.  *
  34.  * @since 3.4.
  35.  */
  36. public class TricubicInterpolatingFunction
  37.     implements TrivariateFunction {
  38.     /**
  39.      * Matrix to compute the spline coefficients from the function values
  40.      * and function derivatives values.
  41.      */
  42.     private static final double[][] AINV = {
  43.         { 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 },
  44.         { 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 },
  45.         { -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 },
  46.         { 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 },
  47.         { 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 },
  48.         { 0,0,0,0,0,0,0,0,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 },
  49.         { 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 },
  50.         { 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 },
  51.         { -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 },
  52.         { 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 },
  53.         { 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 },
  54.         { -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 },
  55.         { 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 },
  56.         { 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 },
  57.         { -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 },
  58.         { 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 },
  59.         { 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 },
  60.         { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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 },
  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,-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 },
  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,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 },
  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,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 },
  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,0,0,0,0,0,0,0,0,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 },
  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,-3,3,0,0,0,0,0,0,-2,-1,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,2,-2,0,0,0,0,0,0,1,1,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,-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 },
  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,-3,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,-1,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,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 },
  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,-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 },
  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,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 },
  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,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 },
  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,-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 },
  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,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 },
  75.         {-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 },
  76.         { 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 },
  77.         { 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 },
  78.         { -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 },
  79.         { 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 },
  80.         { 0,0,0,0,0,0,0,0,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 },
  81.         { 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 },
  82.         { 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 },
  83.         { 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 },
  84.         { 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 },
  85.         { -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 },
  86.         { 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 },
  87.         { -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 },
  88.         { 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 },
  89.         { 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 },
  90.         { -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 },
  91.         { 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 },
  92.         { 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 },
  93.         { -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 },
  94.         { 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 },
  95.         { 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 },
  96.         { 0,0,0,0,0,0,0,0,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 },
  97.         { 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 },
  98.         { 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 },
  99.         { -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 },
  100.         { 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 },
  101.         { 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 },
  102.         { -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 },
  103.         { 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 },
  104.         { 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 },
  105.         { -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 },
  106.         { 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 }
  107.     };

  108.     /** Samples x-coordinates. */
  109.     private final double[] xval;
  110.     /** Samples y-coordinates. */
  111.     private final double[] yval;
  112.     /** Samples z-coordinates. */
  113.     private final double[] zval;
  114.     /** Set of cubic splines patching the whole data grid. */
  115.     private final TricubicFunction[][][] splines;

  116.     /**
  117.      * @param x Sample values of the x-coordinate, in increasing order.
  118.      * @param y Sample values of the y-coordinate, in increasing order.
  119.      * @param z Sample values of the y-coordinate, in increasing order.
  120.      * @param f Values of the function on every grid point.
  121.      * @param dFdX Values of the partial derivative of function with respect to x on every grid point.
  122.      * @param dFdY Values of the partial derivative of function with respect to y on every grid point.
  123.      * @param dFdZ Values of the partial derivative of function with respect to z on every grid point.
  124.      * @param d2FdXdY Values of the cross partial derivative of function on every grid point.
  125.      * @param d2FdXdZ Values of the cross partial derivative of function on every grid point.
  126.      * @param d2FdYdZ Values of the cross partial derivative of function on every grid point.
  127.      * @param d3FdXdYdZ Values of the cross partial derivative of function on every grid point.
  128.      * @throws NoDataException if any of the arrays has zero length.
  129.      * @throws DimensionMismatchException if the various arrays do not contain the expected number of elements.
  130.      * @throws NonMonotonicSequenceException if {@code x}, {@code y} or {@code z} are not strictly increasing.
  131.      */
  132.     public TricubicInterpolatingFunction(double[] x,
  133.                                          double[] y,
  134.                                          double[] z,
  135.                                          double[][][] f,
  136.                                          double[][][] dFdX,
  137.                                          double[][][] dFdY,
  138.                                          double[][][] dFdZ,
  139.                                          double[][][] d2FdXdY,
  140.                                          double[][][] d2FdXdZ,
  141.                                          double[][][] d2FdYdZ,
  142.                                          double[][][] d3FdXdYdZ)
  143.         throws NoDataException,
  144.                DimensionMismatchException,
  145.                NonMonotonicSequenceException {
  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 NoDataException();
  151.         }
  152.         if (xLen != f.length) {
  153.             throw new DimensionMismatchException(xLen, f.length);
  154.         }
  155.         if (xLen != dFdX.length) {
  156.             throw new DimensionMismatchException(xLen, dFdX.length);
  157.         }
  158.         if (xLen != dFdY.length) {
  159.             throw new DimensionMismatchException(xLen, dFdY.length);
  160.         }
  161.         if (xLen != dFdZ.length) {
  162.             throw new DimensionMismatchException(xLen, dFdZ.length);
  163.         }
  164.         if (xLen != d2FdXdY.length) {
  165.             throw new DimensionMismatchException(xLen, d2FdXdY.length);
  166.         }
  167.         if (xLen != d2FdXdZ.length) {
  168.             throw new DimensionMismatchException(xLen, d2FdXdZ.length);
  169.         }
  170.         if (xLen != d2FdYdZ.length) {
  171.             throw new DimensionMismatchException(xLen, d2FdYdZ.length);
  172.         }
  173.         if (xLen != d3FdXdYdZ.length) {
  174.             throw new DimensionMismatchException(xLen, d3FdXdYdZ.length);
  175.         }

  176.         MathArrays.checkOrder(x);
  177.         MathArrays.checkOrder(y);
  178.         MathArrays.checkOrder(z);

  179.         xval = x.clone();
  180.         yval = y.clone();
  181.         zval = z.clone();

  182.         final int lastI = xLen - 1;
  183.         final int lastJ = yLen - 1;
  184.         final int lastK = zLen - 1;
  185.         splines = new TricubicFunction[lastI][lastJ][lastK];

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

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

  238.                 final int jp1 = j + 1;
  239.                 final double yR = yval[jp1] - yval[j];
  240.                 final double xRyR = xR * yR;
  241.                 for (int k = 0; k < lastK; k++) {
  242.                     final int kp1 = k + 1;
  243.                     final double zR = zval[kp1] - zval[k];
  244.                     final double xRzR = xR * zR;
  245.                     final double yRzR = yR * zR;
  246.                     final double xRyRzR = xR * yRzR;

  247.                     final double[] beta = new double[] {
  248.                         f[i][j][k], f[ip1][j][k],
  249.                         f[i][jp1][k], f[ip1][jp1][k],
  250.                         f[i][j][kp1], f[ip1][j][kp1],
  251.                         f[i][jp1][kp1], f[ip1][jp1][kp1],

  252.                         dFdX[i][j][k] * xR, dFdX[ip1][j][k] * xR,
  253.                         dFdX[i][jp1][k] * xR, dFdX[ip1][jp1][k] * xR,
  254.                         dFdX[i][j][kp1] * xR, dFdX[ip1][j][kp1] * xR,
  255.                         dFdX[i][jp1][kp1] * xR, dFdX[ip1][jp1][kp1] * xR,

  256.                         dFdY[i][j][k] * yR, dFdY[ip1][j][k] * yR,
  257.                         dFdY[i][jp1][k] * yR, dFdY[ip1][jp1][k] * yR,
  258.                         dFdY[i][j][kp1] * yR, dFdY[ip1][j][kp1] * yR,
  259.                         dFdY[i][jp1][kp1] * yR, dFdY[ip1][jp1][kp1] * yR,

  260.                         dFdZ[i][j][k] * zR, dFdZ[ip1][j][k] * zR,
  261.                         dFdZ[i][jp1][k] * zR, dFdZ[ip1][jp1][k] * zR,
  262.                         dFdZ[i][j][kp1] * zR, dFdZ[ip1][j][kp1] * zR,
  263.                         dFdZ[i][jp1][kp1] * zR, dFdZ[ip1][jp1][kp1] * zR,

  264.                         d2FdXdY[i][j][k] * xRyR, d2FdXdY[ip1][j][k] * xRyR,
  265.                         d2FdXdY[i][jp1][k] * xRyR, d2FdXdY[ip1][jp1][k] * xRyR,
  266.                         d2FdXdY[i][j][kp1] * xRyR, d2FdXdY[ip1][j][kp1] * xRyR,
  267.                         d2FdXdY[i][jp1][kp1] * xRyR, d2FdXdY[ip1][jp1][kp1] * xRyR,

  268.                         d2FdXdZ[i][j][k] * xRzR, d2FdXdZ[ip1][j][k] * xRzR,
  269.                         d2FdXdZ[i][jp1][k] * xRzR, d2FdXdZ[ip1][jp1][k] * xRzR,
  270.                         d2FdXdZ[i][j][kp1] * xRzR, d2FdXdZ[ip1][j][kp1] * xRzR,
  271.                         d2FdXdZ[i][jp1][kp1] * xRzR, d2FdXdZ[ip1][jp1][kp1] * xRzR,

  272.                         d2FdYdZ[i][j][k] * yRzR, d2FdYdZ[ip1][j][k] * yRzR,
  273.                         d2FdYdZ[i][jp1][k] * yRzR, d2FdYdZ[ip1][jp1][k] * yRzR,
  274.                         d2FdYdZ[i][j][kp1] * yRzR, d2FdYdZ[ip1][j][kp1] * yRzR,
  275.                         d2FdYdZ[i][jp1][kp1] * yRzR, d2FdYdZ[ip1][jp1][kp1] * yRzR,

  276.                         d3FdXdYdZ[i][j][k] * xRyRzR, d3FdXdYdZ[ip1][j][k] * xRyRzR,
  277.                         d3FdXdYdZ[i][jp1][k] * xRyRzR, d3FdXdYdZ[ip1][jp1][k] * xRyRzR,
  278.                         d3FdXdYdZ[i][j][kp1] * xRyRzR, d3FdXdYdZ[ip1][j][kp1] * xRyRzR,
  279.                         d3FdXdYdZ[i][jp1][kp1] * xRyRzR, d3FdXdYdZ[ip1][jp1][kp1] * xRyRzR,
  280.                     };

  281.                     splines[i][j][k] = new TricubicFunction(computeCoefficients(beta));
  282.                 }
  283.             }
  284.         }
  285.     }

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

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

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

  311.     /**
  312.      * Indicates whether a point is within the interpolation range.
  313.      *
  314.      * @param x First coordinate.
  315.      * @param y Second coordinate.
  316.      * @param z Third coordinate.
  317.      * @return {@code true} if (x, y, z) is a valid point.
  318.      */
  319.     public boolean isValidPoint(double x, double y, double z) {
  320.         return !(x < xval[0] ||
  321.             x > xval[xval.length - 1] ||
  322.             y < yval[0] ||
  323.             y > yval[yval.length - 1] ||
  324.             z < zval[0] ||
  325.             z > zval[zval.length - 1]);
  326.     }

  327.     /**
  328.      * @param c Coordinate.
  329.      * @param val Coordinate samples.
  330.      * @return the index in {@code val} corresponding to the interval containing {@code c}, or {@code -1}
  331.      *   if {@code c} is out of the range defined by the end values of {@code val}.
  332.      */
  333.     private int searchIndex(double c, double[] val) {
  334.         if (c < val[0]) {
  335.             return -1;
  336.         }

  337.         final int max = val.length;
  338.         for (int i = 1; i < max; i++) {
  339.             if (c <= val[i]) {
  340.                 return i - 1;
  341.             }
  342.         }

  343.         return -1;
  344.     }

  345.     /**
  346.      * Compute the spline coefficients from the list of function values and
  347.      * function partial derivatives values at the four corners of a grid
  348.      * element. They must be specified in the following order:
  349.      * <ul>
  350.      *  <li>f(0,0,0)</li>
  351.      *  <li>f(1,0,0)</li>
  352.      *  <li>f(0,1,0)</li>
  353.      *  <li>f(1,1,0)</li>
  354.      *  <li>f(0,0,1)</li>
  355.      *  <li>f(1,0,1)</li>
  356.      *  <li>f(0,1,1)</li>
  357.      *  <li>f(1,1,1)</li>
  358.      *
  359.      *  <li>f<sub>x</sub>(0,0,0)</li>
  360.      *  <li>... <em>(same order as above)</em></li>
  361.      *  <li>f<sub>x</sub>(1,1,1)</li>
  362.      *
  363.      *  <li>f<sub>y</sub>(0,0,0)</li>
  364.      *  <li>... <em>(same order as above)</em></li>
  365.      *  <li>f<sub>y</sub>(1,1,1)</li>
  366.      *
  367.      *  <li>f<sub>z</sub>(0,0,0)</li>
  368.      *  <li>... <em>(same order as above)</em></li>
  369.      *  <li>f<sub>z</sub>(1,1,1)</li>
  370.      *
  371.      *  <li>f<sub>xy</sub>(0,0,0)</li>
  372.      *  <li>... <em>(same order as above)</em></li>
  373.      *  <li>f<sub>xy</sub>(1,1,1)</li>
  374.      *
  375.      *  <li>f<sub>xz</sub>(0,0,0)</li>
  376.      *  <li>... <em>(same order as above)</em></li>
  377.      *  <li>f<sub>xz</sub>(1,1,1)</li>
  378.      *
  379.      *  <li>f<sub>yz</sub>(0,0,0)</li>
  380.      *  <li>... <em>(same order as above)</em></li>
  381.      *  <li>f<sub>yz</sub>(1,1,1)</li>
  382.      *
  383.      *  <li>f<sub>xyz</sub>(0,0,0)</li>
  384.      *  <li>... <em>(same order as above)</em></li>
  385.      *  <li>f<sub>xyz</sub>(1,1,1)</li>
  386.      * </ul>
  387.      * where the subscripts indicate the partial derivative with respect to
  388.      * the corresponding variable(s).
  389.      *
  390.      * @param beta List of function values and function partial derivatives values.
  391.      * @return the spline coefficients.
  392.      */
  393.     private double[] computeCoefficients(double[] beta) {
  394.         final int sz = 64;
  395.         final double[] a = new double[sz];

  396.         for (int i = 0; i < sz; i++) {
  397.             double result = 0;
  398.             final double[] row = AINV[i];
  399.             for (int j = 0; j < sz; j++) {
  400.                 result += row[j] * beta[j];
  401.             }
  402.             a[i] = result;
  403.         }

  404.         return a;
  405.     }
  406. }

  407. /**
  408.  * 3D-spline function.
  409.  *
  410.  */
  411. class TricubicFunction
  412.     implements TrivariateFunction {
  413.     /** Number of points. */
  414.     private static final short N = 4;
  415.     /** Coefficients. */
  416.     private final double[][][] a = new double[N][N][N];

  417.     /**
  418.      * @param aV List of spline coefficients.
  419.      */
  420.     TricubicFunction(double[] aV) {
  421.         for (int i = 0; i < N; i++) {
  422.             for (int j = 0; j < N; j++) {
  423.                 for (int k = 0; k < N; k++) {
  424.                     a[i][j][k] = aV[i + N * (j + N * k)];
  425.                 }
  426.             }
  427.         }
  428.     }

  429.     /**
  430.      * @param x x-coordinate of the interpolation point.
  431.      * @param y y-coordinate of the interpolation point.
  432.      * @param z z-coordinate of the interpolation point.
  433.      * @return the interpolated value.
  434.      * @throws OutOfRangeException if {@code x}, {@code y} or
  435.      * {@code z} are not in the interval {@code [0, 1]}.
  436.      */
  437.     @Override
  438.     public double value(double x, double y, double z) throws OutOfRangeException {
  439.         if (x < 0 || x > 1) {
  440.             throw new OutOfRangeException(x, 0, 1);
  441.         }
  442.         if (y < 0 || y > 1) {
  443.             throw new OutOfRangeException(y, 0, 1);
  444.         }
  445.         if (z < 0 || z > 1) {
  446.             throw new OutOfRangeException(z, 0, 1);
  447.         }

  448.         final double x2 = x * x;
  449.         final double x3 = x2 * x;
  450.         final double[] pX = { 1, x, x2, x3 };

  451.         final double y2 = y * y;
  452.         final double y3 = y2 * y;
  453.         final double[] pY = { 1, y, y2, y3 };

  454.         final double z2 = z * z;
  455.         final double z3 = z2 * z;
  456.         final double[] pZ = { 1, z, z2, z3 };

  457.         double result = 0;
  458.         for (int i = 0; i < N; i++) {
  459.             for (int j = 0; j < N; j++) {
  460.                 for (int k = 0; k < N; k++) {
  461.                     result += a[i][j][k] * pX[i] * pY[j] * pZ[k];
  462.                 }
  463.             }
  464.         }

  465.         return result;
  466.     }
  467. }