示例#1
0
int main(int argc, char** argv)
{
    // Set output precision
    int decimals = 16;

    // Process input parameters
    if (argc != 3) {
        std::cout << "Usage: mirror_grid filename.grdecl direction" << std::endl;
        std::cout << "(replace direction with either x or y)" << std::endl;
        exit(1);
    }
    const char* eclipsefilename = argv[1];
    std::string direction(argv[2]);
    if ( ! ((direction == "x") || (direction == "y")) ) {
        std::cerr << "Unrecognized input parameter for direction: '" << direction 
                  << "'. Should be either x or y (maybe also z later)." << std::endl;
        exit(1);
    }

    // Parse grdecl file
    std::cout << "Parsing grid file '" << eclipsefilename << "' ..." << std::endl;
    Opm::Parser parser;
    Opm::ParseContext parseContext;
    const Opm::Deck deck(parser.parseFile(eclipsefilename , parseContext));
    if ( ! (deck.hasKeyword("SPECGRID") && deck.hasKeyword("COORD") && deck.hasKeyword("ZCORN")) ) {
        std::cerr << "Grid file " << eclipsefilename << "are missing keywords SPECGRID, COORD or ZCORN!" << std::endl;
        exit(1);
    }

    // Create new grid file
    std::string mirrored_eclipsefilename = std::string(eclipsefilename);
    std::string::size_type last_dot = mirrored_eclipsefilename.find_last_of('.');
    mirrored_eclipsefilename = mirrored_eclipsefilename.substr(0, last_dot) + "_mirrored-" + direction + ".grdecl";
    std::ofstream outfile;
    outfile.open(mirrored_eclipsefilename.c_str(), std::ios::out | std::ios::trunc);
    if (!outfile) {
        std::cerr << "Can't open output file " << mirrored_eclipsefilename << std::endl;
        exit(1);
    }
    outfile.precision(decimals);
    outfile.setf(std::ios::fixed);

    // Print init message
    printInitMessage(outfile, eclipsefilename, direction);
    
    // Mirror keywords
    mirror_mapaxes(deck, direction, outfile);
    mirror_specgrid(deck, direction, outfile);
    mirror_coord(deck, direction, outfile);
    mirror_zcorn(deck, direction, outfile);
    mirror_celldata<int>("ACTNUM", deck, direction, outfile);
    mirror_celldata<double>("PERMX", deck, direction, outfile);
    mirror_celldata<double>("PERMY", deck, direction, outfile);
    mirror_celldata<double>("PERMZ", deck, direction, outfile);
    mirror_celldata<double>("PORO", deck, direction, outfile);
    mirror_celldata<int>("SATNUM", deck, direction, outfile);
    mirror_celldata<double>("NTG", deck, direction, outfile);
    mirror_celldata<double>("SWCR", deck, direction, outfile);
    mirror_celldata<double>("SOWCR", deck, direction, outfile);
}
示例#2
0
    IncompPropertiesSinglePhase::IncompPropertiesSinglePhase(const Opm::Deck& deck,
                                                             const Opm::EclipseState& eclState,
                                                             const UnstructuredGrid& grid)
    {
        rock_.init(eclState, grid.number_of_cells, grid.global_cell, grid.cartdims);

        if (deck.hasKeyword("DENSITY")) {
            const auto& densityRecord = deck.getKeyword("DENSITY").getRecord(0);
            surface_density_ = densityRecord.getItem("OIL").getSIDouble(0);
        } else {
            surface_density_ = 1000.0;
            OPM_MESSAGE("Input is missing DENSITY -- using a standard density of "
                        << surface_density_ << ".\n");
        }

        // This will be modified if we have a PVCDO specification.
        reservoir_density_ = surface_density_;

        if (deck.hasKeyword("PVCDO")) {
            const auto& pvcdoRecord = deck.getKeyword("PVCDO").getRecord(0);
            if (pvcdoRecord.getItem("OIL_COMPRESSIBILITY").getSIDouble(0) != 0.0 ||
                pvcdoRecord.getItem("OIL_VISCOSIBILITY").getSIDouble(0) != 0.0) {
                OPM_MESSAGE("Compressibility effects in PVCDO are ignored.");
            }
            reservoir_density_ /= pvcdoRecord.getItem("OIL_VOL_FACTOR").getSIDouble(0);
            viscosity_ = pvcdoRecord.getItem("OIL_VISCOSITY").getSIDouble(0);
        } else {
            viscosity_ = 1.0 * prefix::centi*unit::Poise;
            OPM_MESSAGE("Input is missing PVCDO -- using a standard viscosity of "
                        << viscosity_ << " and reservoir density equal to surface density.\n");
        }
    }
示例#3
0
static const Opm::DeckKeyword createTABDIMSKeyword( ) {
    const char* deckData =
    "TABDIMS\n"
    "  0 1 2 3 4 5 / \n"
    "\n";

    Opm::Parser parser;
    Opm::Deck deck = parser.parseString(deckData, Opm::ParseContext());
    return deck.getKeyword("TABDIMS");
}
示例#4
0
static const Opm::DeckKeyword createSATNUMKeyword( ) {
    const char* deckData =
    "SATNUM \n"
    "  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 / \n"
    "\n";

    Opm::Parser parser;
    Opm::Deck deck = parser.parseString(deckData, Opm::ParseContext());
    return deck.getKeyword("SATNUM");
}
示例#5
0
    void GridManager::createGrdecl(const Opm::Deck& deck, struct grdecl &grdecl)
    {
        // Extract data from deck.
        const std::vector<double>& zcorn = deck.getKeyword("ZCORN").getSIDoubleData();
        const std::vector<double>& coord = deck.getKeyword("COORD").getSIDoubleData();
        const int* actnum = NULL;
        if (deck.hasKeyword("ACTNUM")) {
            actnum = &(deck.getKeyword("ACTNUM").getIntData()[0]);
        }

        std::array<int, 3> dims;
        if (deck.hasKeyword("DIMENS")) {
            const auto& dimensKeyword = deck.getKeyword("DIMENS");
            dims[0] = dimensKeyword.getRecord(0).getItem(0).get< int >(0);
            dims[1] = dimensKeyword.getRecord(0).getItem(1).get< int >(0);
            dims[2] = dimensKeyword.getRecord(0).getItem(2).get< int >(0);
        } else if (deck.hasKeyword("SPECGRID")) {
            const auto& specgridKeyword = deck.getKeyword("SPECGRID");
            dims[0] = specgridKeyword.getRecord(0).getItem(0).get< int >(0);
            dims[1] = specgridKeyword.getRecord(0).getItem(1).get< int >(0);
            dims[2] = specgridKeyword.getRecord(0).getItem(2).get< int >(0);
        } else {
            OPM_THROW(std::runtime_error, "Deck must have either DIMENS or SPECGRID.");
        }

        // Collect in input struct for preprocessing.

        grdecl.zcorn = &zcorn[0];
        grdecl.coord = &coord[0];
        grdecl.actnum = actnum;
        grdecl.dims[0] = dims[0];
        grdecl.dims[1] = dims[1];
        grdecl.dims[2] = dims[2];

        if (deck.hasKeyword("MAPAXES")) {
            const auto& mapaxesKeyword = deck.getKeyword("MAPAXES");
            const auto& mapaxesRecord = mapaxesKeyword.getRecord(0);

            // memleak alert: here we need to make sure that C code
            // can properly take ownership of the grdecl.mapaxes
            // object. if it is not freed, it will result in a
            // memleak...
            double *cWtfMapaxes = static_cast<double*>(malloc(sizeof(double)*mapaxesRecord.size()));
            for (unsigned i = 0; i < mapaxesRecord.size(); ++i)
                cWtfMapaxes[i] = mapaxesRecord.getItem(i).getSIDouble(0);
            grdecl.mapaxes = cWtfMapaxes;
        } else
            grdecl.mapaxes = NULL;

    }
示例#6
0
std::vector<double> getMapaxesValues(const Opm::Deck& deck)
{
    const auto& mapaxesRecord = deck.getKeyword("MAPAXES").getRecord(0);
    std::vector<double> result;
    for (size_t itemIdx = 0; itemIdx < mapaxesRecord.size(); ++itemIdx) {
        const auto& curItem = mapaxesRecord.getItem(itemIdx);

        for (size_t dataItemIdx = 0; dataItemIdx < curItem.size(); ++dataItemIdx) {
            result.push_back(curItem.get< double >(dataItemIdx));
        }
    }
    return result;
}
示例#7
0
/// Mirror keyword SPECGRID in deck
void mirror_specgrid( const Opm::Deck& deck, std::string direction, std::ofstream& out) {
    // We only need to multiply the dimension by 2 in the correct direction.
    const auto& specgridRecord = deck.getKeyword("SPECGRID").getRecord(0);
    std::vector<int> dimensions(3);
    dimensions[0] = specgridRecord.getItem("NX").get< int >(0);
    dimensions[1] = specgridRecord.getItem("NY").get< int >(0);
    dimensions[2] = specgridRecord.getItem("NZ").get< int >(0);
    if (direction == "x")      {dimensions[0] *= 2;}
    else if (direction == "y") {dimensions[1] *= 2;}
    else                       {std::cerr << "Direction should be either x or y" << std::endl; exit(1);}
    out << "SPECGRID" << std::endl << dimensions[0] << " " << dimensions[1] << " " << dimensions[2] << " "
        << specgridRecord.getItem("NUMRES").get< int >(0) << " "
        << specgridRecord.getItem("COORD_TYPE").get< std::string >(0) << " "
        << std::endl << "/" << std::endl << std::endl;
}
示例#8
0
/// Mirror keyword MAPAXES in deck
void mirror_mapaxes( const Opm::Deck& deck, std::string direction, std::ofstream& out) {
    // Assumes axis aligned with x/y-direction
    std::cout << "Warning: Keyword MAPAXES not fully understood. Result should be verified manually." << std::endl;
    if (deck.hasKeyword("MAPAXES")) {
        std::vector<double> mapaxes = getMapaxesValues(deck);
        std::vector<double> mapaxes_mirrored = mapaxes;
        // Double the length of the coordinate axis
        if (direction == "x") {
            mapaxes_mirrored[4] = (mapaxes[4]-mapaxes[2])*2 + mapaxes[2];
        }
        else if (direction == "y") {
            mapaxes_mirrored[1] = (mapaxes[1]-mapaxes[3])*2 + mapaxes[3];
        }
        printKeywordValues(out, "MAPAXES", mapaxes_mirrored, 2);
    }
}
示例#9
0
void mirror_celldata(std::string keyword, const Opm::Deck& deck, std::string direction, std::ofstream& out) {
    if ( ! deck.hasKeyword(keyword)) {
        std::cout << "Ignoring keyword " << keyword << " as it was not found." << std::endl;
        return;
    }
    // Get data from eclipse deck
    const auto& specgridRecord = deck.getKeyword("SPECGRID").getRecord(0);
    std::vector<int> dimensions(3);
    dimensions[0] = specgridRecord.getItem("NX").get< int >(0);
    dimensions[1] = specgridRecord.getItem("NY").get< int >(0);
    dimensions[2] = specgridRecord.getItem("NZ").get< int >(0);
    std::vector<T> values = getKeywordValues(keyword, deck, T(0.0));
    std::vector<T> values_mirrored(2*dimensions[0]*dimensions[1]*dimensions[2], 0.0);
    // Handle the two directions differently due to ordering of the pillars.
    if (direction == "x") {
        typename std::vector<T>::iterator it_orig = values.begin();
        typename std::vector<T>::iterator it_new = values_mirrored.begin();
        // Loop through each line and copy old cell data and add new (which are the old reversed)
        for ( ; it_orig != values.end(); it_orig += dimensions[0]) {
            // Copy old cell data
            copy(it_orig, it_orig + dimensions[0], it_new);
            it_new += dimensions[0];
            // Add new cell data
            std::vector<double> next_vec(it_orig, it_orig + dimensions[0]);
            std::vector<double> next_reversed = next_vec;
            reverse(next_reversed.begin(), next_reversed.end());
            copy(next_reversed.begin(), next_reversed.end(), it_new);
            it_new += dimensions[0];
        }
    }
    else if (direction =="y") {
        typename std::vector<T>::iterator it_orig = values.begin();
        typename std::vector<T>::iterator it_new = values_mirrored.begin();
        // Entries per layer
        const int entries_per_layer = dimensions[0]*dimensions[1];
        // Loop through each layer and copy old cell data and add new (which are the old reordered) 
        for ( ; it_orig != values.end(); it_orig += entries_per_layer) {
            // Copy old cell data
            copy(it_orig, it_orig + entries_per_layer, it_new);
            it_new += entries_per_layer;
            // Add new cell data
            std::vector<T> next_vec(it_orig, it_orig + entries_per_layer);
            std::vector<T> next_reordered(entries_per_layer, 0.0);
            typename std::vector<T>::iterator it_next = next_vec.end();
            typename std::vector<T>::iterator it_reordered = next_reordered.begin();
            // Reorder next entries
            for ( ; it_reordered != next_reordered.end(); it_reordered += dimensions[0]) {
                copy(it_next - dimensions[0], it_next, it_reordered);
                it_next -= dimensions[0];
            }
            copy(next_reordered.begin(), next_reordered.end(), it_new);
            it_new += entries_per_layer;
        }
    }
    else {
        std::cerr << "Direction should be either x or y" << std::endl;
        exit(1);
    }
    // Write new keyword values to output file
    printKeywordValues(out, keyword, values_mirrored, 8);
}
示例#10
0
std::vector<double> getKeywordValues(std::string keyword, const Opm::Deck& deck, double /*dummy*/) {
    return deck.getKeyword(keyword).getRawDoubleData();
}
示例#11
0
std::vector<int> getKeywordValues(std::string keyword, const Opm::Deck& deck, int /*dummy*/) {
    return deck.getKeyword(keyword).getIntData();
}
示例#12
0
/// Mirror keyword ZCORN in deck
void mirror_zcorn(const Opm::Deck& deck, std::string direction, std::ofstream& out) {
    const auto& specgridRecord = deck.getKeyword("SPECGRID").getRecord(0);
    std::vector<int> dimensions(3);
    dimensions[0] = specgridRecord.getItem("NX").get< int >(0);
    dimensions[1] = specgridRecord.getItem("NY").get< int >(0);
    dimensions[2] = specgridRecord.getItem("NZ").get< int >(0);
    std::vector<double> zcorn = deck.getKeyword("ZCORN").getRawDoubleData();
    std::vector<double> zcorn_mirrored;
    // Handle the two directions differently due to ordering of the pillars.
    if (direction == "x") {
        // Total entries in mirrored ZCORN. Eight corners per cell.
        const int entries = dimensions[0]*2*dimensions[1]*dimensions[2]*8;
        zcorn_mirrored.assign(entries, 0.0);
        // Entries per line in x-direction. Two for each cell.
        const int entries_per_line = dimensions[0]*2;
        std::vector<double>::iterator it_new = zcorn_mirrored.begin();
        std::vector<double>::iterator it_orig = zcorn.begin();
        // Loop through each line and copy old corner-points and add new (which are the old reversed)
        for ( ; it_orig != zcorn.end(); it_orig += entries_per_line) {
            std::vector<double> next_vec(it_orig, it_orig + entries_per_line);
            std::vector<double> next_reversed = next_vec;
            reverse(next_reversed.begin(), next_reversed.end());
            // Copy old corner-points
            copy(it_orig, it_orig + entries_per_line, it_new);
            it_new += entries_per_line;
            // Add new corner-points
            copy(next_reversed.begin(), next_reversed.end(), it_new);
            it_new += entries_per_line;
        }
    }
    else if (direction == "y") {
        // Total entries in mirrored ZCORN. Eight corners per cell.
        const int entries = dimensions[0]*dimensions[1]*2*dimensions[2]*8;
        zcorn_mirrored.assign(entries, 0.0);
        // Entries per line in x-direction. Two for each cell.
        const int entries_per_line_x = dimensions[0]*2;
        // Entries per layer of corner-points. Four for each cell
        const int entries_per_layer = dimensions[0]*dimensions[1]*4;
        std::vector<double>::iterator it_new = zcorn_mirrored.begin();
        std::vector<double>::iterator it_orig = zcorn.begin();
        // Loop through each layer and copy old corner-points and add new (which are the old reordered) 
        for ( ; it_orig != zcorn.end(); it_orig += entries_per_layer) {
            // Copy old corner-points
            copy(it_orig, it_orig + entries_per_layer, it_new);
            it_new += entries_per_layer;
            // Add new corner-points
            std::vector<double> next_vec(it_orig, it_orig + entries_per_layer);
            std::vector<double> next_reordered(entries_per_layer, 0.0);
            std::vector<double>::iterator it_next = next_vec.end();
            std::vector<double>::iterator it_reordered = next_reordered.begin();
            // Reorder next entries
            for ( ; it_reordered != next_reordered.end(); it_reordered += entries_per_line_x) {
                copy(it_next - entries_per_line_x, it_next, it_reordered);
                it_next -= entries_per_line_x;
            }
            copy(next_reordered.begin(), next_reordered.end(), it_new);
            it_new += entries_per_layer;
        }
    }
    else {
        std::cerr << "Direction should be either x or y" << std::endl;
        exit(1);
    }
    // Write new ZCORN values to output file
    printKeywordValues(out, "ZCORN", zcorn_mirrored, 8);
}
示例#13
0
/// Mirror keyword COORD in deck
void mirror_coord(const Opm::Deck& deck, std::string direction, std::ofstream& out) {
    // We assume uniform spacing in x and y directions and parallel top and bottom faces
    const auto& specgridRecord = deck.getKeyword("SPECGRID").getRecord(0);
    std::vector<int> dimensions(3);
    dimensions[0] = specgridRecord.getItem("NX").get< int >(0);
    dimensions[1] = specgridRecord.getItem("NY").get< int >(0);
    dimensions[2] = specgridRecord.getItem("NZ").get< int >(0);
    std::vector<double> coord = deck.getKeyword("COORD").getRawDoubleData();
    const int entries_per_pillar = 6;
    std::vector<double> coord_mirrored;
    // Handle the two directions differently due to ordering of the pillars.
    if (direction == "x") {
        // Total entries in mirrored ZCORN. Number of pillars times 6
        const int entries = (2*dimensions[0] + 1) * (dimensions[1] + 1) * entries_per_pillar;
        // Entries per line in x-direction. Number of pillars in x-direction times 6
        const int entries_per_line = entries_per_pillar*(dimensions[0] + 1);
        coord_mirrored.assign(entries, 0.0);
        // Distance between pillars in x-directiion
        const double spacing = coord[entries_per_pillar]-coord[0];
        std::vector<double>::iterator it_new = coord_mirrored.begin();
        std::vector<double>::iterator it_orig;
        // Loop through each pillar line in the x-direction
        for (it_orig = coord.begin(); it_orig != coord.end(); it_orig += entries_per_line) {
            // Copy old pillars
            copy(it_orig, it_orig + entries_per_line, it_new);
            // Add new pillars in between
            it_new += entries_per_line;
            std::vector<double> next_vec(it_orig + entries_per_line - entries_per_pillar, it_orig + entries_per_line);
            for (int r=0; r < dimensions[0]; ++r) {
                next_vec[0] += spacing;
                next_vec[3] += spacing;
                copy(next_vec.begin(), next_vec.end(), it_new);
                it_new += entries_per_pillar;
            }
        }
    }
    else if (direction == "y") {
        // Total entries in mirrored ZCORN. Number of pillars times 6
        const int entries = (dimensions[0] + 1) * (2*dimensions[1] + 1) * entries_per_pillar;
        // Entries per line in y-direction. Number of pillars in y-direction times 6
        const int entries_per_line = entries_per_pillar*(dimensions[0] + 1);
        coord_mirrored.assign(entries, 0.0);
        // Distance between pillars in y-directiion
        const double spacing = coord[entries_per_line + 1]-coord[1];
        std::vector<double>::iterator it_new = coord_mirrored.begin();
        // Copy old pillars
        copy(coord.begin(), coord.end(), it_new);
        // Add new pillars at the end
        it_new += coord.size();
        std::vector<double> next_vec(coord.end() - entries_per_line, coord.end());
        for ( ; it_new != coord_mirrored.end(); it_new += entries_per_line) {
            for (int i = 1; i < entries_per_line; i += 3) {
                next_vec[i] += spacing;
            }
            copy(next_vec.begin(), next_vec.end(), it_new);
        }
    }
    else {
        std::cerr << "Direction should be either x or y" << std::endl;
        exit(1);
    }
    // Write new COORD values to output file
    printKeywordValues(out, "COORD", coord_mirrored, 6);
}
示例#14
0
// ----------------- Main program -----------------
int
main(int argc, char** argv)
try
{
    using namespace Opm;

    std::cout << "\n================    Test program for weakly compressible two-phase flow with polymer    ===============\n\n";
    parameter::ParameterGroup param(argc, argv, false);
    std::cout << "---------------    Reading parameters     ---------------" << std::endl;

    // If we have a "deck_filename", grid and props will be read from that.
    bool use_deck = param.has("deck_filename");
    boost::scoped_ptr<GridManager> grid;
    boost::scoped_ptr<BlackoilPropertiesInterface> props;
    boost::scoped_ptr<RockCompressibility> rock_comp;
    std::unique_ptr<PolymerBlackoilState> state;
    Opm::PolymerProperties poly_props;
    Opm::Deck deck;
    std::unique_ptr< EclipseState > eclipseState;
    // bool check_well_controls = false;
    // int max_well_control_iterations = 0;
    double gravity[3] = { 0.0 };
    if (use_deck) {
        std::string deck_filename = param.get<std::string>("deck_filename");
        Parser parser;
        Opm::ParseContext parseContext({{ ParseContext::PARSE_RANDOM_SLASH , InputError::IGNORE }});
        deck = parser.parseFile(deck_filename , parseContext);
        eclipseState.reset( new EclipseState(deck , parseContext) );

        // Grid init
        grid.reset(new GridManager(eclipseState->getInputGrid()));
        {
            const UnstructuredGrid& ug_grid = *(grid->c_grid());

            // Rock and fluid init
            props.reset(new BlackoilPropertiesFromDeck(deck, *eclipseState, ug_grid));
            // check_well_controls = param.getDefault("check_well_controls", false);
            // max_well_control_iterations = param.getDefault("max_well_control_iterations", 10);

            state.reset( new PolymerBlackoilState(  UgGridHelpers::numCells( ug_grid ) , UgGridHelpers::numFaces( ug_grid ), 2));
            // Rock compressibility.
            rock_comp.reset(new RockCompressibility(*eclipseState));
            // Gravity.
            gravity[2] = deck.hasKeyword("NOGRAV") ? 0.0 : unit::gravity;
            // Init state variables (saturation and pressure).
            if (param.has("init_saturation")) {
                initStateBasic(ug_grid, *props, param, gravity[2], *state);
            } else {
                initStateFromDeck(ug_grid, *props, deck, gravity[2], *state);
            }
            initBlackoilSurfvol(ug_grid, *props, *state);
            // Init polymer properties.
            poly_props.readFromDeck(deck, *eclipseState);
        }
    } else {
        // Grid init.
        const int nx = param.getDefault("nx", 100);
        const int ny = param.getDefault("ny", 100);
        const int nz = param.getDefault("nz", 1);
        const double dx = param.getDefault("dx", 1.0);
        const double dy = param.getDefault("dy", 1.0);
        const double dz = param.getDefault("dz", 1.0);
        grid.reset(new GridManager(nx, ny, nz, dx, dy, dz));
        {
            const UnstructuredGrid& ug_grid = *(grid->c_grid());

            // Rock and fluid init.
            props.reset(new BlackoilPropertiesBasic(param, ug_grid.dimensions, UgGridHelpers::numCells( ug_grid )));
            state.reset( new PolymerBlackoilState(  UgGridHelpers::numCells( ug_grid ) , UgGridHelpers::numFaces( ug_grid ) , 2));
            // Rock compressibility.
            rock_comp.reset(new RockCompressibility(param));
            // Gravity.
            gravity[2] = param.getDefault("gravity", 0.0);
            // Init state variables (saturation and pressure).
            initStateBasic(ug_grid, *props, param, gravity[2], *state);
            initBlackoilSurfvol(ug_grid, *props, *state);
            // Init Polymer state

            if (param.has("poly_init")) {
                double poly_init = param.getDefault("poly_init", 0.0);
                for (int cell = 0; cell < UgGridHelpers::numCells( ug_grid ); ++cell) {
                    double smin[2], smax[2];

                    auto& saturation = state->saturation();
                    auto& concentration = state->getCellData( state->CONCENTRATION );
                    auto& max_concentration = state->getCellData( state->CMAX );

                    props->satRange(1, &cell, smin, smax);
                    if (saturation[2*cell] > 0.5*(smin[0] + smax[0])) {
                        concentration[cell] = poly_init;
                        max_concentration[cell] = poly_init;
                    } else {
                        saturation[2*cell + 0] = 0.;
                        saturation[2*cell + 1] = 1.;
                        concentration[cell] = 0.;
                        max_concentration[cell] = 0.;
                    }
                }
            }

        }
        // Init polymer properties.
        // Setting defaults to provide a simple example case.
        double c_max = param.getDefault("c_max_limit", 5.0);
        double mix_param = param.getDefault("mix_param", 1.0);
        double rock_density = param.getDefault("rock_density", 1000.0);
        double dead_pore_vol = param.getDefault("dead_pore_vol", 0.15);
        double res_factor = param.getDefault("res_factor", 1.) ; // res_factor = 1 gives no change in permeability
        double c_max_ads = param.getDefault("c_max_ads", 1.);
        int ads_index = param.getDefault<int>("ads_index", Opm::PolymerProperties::NoDesorption);
        std::vector<double> c_vals_visc(2, -1e100);
        c_vals_visc[0] = 0.0;
        c_vals_visc[1] = 7.0;
        std::vector<double> visc_mult_vals(2, -1e100);
        visc_mult_vals[0] = 1.0;
        // poly_props.visc_mult_vals[1] = param.getDefault("c_max_viscmult", 30.0);
        visc_mult_vals[1] = 20.0;
        std::vector<double> c_vals_ads(3, -1e100);
        c_vals_ads[0] = 0.0;
        c_vals_ads[1] = 2.0;
        c_vals_ads[2] = 8.0;
        std::vector<double> ads_vals(3, -1e100);
        ads_vals[0] = 0.0;
        ads_vals[1] = 0.0015;
        ads_vals[2] = 0.0025;
        // ads_vals[1] = 0.0;
        // ads_vals[2] = 0.0;
        std::vector<double> water_vel_vals(2, -1e100);
        water_vel_vals[0] = 0.0;
        water_vel_vals[1] = 10.0;
        std::vector<double> shear_vrf_vals(2, -1e100);
        shear_vrf_vals[0] = 1.0;
        shear_vrf_vals[1] = 1.0;
        poly_props.set(c_max, mix_param, rock_density, dead_pore_vol, res_factor, c_max_ads,
                       static_cast<Opm::PolymerProperties::AdsorptionBehaviour>(ads_index),
                       c_vals_visc,  visc_mult_vals, c_vals_ads, ads_vals, water_vel_vals, shear_vrf_vals);
    }

    bool use_gravity = (gravity[0] != 0.0 || gravity[1] != 0.0 || gravity[2] != 0.0);
    const double *grav = use_gravity ? &gravity[0] : 0;

    // Linear solver.
    LinearSolverFactory linsolver(param);

    // Write parameters used for later reference.
    bool output = param.getDefault("output", true);
    if (output) {
      std::string output_dir =
        param.getDefault("output_dir", std::string("output"));
      boost::filesystem::path fpath(output_dir);
      try {
        create_directories(fpath);
      }
      catch (...) {
        OPM_THROW(std::runtime_error, "Creating directories failed: " << fpath);
      }
      param.writeParam(output_dir + "/simulation.param");
    }


    std::cout << "\n\n================    Starting main simulation loop     ===============\n"
              << std::flush;

    SimulatorReport rep;
    if (!use_deck) {
        // Simple simulation without a deck.
        PolymerInflowBasic polymer_inflow(param.getDefault("poly_start_days", 300.0)*Opm::unit::day,
                                          param.getDefault("poly_end_days", 800.0)*Opm::unit::day,
                                          param.getDefault("poly_amount", poly_props.cMax()));
        WellsManager wells;
        SimulatorCompressiblePolymer simulator(param,
                                               *grid->c_grid(),
                                               *props,
                                               poly_props,
                                               rock_comp->isActive() ? rock_comp.get() : 0,
                                               wells,
                                               polymer_inflow,
                                               linsolver,
                                               grav);
        SimulatorTimer simtimer;
        simtimer.init(param);
        warnIfUnusedParams(param);
        WellState well_state;
        well_state.init(0, *state);
        rep = simulator.run(simtimer, *state, well_state);
    } else {
        // With a deck, we may have more epochs etc.
        WellState well_state;
        int step = 0;
        Opm::TimeMap timeMap(deck);
        SimulatorTimer simtimer;
        simtimer.init(timeMap);
        // Check for WPOLYMER presence in last report step to decide
        // polymer injection control type.
        const bool use_wpolymer = deck.hasKeyword("WPOLYMER");
        if (use_wpolymer) {
            if (param.has("poly_start_days")) {
                OPM_MESSAGE("Warning: Using WPOLYMER to control injection since it was found in deck. "
                        "You seem to be trying to control it via parameter poly_start_days (etc.) as well.");
            }
        }
        for (size_t reportStepIdx = 0; reportStepIdx < timeMap.numTimesteps(); ++reportStepIdx) {
            simtimer.setCurrentStepNum(reportStepIdx);

            // Report on start of report step.
            std::cout << "\n\n--------------    Starting report step " << reportStepIdx << "    --------------"
                      << "\n                  (number of remaining steps: "
                      << simtimer.numSteps() - step << ")\n\n" << std::flush;

            // Create new wells, polymer inflow controls.
            eclipseState.reset( new EclipseState( deck ) );
            WellsManager wells(*eclipseState , reportStepIdx , *grid->c_grid(), props->permeability());
            boost::scoped_ptr<PolymerInflowInterface> polymer_inflow;
            if (use_wpolymer) {
                if (wells.c_wells() == 0) {
                    OPM_THROW(std::runtime_error, "Cannot control polymer injection via WPOLYMER without wells.");
                }
                polymer_inflow.reset(new PolymerInflowFromDeck(*eclipseState, *wells.c_wells(), props->numCells(), simtimer.currentStepNum()));
            } else {
                polymer_inflow.reset(new PolymerInflowBasic(param.getDefault("poly_start_days", 300.0)*Opm::unit::day,
                                                            param.getDefault("poly_end_days", 800.0)*Opm::unit::day,
                                                            param.getDefault("poly_amount", poly_props.cMax())));
            }

            // @@@ HACK: we should really make a new well state and
            // properly transfer old well state to it every report step,
            // since number of wells may change etc.
            if (reportStepIdx == 0) {
                well_state.init(wells.c_wells(), *state);
            }

            // Create and run simulator.
            SimulatorCompressiblePolymer simulator(param,
                                                   *grid->c_grid(),
                                                   *props,
                                                   poly_props,
                                                   rock_comp->isActive() ? rock_comp.get() : 0,
                                                   wells,
                                                   *polymer_inflow,
                                                   linsolver,
                                                   grav);
            if (reportStepIdx == 0) {
                warnIfUnusedParams(param);
            }
            SimulatorReport epoch_rep = simulator.run(simtimer, *state, well_state);

            // Update total timing report and remember step number.
            rep += epoch_rep;
            step = simtimer.currentStepNum();
        }
    }

    std::cout << "\n\n================    End of simulation     ===============\n\n";
    rep.report(std::cout);
}
catch (const std::exception &e) {
    std::cerr << "Program threw an exception: " << e.what() << "\n";
    throw;
}
        /// set the tables which specify the temperature dependence of the oil viscosity
        void initFromDeck(std::shared_ptr<const PvtInterface> isothermalPvt,
                          const Opm::Deck& deck,
                          const Opm::EclipseState& eclipseState)
        {
            isothermalPvt_ = isothermalPvt;

            int numRegions;
            auto tables = eclipseState->getTableManager();

            if (deck->hasKeyword("PVTO"))
                numRegions = tables->getPvtoTables().size();
            else if (deck->hasKeyword("PVDO"))
                numRegions = tables->getPvdoTables().size();
            else if (deck->hasKeyword("PVCDO"))
                numRegions = deck->getKeyword("PVCDO").size();
            else
                OPM_THROW(std::runtime_error, "Oil phase was not initialized using a known way");

            // viscosity
            if (deck->hasKeyword("VISCREF")) {
                oilvisctTables_ = &tables->getOilvisctTables();
                const auto& viscrefKeyword = deck->getKeyword("VISCREF");

                assert(int(oilvisctTables_->size()) == numRegions);
                assert(int(viscrefKeyword.size()) == numRegions);

                viscrefPress_.resize(numRegions);
                viscrefRs_.resize(numRegions);
                muRef_.resize(numRegions);
                for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                    const auto& viscrefRecord = viscrefKeyword.getRecord(regionIdx);
                    viscrefPress_[regionIdx] = viscrefRecord.getItem("REFERENCE_PRESSURE").getSIDouble(0);
                    viscrefRs_[regionIdx] = viscrefRecord.getItem("REFERENCE_RS").getSIDouble(0);

                    // temperature used to calculate the reference viscosity [K]. the
                    // value does not really matter if the underlying PVT object really
                    // is isothermal...
                    double Tref = 273.15 + 20;

                    // compute the reference viscosity using the isothermal PVT object.
                    double tmp1, tmp2;
                    isothermalPvt_->mu(1,
                                       &regionIdx,
                                       &viscrefPress_[regionIdx],
                                       &Tref,
                                       &viscrefRs_[regionIdx],
                                       &muRef_[regionIdx],
                                       &tmp1,
                                       &tmp2);
                }
            }

            // quantities required for density. note that we just always use the values
            // for the first EOS. (since EOS != PVT region.)
            tref_ = 0.0;
            if (deck->hasKeyword("THERMEX1")) {
                oilCompIdx_ = deck->getKeyword("OCOMPIDX").getRecord(0).getItem("OIL_COMPONENT_INDEX").get< int >(0) - 1;

                // always use the values of the first EOS
                tref_ = deck->getKeyword("TREF").getRecord(0).getItem("TEMPERATURE").getSIDouble(oilCompIdx_);
                pref_ = deck->getKeyword("PREF").getRecord(0).getItem("PRESSURE").getSIDouble(oilCompIdx_);
                cref_ = deck->getKeyword("CREF").getRecord(0).getItem("COMPRESSIBILITY").getSIDouble(oilCompIdx_);
                thermex1_ = deck->getKeyword("THERMEX1").getRecord(0).getItem("EXPANSION_COEFF").getSIDouble(oilCompIdx_);
            }
        }