private SurfaceMetadata updateSurfaceMetadata(Set<DoublesPair> pairs) {
   SurfaceMetadata surfaceMetadata = surface.getMetadata();
   List<SurfaceParameterMetadata> sortedMetaList = new ArrayList<SurfaceParameterMetadata>();
   if (surfaceMetadata.getParameterMetadata().isPresent()) {
     List<SurfaceParameterMetadata> metaList =
         new ArrayList<SurfaceParameterMetadata>(surfaceMetadata.getParameterMetadata().get());
     for (DoublesPair pair : pairs) {
       metadataLoop:
       for (SurfaceParameterMetadata parameterMetadata : metaList) {
         ArgChecker.isTrue(
             parameterMetadata instanceof GenericVolatilitySurfaceYearFractionMetadata,
             "Surface parameter metadata must be instance of GenericVolatilitySurfaceYearFractionMetadata");
         GenericVolatilitySurfaceYearFractionMetadata casted =
             (GenericVolatilitySurfaceYearFractionMetadata) parameterMetadata;
         if (pair.getFirst() == casted.getYearFraction()
             && pair.getSecond() == casted.getStrike().getValue()) {
           sortedMetaList.add(casted);
           metaList.remove(parameterMetadata);
           break metadataLoop;
         }
       }
     }
     ArgChecker.isTrue(
         metaList.size() == 0,
         "Mismatch between surface parameter metadata list and doubles pair list");
   } else {
     for (DoublesPair pair : pairs) {
       GenericVolatilitySurfaceYearFractionMetadata parameterMetadata =
           GenericVolatilitySurfaceYearFractionMetadata.of(
               pair.getFirst(), SimpleStrike.of(pair.getSecond()));
       sortedMetaList.add(parameterMetadata);
     }
   }
   return surfaceMetadata.withParameterMetadata(sortedMetaList);
 }
 @Override
 public SurfaceCurrencyParameterSensitivity surfaceCurrencyParameterSensitivity(
     IborCapletFloorletSensitivity point) {
   ArgChecker.isTrue(
       point.getIndex().equals(index),
       "Ibor index of provider must be the same as Ibor index of point sensitivity");
   double expiry = relativeTime(point.getExpiry());
   double strike = point.getStrike();
   // copy to ImmutableMap to lock order (keySet and values used separately but must match)
   Map<DoublesPair, Double> result =
       ImmutableMap.copyOf(surface.zValueParameterSensitivity(expiry, strike));
   SurfaceCurrencyParameterSensitivity parameterSensi =
       SurfaceCurrencyParameterSensitivity.of(
           updateSurfaceMetadata(result.keySet()),
           point.getCurrency(),
           DoubleArray.copyOf(Doubles.toArray(result.values())));
   return parameterSensi.multipliedBy(point.getSensitivity());
 }
 // -------------------------------------------------------------------------
 @Override
 public double volatility(double expiry, double strike, double forward) {
   return surface.zValue(expiry, strike);
 }
 /**
  * Return the nu parameter for a pair of time to expiry and instrument tenor.
  *
  * @param expirytenor The expiry/tenor pair
  * @return The nu parameter
  */
 public double getShift(DoublesPair expirytenor) {
   return shiftSurface.zValue(expirytenor);
 }
 /**
  * Return the nu parameter for a pair of time to expiry and instrument tenor.
  *
  * @param expirytenor The expiry/tenor pair
  * @return The nu parameter
  */
 public double getNu(DoublesPair expirytenor) {
   return nuSurface.zValue(expirytenor);
 }
 /**
  * Return the rho parameter for a pair of time to expiry and instrument tenor.
  *
  * @param expirytenor The expiry/tenor pair
  * @return The rho parameter
  */
 public double getRho(DoublesPair expirytenor) {
   return rhoSurface.zValue(expirytenor);
 }
 /**
  * Return the beta parameter for a pair of time to expiry and instrument tenor.
  *
  * @param expirytenor The expiry/tenor pair
  * @return The beta parameter
  */
 public double getBeta(DoublesPair expirytenor) {
   return betaSurface.zValue(expirytenor);
 }
 /**
  * Return the alpha parameter for a pair of time to expiry and instrument tenor.
  *
  * @param expirytenor The expiry/tenor pair
  * @return The alpha parameter
  */
 public double getAlpha(DoublesPair expirytenor) {
   return alphaSurface.zValue(expirytenor);
 }