void FdSimpleExtOUJumpSwingEngine::calculate() const {

        boost::shared_ptr<SwingExercise> swingExercise(
            boost::dynamic_pointer_cast<SwingExercise>(arguments_.exercise));

        QL_REQUIRE(swingExercise, "Swing exercise supported only");

        // 1. Layout
        std::vector<Size> dim;
        dim.push_back(xGrid_);
        dim.push_back(yGrid_);
        dim.push_back(arguments_.maxExerciseRights+1);
        const boost::shared_ptr<FdmLinearOpLayout> layout(
                                            new FdmLinearOpLayout(dim));

        // 2. Mesher
        const std::vector<Time> exerciseTimes
            = swingExercise->exerciseTimes(rTS_->dayCounter(),
                                           rTS_->referenceDate());

        const Time maturity = exerciseTimes.back();
        const boost::shared_ptr<StochasticProcess1D> ouProcess(
                              process_->getExtendedOrnsteinUhlenbeckProcess());
        const boost::shared_ptr<Fdm1dMesher> xMesher(
                     new FdmSimpleProcess1dMesher(xGrid_, ouProcess,maturity));

        const boost::shared_ptr<Fdm1dMesher> yMesher(
                        new ExponentialJump1dMesher(yGrid_,
                                                    process_->beta(),
                                                    process_->jumpIntensity(),
                                                    process_->eta()));
        const boost::shared_ptr<Fdm1dMesher> exerciseMesher(
                       new Uniform1dMesher(0, arguments_.maxExerciseRights,
                                              arguments_.maxExerciseRights+1));

        std::vector<boost::shared_ptr<Fdm1dMesher> > meshers;
        meshers.push_back(xMesher);
        meshers.push_back(yMesher);
        meshers.push_back(exerciseMesher);
        const boost::shared_ptr<FdmMesher> mesher (
                                   new FdmMesherComposite(layout, meshers));

        // 3. Calculator
        boost::shared_ptr<FdmInnerValueCalculator> calculator(
                                                    new FdmZeroInnerValue());
        // 4. Step conditions
        std::list<boost::shared_ptr<StepCondition<Array> > > stepConditions;
        std::list<std::vector<Time> > stoppingTimes;

        // 4.1 Bermudan step conditions
        stoppingTimes.push_back(exerciseTimes);

        const boost::shared_ptr<StrikedTypePayoff> payoff =
            boost::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
        boost::shared_ptr<FdmInnerValueCalculator> exerciseCalculator(
                      new FdmExtOUJumpModelInnerValue(payoff, mesher, shape_));

        stepConditions.push_back(boost::shared_ptr<StepCondition<Array> >(
                new FdmSimpleSwingCondition(exerciseTimes, mesher,
                                            exerciseCalculator, 2)));

        boost::shared_ptr<FdmStepConditionComposite> conditions(
                new FdmStepConditionComposite(stoppingTimes, stepConditions));


        // 5. Boundary conditions
        const std::vector<boost::shared_ptr<FdmDirichletBoundary> > boundaries;

        // 6. set-up solver
        FdmSolverDesc solverDesc = { mesher, boundaries, conditions,
                                     calculator, maturity, tGrid_, 0 };

        const boost::shared_ptr<FdmSimple3dExtOUJumpSolver> solver(
            new FdmSimple3dExtOUJumpSolver(
                                    Handle<ExtOUWithJumpsProcess>(process_),
                                    rTS_, solverDesc, schemeDesc_));

        const Real x = process_->initialValues()[0];
        const Real y = process_->initialValues()[1];

        std::vector< std::pair<Real, Real> > exerciseValues;
        for (Size i=arguments_.minExerciseRights;
             i <= arguments_.maxExerciseRights; ++i) {
            const Real z = Real(i);
            exerciseValues.push_back(std::pair<Real, Real>(
                                       solver->valueAt(x, y, z), z));
        }
        const Real z = std::max_element(exerciseValues.begin(),
                                        exerciseValues.end())->second;

        results_.value = solver->valueAt(x, y, z);
    }
    void FdSimpleBSSwingEngine::calculate() const {

        QL_REQUIRE(arguments_.exercise->type() == Exercise::Bermudan,
                   "Bermudan exercise supported only");

        // 1. Mesher
        const boost::shared_ptr<StrikedTypePayoff> payoff =
            boost::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
        const Time maturity = process_->time(arguments_.exercise->lastDate());
        const boost::shared_ptr<Fdm1dMesher> equityMesher(
            new FdmBlackScholesMesher(xGrid_, process_,
                                      maturity, payoff->strike()));
        
        const boost::shared_ptr<Fdm1dMesher> exerciseMesher(
                 new Uniform1dMesher(0, arguments_.maxExerciseRights,
                                        arguments_.maxExerciseRights+1));
        
        const boost::shared_ptr<FdmMesher> mesher (
            new FdmMesherComposite(equityMesher, exerciseMesher));
        
        // 2. Calculator
        boost::shared_ptr<FdmInnerValueCalculator> calculator(
                                                    new FdmZeroInnerValue());
        
        // 3. Step conditions
        std::list<boost::shared_ptr<StepCondition<Array> > > stepConditions;
        std::list<std::vector<Time> > stoppingTimes;
        
        // 3.1 Bermudan step conditions
        std::vector<Time> exerciseTimes;
        for (Size i=0; i<arguments_.exercise->dates().size(); ++i) {
            Time t = process_->time(arguments_.exercise->dates()[i]);
            QL_REQUIRE(t >= 0, "exercise dates must not contain past date");
            exerciseTimes.push_back(t);
        }
        stoppingTimes.push_back(exerciseTimes);
        
        boost::shared_ptr<FdmInnerValueCalculator> exerciseCalculator(
                                    new FdmLogInnerValue(payoff, mesher, 0));

        stepConditions.push_back(boost::shared_ptr<StepCondition<Array> >(
            new FdmSimpleSwingCondition(exerciseTimes, mesher,
                                        exerciseCalculator, 1)));
        
        boost::shared_ptr<FdmStepConditionComposite> conditions(
                new FdmStepConditionComposite(stoppingTimes, stepConditions));
        
        // 4. Boundary conditions
        const FdmBoundaryConditionSet boundaries;
        
        // 5. Solver
        FdmSolverDesc solverDesc = { mesher, boundaries, conditions,
                                     calculator, maturity, tGrid_, 0 };
        boost::shared_ptr<FdmSimple2dBSSolver> solver(
                new FdmSimple2dBSSolver(
                               Handle<GeneralizedBlackScholesProcess>(process_),
                               payoff->strike(), solverDesc, schemeDesc_));
    
        const Real spot = process_->x0();
        
        std::vector< std::pair<Real, Real> > exerciseValues;
        for (Size i=arguments_.minExerciseRights;
             i <= arguments_.maxExerciseRights; ++i) {
            const Real y = std::exp(Real(i));
            exerciseValues.push_back(
                           std::pair<Real, Real>(solver->valueAt(spot, y), y));
        }
        const Real y = std::max_element(exerciseValues.begin(),
                                        exerciseValues.end())->second;

        results_.value = solver->valueAt(spot, y);
        results_.delta = solver->deltaAt(spot, y, spot*0.01);
        results_.gamma = solver->gammaAt(spot, y, spot*0.01);
        results_.theta = solver->thetaAt(spot, y);
    }