Real Gaussian1dSmileSection::optionPrice(Rate strike, Option::Type type,
                                         Real discount) const {

    if (swapIndex_ != NULL) {
        Swaption s = MakeSwaption(swapIndex_, fixingDate_, strike)
                         .withUnderlyingType(type == Option::Call
                                                 ? VanillaSwap::Payer
                                                 : VanillaSwap::Receiver)
                         .withPricingEngine(engine_);
        Real tmp = s.NPV();
        return tmp / annuity_ * discount;
    } else {
        CapFloor c =
            MakeCapFloor(type == Option::Call ? CapFloor::Cap : CapFloor::Floor,
                         iborIndex_->tenor(), iborIndex_, strike, 0 * Days)
                .withEffectiveDate(fixingDate_, false)
                .withPricingEngine(engine_);
        Real tmp = c.NPV();
        return tmp / annuity_ * discount;
    }
}
Gaussian1dSmileSection::Gaussian1dSmileSection(
    const Date &fixingDate, const boost::shared_ptr<IborIndex> &iborIndex,
    const boost::shared_ptr<Gaussian1dModel> &model,
    const DayCounter &dc,
    const boost::shared_ptr<Gaussian1dCapFloorEngine> capEngine)
    : SmileSection(fixingDate, dc, model->termStructure()->referenceDate()),
      fixingDate_(fixingDate), swapIndex_(boost::shared_ptr<SwapIndex>()),
      iborIndex_(iborIndex), model_(model), engine_(capEngine) {

    atm_ = model_->forwardRate(fixingDate_, Null<Date>(), 0.0, iborIndex_);
    CapFloor c = MakeCapFloor(CapFloor::Cap, iborIndex_->tenor(), iborIndex_,
                              Null<Real>(),
                              0 * Days).withEffectiveDate(fixingDate_, false);
    annuity_ =
        iborIndex_->dayCounter().yearFraction(c.startDate(), c.maturityDate()) *
        model_->zerobond(c.maturityDate());

    if (engine_ == NULL) {
        engine_ = boost::make_shared<Gaussian1dCapFloorEngine>(
            model_, 64, 7.0, true,
            false); // use model curve as discounting curve
    }
}
void OptionletStripper2::performCalculations() const {

    //// optionletStripper data
    optionletDates_ = stripper1_->optionletFixingDates();
    optionletPaymentDates_ = stripper1_->optionletPaymentDates();
    optionletAccrualPeriods_ = stripper1_->optionletAccrualPeriods();
    optionletTimes_ = stripper1_->optionletFixingTimes();
    atmOptionletRate_ = stripper1_->atmOptionletRates();
    for (Size i=0; i<optionletTimes_.size(); ++i) {
        optionletStrikes_[i] = stripper1_->optionletStrikes(i);
        optionletVolatilities_[i] = stripper1_->optionletVolatilities(i);
    }

    // atmCapFloorTermVolCurve data
    const std::vector<Period>& optionExpiriesTenors =
        atmCapFloorTermVolCurve_->optionTenors();
    const std::vector<Time>& optionExpiriesTimes =
        atmCapFloorTermVolCurve_->optionTimes();

    for (Size j=0; j<nOptionExpiries_; ++j) {
        Volatility atmOptionVol = atmCapFloorTermVolCurve_->volatility(
                                      optionExpiriesTimes[j], 33.3333); // dummy strike
        boost::shared_ptr<BlackCapFloorEngine> engine(new
                BlackCapFloorEngine(iborIndex_->forwardingTermStructure(),
                                    atmOptionVol, dc_));
        caps_[j] = MakeCapFloor(CapFloor::Cap,
                                optionExpiriesTenors[j],
                                iborIndex_,
                                Null<Rate>(),
                                0*Days).withPricingEngine(engine);
        atmCapFloorStrikes_[j] =
            caps_[j]->atmRate(**iborIndex_->forwardingTermStructure());
        atmCapFloorPrices_[j] = caps_[j]->NPV();
    }

    spreadsVolImplied_ = spreadsVolImplied();

    StrippedOptionletAdapter adapter(stripper1_);

    Volatility unadjustedVol, adjustedVol;
    for (Size j=0; j<nOptionExpiries_; ++j) {
        for (Size i=0; i<optionletVolatilities_.size(); ++i) {
            if (i<=caps_[j]->floatingLeg().size()) {
                unadjustedVol = adapter.volatility(optionletTimes_[i],
                                                   atmCapFloorStrikes_[j]);
                adjustedVol = unadjustedVol + spreadsVolImplied_[j];

                // insert adjusted volatility
                std::vector<Rate>::const_iterator previous =
                    std::lower_bound(optionletStrikes_[i].begin(),
                                     optionletStrikes_[i].end(),
                                     atmCapFloorStrikes_[j]);
                Size insertIndex = previous - optionletStrikes_[i].begin();

                optionletStrikes_[i].insert(
                    optionletStrikes_[i].begin() + insertIndex,
                    atmCapFloorStrikes_[j]);
                optionletVolatilities_[i].insert(
                    optionletVolatilities_[i].begin() + insertIndex,
                    adjustedVol);
            }
        }
    }
}