void BlackCapFloorEngine::calculate() const {
        Real value = 0.0;
        Real vega = 0.0;
        Size optionlets = arguments_.startDates.size();
        std::vector<Real> values(optionlets, 0.0);
        std::vector<Real> vegas(optionlets, 0.0);
        std::vector<Real> stdDevs(optionlets, 0.0);
        CapFloor::Type type = arguments_.type;
        Date today = vol_->referenceDate();
        Date settlement = discountCurve_->referenceDate();

        for (Size i=0; i<optionlets; ++i) {
            Date paymentDate = arguments_.endDates[i];
            // handling of settlementDate, npvDate and includeSettlementFlows
            // should be implemented.
            // For the time being just discard expired caplets
            if (paymentDate > settlement) {
                DiscountFactor d = arguments_.nominals[i] *
                                   arguments_.gearings[i] *
                                   discountCurve_->discount(paymentDate) *
                                   arguments_.accrualTimes[i];

                Rate forward = arguments_.forwards[i];

                Date fixingDate = arguments_.fixingDates[i];
                Time sqrtTime = 0.0;
                if (fixingDate > today)
                    sqrtTime = std::sqrt(vol_->timeFromReference(fixingDate));

                if (type == CapFloor::Cap || type == CapFloor::Collar) {
                    Rate strike = arguments_.capRates[i];
                    if (sqrtTime>0.0) {
                        stdDevs[i] = std::sqrt(vol_->blackVariance(fixingDate,
                                                                   strike));
                        vegas[i] = blackFormulaStdDevDerivative(strike,
                            forward, stdDevs[i], d, displacement_) * sqrtTime;
                    }
                    // include caplets with past fixing date
                    values[i] = blackFormula(Option::Call,
                        strike, forward, stdDevs[i], d, displacement_);
                }
                if (type == CapFloor::Floor || type == CapFloor::Collar) {
                    Rate strike = arguments_.floorRates[i];
                    Real floorletVega = 0.0;
                    if (sqrtTime>0.0) {
                        stdDevs[i] = std::sqrt(vol_->blackVariance(fixingDate,
                                                                   strike));
                        floorletVega = blackFormulaStdDevDerivative(strike,
                            forward, stdDevs[i], d, displacement_) * sqrtTime;
                    }
                    Real floorlet = blackFormula(Option::Put,
                        strike, forward, stdDevs[i], d, displacement_);
                    if (type == CapFloor::Floor) {
                        values[i] = floorlet;
                        vegas[i] = floorletVega;
                    } else {
                        // a collar is long a cap and short a floor
                        values[i] -= floorlet;
                        vegas[i] -= floorletVega;
                    }
                }
                value += values[i];
                vega += vegas[i];
            }
        }
        results_.value = value;
        results_.additionalResults["vega"] = vega;

        results_.additionalResults["optionletsPrice"] = values;
        results_.additionalResults["optionletsVega"] = vegas;
        results_.additionalResults["optionletsAtmForward"] = arguments_.forwards;
        if (type != CapFloor::Collar)
            results_.additionalResults["optionletsStdDev"] = stdDevs;
    }
    void YoYInflationCapFloorEngine::calculate() const {

        // copy black version then adapt to others

        Real value = 0.0;
        Size optionlets = arguments_.startDates.size();
        std::vector<Real> values(optionlets, 0.0);
        std::vector<Real> stdDevs(optionlets, 0.0);
        std::vector<Real> forwards(optionlets, 0.0);
        YoYInflationCapFloor::Type type = arguments_.type;

        Handle<YoYInflationTermStructure> yoyTS
        = index()->yoyInflationTermStructure();
        Handle<YieldTermStructure> nominalTS =
            !nominalTermStructure_.empty() ?
            nominalTermStructure_ :
            yoyTS->nominalTermStructure();
        Date settlement = nominalTS->referenceDate();

        for (Size i=0; i<optionlets; ++i) {
            Date paymentDate = arguments_.payDates[i];
            if (paymentDate > settlement) { // discard expired caplets
                DiscountFactor d = arguments_.nominals[i] *
                    arguments_.gearings[i] *
                    nominalTS->discount(paymentDate) *
                arguments_.accrualTimes[i];

                // We explicitly have the index and assume that
                // the fixing is natural, i.e. no convexity adjustment.
                // If that was required then we would also need
                // nominal vols in the pricing engine, i.e. a different engine.
                // This also means that we do not need the coupon to have
                // a pricing engine to return the swaplet rate and then
                // the adjusted fixing in the instrument.
                forwards[i] = yoyTS->yoyRate(arguments_.fixingDates[i],Period(0,Days));
                Rate forward = forwards[i];

                Date fixingDate = arguments_.fixingDates[i];
                Time sqrtTime = 0.0;
                if (fixingDate > volatility_->baseDate()){
                    sqrtTime = std::sqrt(
                        volatility_->timeFromBase(fixingDate));
                }

                if (type == YoYInflationCapFloor::Cap || type == YoYInflationCapFloor::Collar) {
                    Rate strike = arguments_.capRates[i];
                    if (sqrtTime>0.0) {
                        stdDevs[i] = std::sqrt(
                            volatility_->totalVariance(fixingDate, strike, Period(0,Days)));

                    }

                    // sttDev=0 for already-fixed dates so everything on forward
                    values[i] = optionletImpl(Option::Call, strike,
                                              forward, stdDevs[i], d);
                }
                if (type == YoYInflationCapFloor::Floor || type == YoYInflationCapFloor::Collar) {
                    Rate strike = arguments_.floorRates[i];
                    if (sqrtTime>0.0) {
                        stdDevs[i] = std::sqrt(
                            volatility_->totalVariance(fixingDate, strike, Period(0,Days)));
                    }
                    Real floorlet = optionletImpl(Option::Put, strike,
                                                  forward, stdDevs[i], d);
                    if (type == YoYInflationCapFloor::Floor) {
                        values[i] = floorlet;
                    } else {
                        // a collar is long a cap and short a floor
                        values[i] -= floorlet;
                    }

                }
                value += values[i];
            }
        }
        results_.value = value;

        results_.additionalResults["optionletsPrice"] = values;
        results_.additionalResults["optionletsAtmForward"] = forwards;
        if (type != YoYInflationCapFloor::Collar)
            results_.additionalResults["optionletsStdDev"] = stdDevs;
    }