/*!
          \brief Apply the preconditoner.

          \copydoc Preconditioner::apply(X&,const Y&)
        */
        virtual void apply (X& v, const Y& d)
        {
            // Extract part of d corresponding to elliptic part.
            // Note: Assumes that the elliptic part comes first.
            std::copy_n(d.begin(), de_.size(), de_.begin());

            // Solve elliptic part, extend solution to full.
            // reset result
            ve_ = 0;
            solveElliptic( ve_, de_ );

            //reset return value
            v = 0.0;
            // Again assuming that the elliptic part comes first.
            std::copy(ve_.begin(), ve_.end(), v.begin());

            // Subtract elliptic residual from initial residual.
            // dmodified = d - A * vfull
            dmodified_ = d;
            A_.mmv(v, dmodified_);
            // A is not parallel, do communication manually.
            comm_.copyOwnerToAll(dmodified_, dmodified_);

            // Apply Preconditioner for whole system (relax will be applied already)
            pre_->apply( vilu_, dmodified_);

            // don't apply relaxation if relax_ == 1
            if( std::abs( param_.cpr_relax_ - 1.0 ) < 1e-12 ) {
                v += vilu_;
            }
            else {
                v *= param_.cpr_relax_;
                v += vilu_;
            }
        }
        /*!
          \brief Apply the preconditoner.

          \copydoc Preconditioner::apply(X&,const Y&)
        */
        virtual void apply (X& v, const Y& d)
        {
            // Extract part of d corresponding to elliptic part.
            Y de(Ae_.N());
            // Note: Assumes that the elliptic part comes first.
            std::copy_n(d.begin(), Ae_.N(), de.begin());

            // Solve elliptic part, extend solution to full.
            Y ve = solveElliptic(de);
            Y vfull(ILU_.N());
            vfull = 0.0;
            // Again assuming that the elliptic part comes first.
            std::copy(ve.begin(), ve.end(), vfull.begin());

            // Subtract elliptic residual from initial residual.
            // dmodified = d - A * vfull
            Y dmodified = d;
            A_.mmv(vfull, dmodified);

            // Apply ILU0.
            Y vilu(ILU_.N());
            Dune::bilu_backsolve(ILU_, vilu, dmodified);
            v = vfull;
            v += vilu;
            v *= relax_;
        }