@Override
  public MulticurveSensitivity visitSwap(
      final Swap<?, ?> swap, final MulticurveProviderInterface multicurves) {
    ArgumentChecker.notNull(multicurves, "multicurve");
    ArgumentChecker.notNull(swap, "Swap");
    // if the swap is an On compounded (ie Brazilian like), the parspread formula is not the same.
    if (swap.getSecondLeg().getNthPayment(0) instanceof CouponONCompounded
        && swap.getFirstLeg().getNthPayment(0) instanceof CouponFixedAccruedCompounding
        && swap.getFirstLeg().getNumberOfPayments() == 1) {
      // Implementation note: check if the swap is a Brazilian swap.

      final MulticurveSensitivity pvcsFirstLeg =
          swap.getFirstLeg()
              .accept(PVCSMC, multicurves)
              .getSensitivity(swap.getFirstLeg().getCurrency());
      final MulticurveSensitivity pvcsSecondLeg =
          swap.getSecondLeg()
              .accept(PVCSMC, multicurves)
              .getSensitivity(swap.getSecondLeg().getCurrency());

      final CouponFixedAccruedCompounding cpnFixed =
          (CouponFixedAccruedCompounding) swap.getFirstLeg().getNthPayment(0);
      final double pvONCompoundedLeg =
          swap.getSecondLeg()
              .accept(PVMC, multicurves)
              .getAmount(swap.getSecondLeg().getCurrency());
      final double discountFactor =
          multicurves.getDiscountFactor(
              swap.getFirstLeg().getCurrency(), cpnFixed.getPaymentTime());
      final double paymentYearFraction = cpnFixed.getPaymentYearFraction();

      final double notional =
          ((CouponONCompounded) swap.getSecondLeg().getNthPayment(0)).getNotional();
      final double intermediateVariable =
          (1 / paymentYearFraction)
              * Math.pow(pvONCompoundedLeg / discountFactor / notional, 1 / paymentYearFraction - 1)
              / (discountFactor * notional);
      final MulticurveSensitivity modifiedpvcsFirstLeg =
          pvcsFirstLeg.multipliedBy(pvONCompoundedLeg * intermediateVariable / discountFactor);
      final MulticurveSensitivity modifiedpvcsSecondLeg =
          pvcsSecondLeg.multipliedBy(-intermediateVariable);

      return modifiedpvcsFirstLeg.plus(modifiedpvcsSecondLeg);
    }
    final Currency ccy1 = swap.getFirstLeg().getCurrency();
    final MultipleCurrencyMulticurveSensitivity pvcs = swap.accept(PVCSMC, multicurves);
    final MulticurveSensitivity pvcs1 =
        pvcs.converted(ccy1, multicurves.getFxRates()).getSensitivity(ccy1);
    final MulticurveSensitivity pvmqscs = swap.getFirstLeg().accept(PVMQSCSMC, multicurves);
    final double pvmqs = swap.getFirstLeg().accept(PVMQSMC, multicurves);
    final double pv =
        multicurves.getFxRates().convert(swap.accept(PVMC, multicurves), ccy1).getAmount();
    // Implementation note: Total pv in currency 1.
    return pvcs1.multipliedBy(-1.0 / pvmqs).plus(pvmqscs.multipliedBy(pv / (pvmqs * pvmqs)));
  }
 @Test
 /** Tests long/short parity. */
 public void presentValueCurveSensitivityLongShortParityExplicit() {
   final MultipleCurrencyMulticurveSensitivity pvhwsLong =
       METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final MultipleCurrencyMulticurveSensitivity pvhwsShort =
       METHOD_HW.presentValueCurveSensitivity(SWAPTION_SHORT_PAYER, HW_MULTICURVES);
   AssertSensivityObjects.assertEquals(
       "Swaption physical - Hull-White - presentValueCurveSensitivity - long/short parity",
       pvhwsLong,
       pvhwsShort.multipliedBy(-1.0),
       TOLERANCE_PV_DELTA);
 }
 @Test
 /** Tests payer/receiver/swap parity. */
 public void presentValueCurveSensitivityPayerReceiverParityExplicit() {
   final MultipleCurrencyMulticurveSensitivity pvhwsReceiverLong =
       METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_RECEIVER, HW_MULTICURVES);
   final MultipleCurrencyMulticurveSensitivity pvhwsPayerShort =
       METHOD_HW.presentValueCurveSensitivity(SWAPTION_SHORT_PAYER, HW_MULTICURVES);
   final MultipleCurrencyMulticurveSensitivity pvSwap = SWAP_RECEIVER.accept(PVCSDC, MULTICURVES);
   AssertSensivityObjects.assertEquals(
       "Swaption physical - Hull-White - presentValueCurveSensitivity - payer/receiver/swap parity",
       pvSwap.cleaned(TOLERANCE_PV_DELTA),
       pvhwsReceiverLong.plus(pvhwsPayerShort).cleaned(TOLERANCE_PV_DELTA),
       TOLERANCE_PV_DELTA);
 }
 @Test
 public void presentValueCurveSensitivityDiscountingCalculator() {
   final MultipleCurrencyMulticurveSensitivity pvcsSwap =
       SWAP_MULTI_LEG.accept(PVCSDC, MULTICURVES);
   MultipleCurrencyMulticurveSensitivity pvcsLegs =
       SWAP_MULTI_LEG.getLegs()[0].accept(PVCSDC, MULTICURVES);
   for (int loopleg = 1; loopleg < NB_LEGS; loopleg++) {
     pvcsLegs = pvcsLegs.plus(SWAP_MULTI_LEG.getLegs()[loopleg].accept(PVCSDC, MULTICURVES));
   }
   AssertSensitivityObjects.assertEquals(
       "SwapMultileg: presentValueCurveSensitivityDiscountingCalculator",
       pvcsLegs,
       pvcsSwap,
       TOLERANCE_PV_DELTA);
 }
  @Test(enabled = false)
  /** Tests of performance. "enabled = false" for the standard testing. */
  public void performanceCurveSensitivity() {
    long startTime, endTime;
    final int nbTest = 25;
    MultipleCurrencyAmount pvMC = MultipleCurrencyAmount.of(EUR, 0.0);
    final MultipleCurrencyMulticurveSensitivity pvcsExplicit =
        METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    MultipleCurrencyMulticurveSensitivity pvcsMC = pvcsExplicit;
    final HullWhiteMonteCarloMethod methodMC =
        new HullWhiteMonteCarloMethod(
            new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH);

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvMC = METHOD_HW_MONTECARLO.presentValue(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " swaption Hull-White Monte Carlo method ("
            + NB_PATH
            + " paths): "
            + (endTime - startTime)
            + " ms / price:"
            + pvMC.toString());
    // Performance note: HW approximation: 03-Dec-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 250
    // ms for 25 swaptions (12500 paths).
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvcsMC = methodMC.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " curve sensitivity swaption Hull-White MC method: ("
            + NB_PATH
            + " paths) "
            + (endTime - startTime)
            + " ms / risk:"
            + pvcsMC.toString());
    // Performance note: curve sensitivity (40): 03-Dec-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 600 ms for 25 swaptions (12500 paths).

  }
 /**
  * Compute the present value sensitivity to rates of a bond future by discounting.
  *
  * @param future The future.
  * @param issuerMulticurves The issuer and multi-curves provider.
  * @return The present value rate sensitivity.
  */
 public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(
     final BondFuture future, final IssuerProviderInterface issuerMulticurves) {
   Currency ccy = future.getCurrency();
   final MulticurveSensitivity priceSensitivity = priceCurveSensitivity(future, issuerMulticurves);
   final MultipleCurrencyMulticurveSensitivity transactionSensitivity =
       MultipleCurrencyMulticurveSensitivity.of(
           ccy, priceSensitivity.multipliedBy(future.getNotional()));
   return transactionSensitivity;
 }
 /**
  * Compute the present value sensitivity to rates of a Ibor compounded coupon by discounting.
  *
  * @param coupon The coupon.
  * @param multicurve The multi-curve provider.
  * @return The present value sensitivity.
  */
 public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(
     final CouponIborCompounding coupon, final MulticurveProviderInterface multicurve) {
   ArgumentChecker.notNull(coupon, "Coupon");
   ArgumentChecker.notNull(multicurve, "Multi-curves provider");
   final int nbSubPeriod = coupon.getFixingTimes().length;
   double notionalAccrued = coupon.getNotionalAccrued();
   final double[] forward = new double[nbSubPeriod];
   final double[] ratioForward = new double[nbSubPeriod];
   for (int loopsub = 0; loopsub < nbSubPeriod; loopsub++) {
     forward[loopsub] =
         multicurve.getForwardRate(
             coupon.getIndex(),
             coupon.getFixingPeriodStartTimes()[loopsub],
             coupon.getFixingPeriodEndTimes()[loopsub],
             coupon.getFixingPeriodAccrualFactors()[loopsub]);
     ratioForward[loopsub] = 1.0 + coupon.getPaymentAccrualFactors()[loopsub] * forward[loopsub];
     notionalAccrued *= ratioForward[loopsub];
   }
   final double dfPayment =
       multicurve.getDiscountFactor(coupon.getCurrency(), coupon.getPaymentTime());
   // Backward sweep
   final double pvBar = 1.0;
   final double dfPaymentBar = (notionalAccrued - coupon.getNotional()) * pvBar;
   final double notionalAccruedBar = dfPayment * pvBar;
   final double[] ratioForwardBar = new double[nbSubPeriod];
   final double[] forwardBar = new double[nbSubPeriod];
   for (int loopsub = 0; loopsub < nbSubPeriod; loopsub++) {
     ratioForwardBar[loopsub] = notionalAccrued / ratioForward[loopsub] * notionalAccruedBar;
     forwardBar[loopsub] = coupon.getPaymentAccrualFactors()[loopsub] * ratioForwardBar[loopsub];
   }
   final Map<String, List<DoublesPair>> mapDsc = new HashMap<>();
   final List<DoublesPair> listDiscounting = new ArrayList<>();
   listDiscounting.add(
       new DoublesPair(
           coupon.getPaymentTime(), -coupon.getPaymentTime() * dfPayment * dfPaymentBar));
   mapDsc.put(multicurve.getName(coupon.getCurrency()), listDiscounting);
   final Map<String, List<ForwardSensitivity>> mapFwd = new HashMap<>();
   final List<ForwardSensitivity> listForward = new ArrayList<>();
   for (int loopsub = 0; loopsub < nbSubPeriod; loopsub++) {
     listForward.add(
         new ForwardSensitivity(
             coupon.getFixingPeriodStartTimes()[loopsub],
             coupon.getFixingPeriodEndTimes()[loopsub],
             coupon.getFixingPeriodAccrualFactors()[loopsub],
             forwardBar[loopsub]));
   }
   mapFwd.put(multicurve.getName(coupon.getIndex()), listForward);
   return MultipleCurrencyMulticurveSensitivity.of(
       coupon.getCurrency(), MulticurveSensitivity.of(mapDsc, mapFwd));
 }
 /**
  * Computes the present value curve sensitivity of a fixed payment by discounting.
  *
  * @param payment The fixed payment.
  * @param multicurves The multi-curve provider.
  * @return The sensitivity.
  */
 public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(
     final PaymentFixed payment, final MulticurveProviderInterface multicurves) {
   final double time = payment.getPaymentTime();
   final DoublesPair s =
       DoublesPair.of(
           time,
           -time
               * payment.getAmount()
               * multicurves.getDiscountFactor(payment.getCurrency(), time));
   final List<DoublesPair> list = new ArrayList<>();
   list.add(s);
   final Map<String, List<DoublesPair>> result = new HashMap<>();
   result.put(multicurves.getName(payment.getCurrency()), list);
   return MultipleCurrencyMulticurveSensitivity.of(
       payment.getCurrency(), MulticurveSensitivity.ofYieldDiscounting(result));
 }
  @Test(enabled = false)
  /** Tests of performance. "enabled = false" for the standard testing. */
  public void performance() {
    long startTime, endTime;
    final int nbTest = 1000;
    MultipleCurrencyAmount pvPayerLongExplicit = MultipleCurrencyAmount.of(EUR, 0.0);
    MultipleCurrencyAmount pvPayerLongIntegration = MultipleCurrencyAmount.of(EUR, 0.0);
    MultipleCurrencyAmount pvPayerLongApproximation = MultipleCurrencyAmount.of(EUR, 0.0);
    @SuppressWarnings("unused")
    MultipleCurrencyAmount pvPayerLongMC = MultipleCurrencyAmount.of(EUR, 0.0);
    double[] pvhws =
        METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    MultipleCurrencyMulticurveSensitivity pvcs =
        METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongExplicit = METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest + " pv swaption Hull-White explicit method: " + (endTime - startTime) + " ms");
    // Performance note: HW price: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 380 ms for
    // 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " HW sensitivity swaption Hull-White explicit method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW sensitivity (3): 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon:
    // 430 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvcs = METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " curve sensitivity swaption Hull-White explicit method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: curve sensitivity (40): 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 855 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
      pvcs = METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
      pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " price/delta/vega swaption Hull-White explicit method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: present value/delta/vega: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 1730 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongIntegration =
          METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " swaption Hull-White numerical integration method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW numerical integration: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 1700 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongApproximation =
          METHOD_HW_APPROXIMATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest + " swaption Hull-White approximation method: " + (endTime - startTime) + " ms");
    // Performance note: HW approximation: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 250
    // ms for 10000 swaptions.

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongMC = METHOD_HW_MONTECARLO.presentValue(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " swaption Hull-White Monte Carlo method ("
            + NB_PATH
            + " paths): "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW approximation: 18-Aug-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 9200
    // ms for 1000 swaptions (12500 paths).

    final double difference =
        pvPayerLongExplicit.getAmount(EUR) - pvPayerLongIntegration.getAmount(EUR);
    final double difference2 =
        pvPayerLongExplicit.getAmount(EUR) - pvPayerLongApproximation.getAmount(EUR);
    //      double difference3 = pvPayerLongExplicit.getAmount(CUR) - pvPayerLongMC.getAmount(CUR);
    System.out.println("Difference explicit-integration: " + difference);
    System.out.println("Difference explicit-approximation: " + difference2);
    //      System.out.println("Difference explicit-Monte Carlo: " + difference3);
    System.out.println("Curve sensitivity: " + pvcs.toString());
    System.out.println("HW sensitivity: " + Arrays.toString(pvhws));
  }
  /**
   * Computes the pv sensitivity of an Ibor cap/floor in arrears
   *
   * @param cap The cap/floor
   * @param curves The curves
   * @return The sensitivity
   */
  public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(
      final CapFloorIbor cap, final MulticurveProviderInterface curves) {
    ArgumentChecker.notNull(cap, "The cap/floor shoud not be null");
    ArgumentChecker.notNull(curves, "curves");
    final Currency ccy = cap.getCurrency();
    // Construct a "standard" CapFloorIbor whose paymentTime is set to be fixingPeriodEndTime
    CapFloorIbor capStandard =
        new CapFloorIbor(
            cap.getCurrency(),
            cap.getFixingPeriodEndTime(),
            cap.getPaymentYearFraction(),
            cap.getNotional(),
            cap.getFixingTime(),
            cap.getIndex(),
            cap.getFixingPeriodStartTime(),
            cap.getFixingPeriodEndTime(),
            cap.getFixingAccrualFactor(),
            cap.getStrike(),
            cap.isCap());
    final double forward =
        curves.getSimplyCompoundForwardRate(
            cap.getIndex(),
            cap.getFixingPeriodStartTime(),
            cap.getFixingPeriodEndTime(),
            cap.getFixingAccrualFactor());
    final double beta =
        (1.0 + cap.getFixingAccrualFactor() * forward)
            * curves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime())
            / curves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime());

    double df = curves.getDiscountFactor(capStandard.getCurrency(), capStandard.getPaymentTime());
    double strikePart =
        (1.0 + cap.getFixingAccrualFactor() * capStandard.getStrike())
            * presentValueStandard(
                forward,
                capStandard.getStrike(),
                capStandard.getFixingTime(),
                capStandard.isCap(),
                df,
                capStandard.getNotional(),
                capStandard.getPaymentYearFraction());
    double strikePartDelta =
        (1.0 + cap.getFixingAccrualFactor() * capStandard.getStrike())
            * presentValueDeltaStandard(
                forward,
                capStandard.getStrike(),
                capStandard.getFixingTime(),
                capStandard.isCap(),
                df,
                capStandard.getNotional(),
                capStandard.getPaymentYearFraction());

    final InArrearsIntegrant integrant = new InArrearsIntegrant(capStandard, curves);
    double integralPart;
    double upper = 0.0;
    try {
      if (cap.isCap()) {
        double atmVol = _smileFunction.getVolatility(forward);
        upper = forward * Math.exp(6.0 * atmVol * Math.sqrt(cap.getFixingTime()));
        double strike = cap.getStrike();
        integralPart = INTEGRATOR.integrate(integrant, strike, upper);
        double reminder = integrant.evaluate(upper) * upper;
        double error = reminder / integralPart;

        int count = 0;
        while (Math.abs(error) > REL_ERROR && count < MAX_COUNT) {
          integralPart += INTEGRATOR.integrate(integrant, upper, 2.0 * upper);
          upper *= 2.0;
          // The increase of integralPart in the next loop is bounded by reminder
          reminder = integrant.evaluate(upper) * upper;
          error = reminder / integralPart;
          ++count;
          if (count == MAX_COUNT) {
            LOGGER.info(
                "Maximum iteration count, "
                    + MAX_COUNT
                    + ", has been reached. Relative error is greater than "
                    + REL_ERROR);
          }
        }
      } else {
        double strike = cap.getStrike();
        integralPart = INTEGRATOR.integrate(integrant, REL_TOL * strike, strike);
      }
    } catch (final Exception e) {
      throw new MathException(e);
    }
    integralPart *= 2.0 * cap.getFixingAccrualFactor();
    double pv = (strikePart + integralPart) / beta;

    double betaFwd =
        cap.getFixingAccrualFactor()
            * curves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime())
            / curves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime());
    double betaDscStart =
        (1.0 + cap.getFixingAccrualFactor() * forward)
            * curves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime())
            * cap.getFixingPeriodStartTime()
            / curves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime());
    double betaDscEnd =
        -(1.0 + cap.getFixingAccrualFactor() * forward)
            * curves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime())
            * cap.getFixingPeriodEndTime()
            / curves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime());

    List<DoublesPair> listDiscounting = new ArrayList<>();
    double strikePartDsc = -capStandard.getPaymentTime() * strikePart;
    double integralPartDsc = -capStandard.getPaymentTime() * integralPart;
    listDiscounting.add(
        DoublesPair.of(capStandard.getPaymentTime(), (strikePartDsc + integralPartDsc) / beta));
    listDiscounting.add(DoublesPair.of(cap.getFixingPeriodStartTime(), -pv * betaDscStart / beta));
    listDiscounting.add(DoublesPair.of(cap.getFixingPeriodEndTime(), -pv * betaDscEnd / beta));
    Map<String, List<DoublesPair>> mapDsc = new HashMap<>();
    mapDsc.put(curves.getName(capStandard.getCurrency()), listDiscounting);

    final List<ForwardSensitivity> listForward = new ArrayList<>();
    double strikePartFwd = strikePartDelta;
    double integralPartFwd = 0.0;
    final InArrearsDeltaIntegrant integrantFwd = new InArrearsDeltaIntegrant(capStandard, curves);
    try {
      if (cap.isCap()) {
        double strike = cap.getStrike();
        integralPartFwd = INTEGRATOR.integrate(integrantFwd, strike, upper);
      } else {
        double strike = cap.getStrike();
        integralPartFwd = INTEGRATOR.integrate(integrantFwd, REL_TOL * strike, strike);
      }
    } catch (final Exception e) {
      throw new MathException(e);
    }
    integralPartFwd *= 2.0 * cap.getFixingAccrualFactor();
    listForward.add(
        new SimplyCompoundedForwardSensitivity(
            capStandard.getFixingPeriodStartTime(),
            capStandard.getFixingPeriodEndTime(),
            capStandard.getFixingAccrualFactor(),
            (strikePartFwd + integralPartFwd - pv * betaFwd) / beta));
    Map<String, List<ForwardSensitivity>> mapFwd = new HashMap<>();
    mapFwd.put(curves.getName(capStandard.getIndex()), listForward);

    return MultipleCurrencyMulticurveSensitivity.of(
        cap.getCurrency(), MulticurveSensitivity.of(mapDsc, mapFwd));
  }