@Test
  public void sensitivityTest() {
    final VolatilitySurfaceProvider vsPro =
        new BasisSplineVolatilitySurfaceProvider(0.0, 0.15, 10, 3, 0.0, 10.0, 7, 2);

    final DoubleMatrix1D w = new DoubleMatrix1D(vsPro.getNumModelParameters());
    for (int i = 0; i < w.getNumberOfElements(); i++) {
      w.getData()[i] = RANDOM.nextDouble();
    }

    final VolatilitySurface volSurf = vsPro.getVolSurface(w);
    final Surface<Double, Double, DoubleMatrix1D> senseSurf =
        vsPro.getParameterSensitivitySurface(w);
    final Surface<Double, Double, Pair<Double, DoubleMatrix1D>> volAndSenseSurf =
        vsPro.getVolAndParameterSensitivitySurface(w);

    final int nSamples = 20;
    final DoublesPair[] points = new DoublesPair[nSamples];
    for (int i = 0; i < nSamples; i++) {
      final double t = 10.0 * RANDOM.nextDouble();
      final double k = 0.15 * RANDOM.nextDouble();
      points[i] = DoublesPair.of(t, k);

      final double vol = volSurf.getVolatility(points[i]);
      final DoubleMatrix1D sense = senseSurf.getZValue(points[i].toPair());
      final Pair<Double, DoubleMatrix1D> volAndSense =
          volAndSenseSurf.getZValue(points[i].toPair());
      assertEquals(vol, volAndSense.getFirst(), 1e-15);
      AssertMatrix.assertEqualsVectors(sense, volAndSense.getSecond(), 1e-15);
    }

    // create a DiscreteVolatilityFunctionProvider in order to compute the Jacobian for a (random)
    // set the points
    final DiscreteVolatilityFunctionProvider dvfp =
        new DiscreteVolatilityFunctionProviderFromVolSurface(vsPro);
    final DiscreteVolatilityFunction func = dvfp.from(points);
    final DoubleMatrix2D jac = func.calculateJacobian(w);
    final DoubleMatrix2D jacFD = func.calculateJacobianViaFD(w);
    AssertMatrix.assertEqualsMatrix(jacFD, jac, 1e-10);
  }