inline SimpleFluid2pWrappingProps::SimpleFluid2pWrappingProps(const Opm::IncompPropertiesInterface& props)
     : props_(props),
       smin_(props.numCells()*props.numPhases()),
       smax_(props.numCells()*props.numPhases())
 {
     if (props.numPhases() != 2) {
         THROW("SimpleFluid2pWrapper requires 2 phases.");
     }
     const int num_cells = props.numCells();
     std::vector<int> cells(num_cells);
     for (int c = 0; c < num_cells; ++c) {
         cells[c] = c;
     }
     props.satRange(num_cells, &cells[0], &smin_[0], &smax_[0]);
 }
    TransportSolverTwophaseReorder::TransportSolverTwophaseReorder(const UnstructuredGrid& grid,
                                                                   const Opm::IncompPropertiesInterface& props,
                                                                   const double* gravity,
                                                                   const double tol,
                                                                   const int maxit)
        : grid_(grid),
          props_(props),
          tol_(tol),
          maxit_(maxit),
          darcyflux_(0),
          source_(0),
          dt_(0.0),
          saturation_(grid.number_of_cells, -1.0),
          fractionalflow_(grid.number_of_cells, -1.0),
          reorder_iterations_(grid.number_of_cells, 0),
          mob_(2*grid.number_of_cells, -1.0)
#ifdef EXPERIMENT_GAUSS_SEIDEL
        , ia_upw_(grid.number_of_cells + 1, -1),
          ja_upw_(grid.number_of_faces, -1),
          ia_downw_(grid.number_of_cells + 1, -1),
          ja_downw_(grid.number_of_faces, -1)
#endif
    {
        if (props.numPhases() != 2) {
            OPM_THROW(std::runtime_error, "Property object must have 2 phases");
        }
        visc_ = props.viscosity();
        int num_cells = props.numCells();
        smin_.resize(props.numPhases()*num_cells);
        smax_.resize(props.numPhases()*num_cells);
        std::vector<int> cells(num_cells);
        for (int i = 0; i < num_cells; ++i) {
            cells[i] = i;
        }
        props.satRange(props.numCells(), &cells[0], &smin_[0], &smax_[0]);
        if (gravity) {
            initGravity(gravity);
            initColumns();
        }
    }
std::vector<ADB>
phaseMobility(const Opm::IncompPropertiesInterface& props,
              const std::vector<int>& cells,
              const typename ADB::V& sw)
{
    typedef Eigen::Array<double, Eigen::Dynamic, 2, Eigen::RowMajor> TwoCol;
    typedef Eigen::Array<double, Eigen::Dynamic, 4, Eigen::RowMajor> FourCol;
    typedef Eigen::SparseMatrix<double> S;
    typedef typename ADB::V V;
    typedef typename ADB::M M;
    const int nc = props.numCells();
    TwoCol s(nc, 2);
    s.leftCols<1>() = sw;
    s.rightCols<1>() = 1.0 - s.leftCols<1>();
    TwoCol kr(nc, 2);
    FourCol dkr(nc, 4);
    props.relperm(nc, s.data(), cells.data(), kr.data(), dkr.data());
    V krw = kr.leftCols<1>();
    V kro = kr.rightCols<1>();
    V dkrw = dkr.leftCols<1>();  // Left column is top-left of dkr/ds 2x2 matrix.
    V dkro = -dkr.rightCols<1>(); // Right column is bottom-right of dkr/ds 2x2 matrix.
    S krwjac(nc,nc);
    S krojac(nc,nc);
    auto sizes = Eigen::ArrayXi::Ones(nc);
    krwjac.reserve(sizes);
    krojac.reserve(sizes);
    for (int c = 0; c < nc; ++c) {
        krwjac.insert(c,c) = dkrw(c);
        krojac.insert(c,c) = dkro(c);
    }
    const double* mu = props.viscosity();
    std::vector<M> dmw = { M(krwjac)/mu[0] };
    std::vector<M> dmo = { M(krojac)/mu[1] };

    std::vector<ADB> pmobc = { ADB::function(krw / mu[0], std::move(dmw)) ,
                               ADB::function(kro / mu[1], std::move(dmo)) };
    return pmobc;
}