int
main(int argc, char* argv[])
{
    const Opm::parameter::ParameterGroup param(argc, argv, false);
    const Opm::GridManager               gm(5, 5);

    const UnstructuredGrid*              g  = gm.c_grid();
    const int                            nc = g->number_of_cells;
    const Opm::BlackoilPropertiesBasic   oldprops(param, 2, nc);
    const Opm::BlackoilPropsAd           props(oldprops);

    typedef AutoDiff::ForwardBlock<double>      ADB;

    Wells* wells = create_wells(2, 2, 5);
    const double inj_frac[] = { 1.0, 0.0 };
    const double prod_frac[] = { 0.0, 0.0 };
    const int num_inj = 3;
    const int inj_cells[num_inj] = { 0, 1, 2 };
    const int num_prod = 2;
    const int prod_cells[num_prod] = { 20, 21 };
    const double WI[3] = { 1e-12, 1e-12, 1e-12 };
    bool ok = add_well(INJECTOR, 0.0, num_inj, inj_frac, inj_cells, WI, "Inj", wells);
    ok = ok && add_well(PRODUCER, 0.0, num_prod, prod_frac, prod_cells, WI, "Prod", wells);
    ok = ok && append_well_controls(BHP, 500.0*Opm::unit::barsa, 0, 0, wells);
    // ok = ok && append_well_controls(BHP, 200.0*Opm::unit::barsa, 0, 1, wells);
    double oildistr[2] = { 0.0, 1.0 };
    ok = ok && append_well_controls(SURFACE_RATE, 1e-3, oildistr, 1, wells);
    if (!ok) {
        THROW("Something went wrong with well init.");
    }
    set_current_control(0, 0, wells);
    set_current_control(1, 0, wells);

    double grav[] = { /*1.0*/ 0.0, 0.0 };
    Opm::DerivedGeology geo(*g, props, grav);
    Opm::LinearSolverFactory linsolver(param);
    Opm::ImpesTPFAAD ps(*g, props, geo, *wells, linsolver);

    Opm::BlackoilState state;
    initStateBasic(*g, oldprops, param, 0.0, state);
    initBlackoilSurfvol(*g, oldprops, state);
    Opm::WellState well_state;
    well_state.init(wells, state);

    ps.solve(1.0, state, well_state);

    std::cout << "Cell pressure:" << std::endl;
    std::copy(state.pressure().begin(), state.pressure().end(), std::ostream_iterator<double>(std::cout, " "));
    std::cout << std::endl;
    std::cout << "Face flux:" << std::endl;
    std::copy(state.faceflux().begin(), state.faceflux().end(), std::ostream_iterator<double>(std::cout, " "));
    std::cout << std::endl;
    std::cout << "Well bhp pressure:" << std::endl;
    std::copy(well_state.bhp().begin(), well_state.bhp().end(), std::ostream_iterator<double>(std::cout, " "));
    std::cout << std::endl;

    return 0;
}
    static void outputStateMatlab(const UnstructuredGrid& grid,
                                  const Opm::BlackoilState& state,
                                  const int step,
                                  const std::string& output_dir)
    {
        Opm::DataMap dm;
        dm["saturation"] = &state.saturation();
        dm["pressure"] = &state.pressure();
        dm["surfvolume"] = &state.surfacevol();
        std::vector<double> cell_velocity;
        Opm::estimateCellVelocity(grid, state.faceflux(), cell_velocity);
        dm["velocity"] = &cell_velocity;

        // Write data (not grid) in Matlab format
        for (Opm::DataMap::const_iterator it = dm.begin(); it != dm.end(); ++it) {
            std::ostringstream fname;
            fname << output_dir << "/" << it->first;
            boost::filesystem::path fpath = fname.str();
            try {
              create_directories(fpath);
            }
            catch (...) {
              OPM_THROW(std::runtime_error, "Creating directories failed: " << fpath);
            }
            fname << "/" << std::setw(3) << std::setfill('0') << step << ".txt";
            std::ofstream file(fname.str().c_str());
            if (!file) {
                OPM_THROW(std::runtime_error, "Failed to open " << fname.str());
            }
            file.precision(15);
            const std::vector<double>& d = *(it->second);
            std::copy(d.begin(), d.end(), std::ostream_iterator<double>(file, "\n"));
        }
    }
    static void outputStateVtk(const UnstructuredGrid& grid,
                               const Opm::BlackoilState& state,
                               const int step,
                               const std::string& output_dir)
    {
        // Write data in VTK format.
        std::ostringstream vtkfilename;
        vtkfilename << output_dir << "/vtk_files";
        boost::filesystem::path fpath(vtkfilename.str());
        try {
          create_directories(fpath);
        }
        catch (...) {
          OPM_THROW(std::runtime_error, "Creating directories failed: " << fpath);
        }
        vtkfilename << "/output-" << std::setw(3) << std::setfill('0') << step << ".vtu";
        std::ofstream vtkfile(vtkfilename.str().c_str());
        if (!vtkfile) {
            OPM_THROW(std::runtime_error, "Failed to open " << vtkfilename.str());
        }

        Opm::DataMap dm;
        dm["saturation"] = &state.saturation();
        dm["pressure"] = &state.pressure();
        std::vector<double> cell_velocity;
        Opm::estimateCellVelocity(grid, state.faceflux(), cell_velocity);
        dm["velocity"] = &cell_velocity;
        Opm::writeVtkData(grid, dm, vtkfile);
    }
    void outputStateVtk(const Dune::CpGrid& grid,
                        const Opm::BlackoilState& state,
                        const int step,
                        const std::string& output_dir)
    {
        // Write data in VTK format.
        std::ostringstream vtkfilename;
        std::ostringstream vtkpath;
        vtkpath << output_dir << "/vtk_files";
        vtkpath << "/output-" << std::setw(3) << std::setfill('0') << step;
        boost::filesystem::path fpath(vtkpath.str());
        try {
            create_directories(fpath);
        }
        catch (...) {
            OPM_THROW(std::runtime_error, "Creating directories failed: " << fpath);
        }
        vtkfilename << "output-" << std::setw(3) << std::setfill('0') << step;
#if DUNE_VERSION_NEWER(DUNE_GRID, 2, 3)
        Dune::VTKWriter<Dune::CpGrid::LeafGridView> writer(grid.leafGridView(), Dune::VTK::nonconforming);
#else
        Dune::VTKWriter<Dune::CpGrid::LeafGridView> writer(grid.leafView(), Dune::VTK::nonconforming);
#endif
        writer.addCellData(state.saturation(), "saturation", state.numPhases());
        writer.addCellData(state.pressure(), "pressure", 1);
        
        std::vector<double> cell_velocity;
        Opm::estimateCellVelocity(AutoDiffGrid::numCells(grid),
                                  AutoDiffGrid::numFaces(grid),
                                  AutoDiffGrid::beginFaceCentroids(grid),
                                  AutoDiffGrid::faceCells(grid),
                                  AutoDiffGrid::beginCellCentroids(grid),
                                  AutoDiffGrid::beginCellVolumes(grid),
                                  AutoDiffGrid::dimensions(grid),
                                  state.faceflux(), cell_velocity);
        writer.addCellData(cell_velocity, "velocity", Dune::CpGrid::dimension);
        writer.pwrite(vtkfilename.str(), vtkpath.str(), std::string("."), Dune::VTK::ascii);
    }