/** Check Math.abs(value) < SMALL is smoothly connected to general cases */
 @Test
 public void closeToZeroTest() {
   double[] xValues = new double[] {0.1, 0.2, 0.3, 0.4};
   double[] yValues = new double[] {0.1, 0.2, 0.3, 0.4};
   int n = INTERP_SENSE.length;
   for (int i = 0; i < n; ++i) {
     ReciprocalExtrapolator1D extrap1D =
         new ReciprocalExtrapolator1D(
             new ProductPiecewisePolynomialInterpolator1D(
                 INTERP_SENSE[i], new double[] {0.0}, new double[] {0.0}));
     Interpolator1DDataBundle data = extrap1D.getDataBundle(xValues, yValues);
     double eps = 1.0e-5;
     InterpolatorTestUtil.assertRelative(
         "closeToZeroTest", extrap1D.interpolate(data, eps), extrap1D.interpolate(data, 0.0), eps);
     InterpolatorTestUtil.assertRelative(
         "closeToZeroTest",
         extrap1D.firstDerivative(data, eps),
         extrap1D.firstDerivative(data, 0.0),
         eps);
   }
 }
  /**
   * No clamped points added. checking agreement with the extrapolation done by the underlying
   * interpolation
   */
  @Test
  public void notClampedTest() {
    double[][] xValuesSet =
        new double[][] {
          {-5.0, -1.4, 3.2, 3.5, 7.6}, {1., 2., 4.5, 12.1, 14.2}, {-5.2, -3.4, -3.2, -0.9, -0.2}
        };
    double[][] yValuesSet =
        new double[][] {
          {-2.2, 1.1, 1.9, 2.3, -0.1}, {3.4, 5.2, 4.3, 1.1, 0.2}, {1.4, 2.2, 4.1, 1.9, 0.99}
        };

    for (int k = 0; k < xValuesSet.length; ++k) {
      double[] xValues = Arrays.copyOf(xValuesSet[k], xValuesSet[k].length);
      double[] yValues = Arrays.copyOf(yValuesSet[k], yValuesSet[k].length);
      int nData = xValues.length;
      int nKeys = 100;
      double interval = (xValues[2] - xValues[0]) / (nKeys - 1.0);

      int n = INTERP_SENSE.length;
      for (int i = 0; i < n; ++i) {
        ProductPiecewisePolynomialInterpolator interp =
            new ProductPiecewisePolynomialInterpolator(INTERP_SENSE[i]);
        PiecewisePolynomialResult result = interp.interpolateWithSensitivity(xValues, yValues);
        ReciprocalExtrapolator1D extrap1D =
            new ReciprocalExtrapolator1D(
                new ProductPiecewisePolynomialInterpolator1D(INTERP_SENSE[i]));
        Interpolator1DDataBundle data = extrap1D.getDataBundle(xValues, yValues);
        InterpolatorTestUtil.assertArrayRelative("notClampedTest", xValues, data.getKeys(), EPS);
        InterpolatorTestUtil.assertArrayRelative("notClampedTest", yValues, data.getValues(), EPS);
        /* left extrapolation */
        double grad = FUNC.differentiate(result, xValues[0]).getEntry(0);
        for (int j = 1; j < nKeys; ++j) {
          double key = xValues[0] - interval * j;
          double ref = grad * (key - xValues[0]) + yValues[0] * xValues[0];
          InterpolatorTestUtil.assertRelative(
              "notClampedTest", ref / key, extrap1D.interpolate(data, key), EPS);
          double keyUp = key + DELTA;
          double keyDw = key - DELTA;
          double refDeriv =
              0.5 * (extrap1D.interpolate(data, keyUp) - extrap1D.interpolate(data, keyDw)) / DELTA;
          InterpolatorTestUtil.assertRelative(
              "notClampedTest", refDeriv, extrap1D.firstDerivative(data, key), DELTA);
          double[] refSense = new double[nData];
          for (int l = 0; l < nData; ++l) {
            double[] yValuesUp = Arrays.copyOf(yValues, nData);
            double[] yValuesDw = Arrays.copyOf(yValues, nData);
            yValuesUp[l] += DELTA;
            yValuesDw[l] -= DELTA;
            Interpolator1DDataBundle dataUp = extrap1D.getDataBundle(xValues, yValuesUp);
            Interpolator1DDataBundle dataDw = extrap1D.getDataBundle(xValues, yValuesDw);
            refSense[l] =
                0.5
                    * (extrap1D.interpolate(dataUp, key) - extrap1D.interpolate(dataDw, key))
                    / DELTA;
          }
          InterpolatorTestUtil.assertArrayRelative(
              "notClampedTest",
              extrap1D.getNodeSensitivitiesForValue(data, key),
              refSense,
              DELTA * 10.0);
        }
        /* right extrapolation */
        for (int j = 1; j < nKeys; ++j) {
          double key = xValues[nData - 1] + interval * j;
          InterpolatorTestUtil.assertRelative(
              "notClampedTest",
              FUNC.evaluate(result, key).getEntry(0) / key,
              extrap1D.interpolate(data, key),
              EPS);
          double keyUp = key + DELTA;
          double keyDw = key - DELTA;
          double refDeriv =
              0.5 * (extrap1D.interpolate(data, keyUp) - extrap1D.interpolate(data, keyDw)) / DELTA;
          InterpolatorTestUtil.assertRelative(
              "notClampedTest", refDeriv, extrap1D.firstDerivative(data, key), DELTA);
          double[] refSense = new double[nData];
          for (int l = 0; l < nData; ++l) {
            double[] yValuesUp = Arrays.copyOf(yValues, nData);
            double[] yValuesDw = Arrays.copyOf(yValues, nData);
            yValuesUp[l] += DELTA;
            yValuesDw[l] -= DELTA;
            Interpolator1DDataBundle dataUp = extrap1D.getDataBundle(xValues, yValuesUp);
            Interpolator1DDataBundle dataDw = extrap1D.getDataBundle(xValues, yValuesDw);
            refSense[l] =
                0.5
                    * (extrap1D.interpolate(dataUp, key) - extrap1D.interpolate(dataDw, key))
                    / DELTA;
          }
          InterpolatorTestUtil.assertArrayRelative(
              "notClampedTest",
              extrap1D.getNodeSensitivitiesForValue(data, key),
              refSense,
              DELTA * 10.0);
        }
      }
    }
  }