Пример #1
0
    void restoreTemperatureData(const ecl_file_type* file,
                              EclipseStateConstPtr eclipse_state,
                              int numcells,
                              SimulatorState& simulator_state) {
        const char* temperature = "TEMP";

        if (ecl_file_has_kw(file , temperature)) {
            ecl_kw_type* temperature_kw = ecl_file_iget_named_kw(file, temperature, 0);

            if (ecl_kw_get_size(temperature_kw) != numcells) {
                throw std::runtime_error("Read of restart file: Could not restore temperature data, length of data from file not equal number of cells");
            }

            float* temperature_data = ecl_kw_get_float_ptr(temperature_kw);

            // factor and offset from the temperature values given in the deck to Kelvin
            double scaling = eclipse_state->getDeckUnitSystem().parse("Temperature")->getSIScaling();
            double offset  = eclipse_state->getDeckUnitSystem().parse("Temperature")->getSIOffset();

            for (size_t index = 0; index < simulator_state.temperature().size(); ++index) {
                simulator_state.temperature()[index] = unit::convert::from((double)temperature_data[index] - offset, scaling);
            }
          } else {
              throw std::runtime_error("Read of restart file: File does not contain TEMP data\n");
          }
    }
Пример #2
0
    /// \brief Get a vector of pressure thresholds from either EclipseState
    /// or maxDp (for defaulted values) for all Non-neighbour connections (NNCs).
    /// \param[in] nnc            The NNCs,
    /// \param[in] eclipseState   Processed eclipse state, EQLNUM is accessed from it.
    /// \param[in] maxDp          The maximum gravity corrected pressure differences between
    ///                           the equilibration regions.
    /// \return                   A vector of pressure thresholds, one
    ///                           for each NNC in the grid. A value
    ///                           of zero means no threshold for that
    ///                           particular connection. An empty vector is
    ///                           returned if there is no THPRES
    ///                           feature used in the deck.
     std::vector<double> thresholdPressuresNNC(EclipseStateConstPtr eclipseState,
                                               const NNC& nnc,
                                               const std::map<std::pair<int, int>, double>& maxDp)
    {
        const SimulationConfig& simulationConfig = eclipseState->getSimulationConfig();
        std::vector<double> thpres_vals;
        if (simulationConfig.hasThresholdPressure()) {
            std::shared_ptr<const ThresholdPressure> thresholdPressure = simulationConfig.getThresholdPressure();
            const auto& eqlnum = eclipseState->get3DProperties().getIntGridProperty("EQLNUM");
            const auto& eqlnumData = eqlnum.getData();

            // Set values for each NNC

            thpres_vals.resize(nnc.numNNC(), 0.0);
            for (size_t i = 0 ; i < nnc.numNNC(); ++i) {
                const int gc1 = nnc.nncdata()[i].cell1;
                const int gc2 = nnc.nncdata()[i].cell2;
                const int eq1 = eqlnumData[gc1];
                const int eq2 = eqlnumData[gc2];

                if (thresholdPressure->hasRegionBarrier(eq1,eq2)) {
                    if (thresholdPressure->hasThresholdPressure(eq1,eq2)) {
                        thpres_vals[i] = thresholdPressure->getThresholdPressure(eq1,eq2);
                    } else {
                        // set the threshold pressure for NNC of PVT regions where the third item
                        // has been defaulted to the maximum pressure potential difference between
                        // these regions
                        const auto barrierId = std::make_pair(eq1, eq2);
                        thpres_vals[i] = maxDp.at(barrierId);
                    }
                }
            }
        }
        return thpres_vals;
    }
Пример #3
0
    std::vector<double> thresholdPressures(const DeckConstPtr& /* deck */,
                                           EclipseStateConstPtr eclipseState,
                                           const Grid& grid,
                                           const std::map<std::pair<int, int>, double>& maxDp)
    {
        const SimulationConfig& simulationConfig = eclipseState->getSimulationConfig();
        std::vector<double> thpres_vals;
        if (simulationConfig.hasThresholdPressure()) {
            std::shared_ptr<const ThresholdPressure> thresholdPressure = simulationConfig.getThresholdPressure();
            const auto& eqlnum = eclipseState->get3DProperties().getIntGridProperty("EQLNUM");
            const auto& eqlnumData = eqlnum.getData();

            // Set threshold pressure values for each cell face.
            const int num_faces = UgGridHelpers::numFaces(grid);
            const auto& fc = UgGridHelpers::faceCells(grid);
            const int* gc = UgGridHelpers::globalCell(grid);
            thpres_vals.resize(num_faces, 0.0);
            for (int face = 0; face < num_faces; ++face) {
                const int c1 = fc(face, 0);
                const int c2 = fc(face, 1);
                if (c1 < 0 || c2 < 0) {
                    // Boundary face, skip it.
                    continue;
                }
                const int gc1 = (gc == 0) ? c1 : gc[c1];
                const int gc2 = (gc == 0) ? c2 : gc[c2];
                const int eq1 = eqlnumData[gc1];
                const int eq2 = eqlnumData[gc2];

                if (thresholdPressure->hasRegionBarrier(eq1,eq2)) {
                    if (thresholdPressure->hasThresholdPressure(eq1,eq2)) {
                        thpres_vals[face] = thresholdPressure->getThresholdPressure(eq1,eq2);
                    }
                    else {
                        // set the threshold pressure for faces of PVT regions where the third item
                        // has been defaulted to the maximum pressure potential difference between
                        // these regions
                        const auto barrierId = std::make_pair(std::min(eq1, eq2), std::max(eq1, eq2));
                        if (maxDp.count(barrierId) > 0)
                            thpres_vals[face] = maxDp.at(barrierId);
                        else
                            thpres_vals[face] = 0.0;
                    }
                }

            }
        }
        return thpres_vals;
    }
Пример #4
0
    void init_from_restart_file(EclipseStateConstPtr eclipse_state,
                                int numcells,
                                const PhaseUsage& phase_usage,
                                SimulatorState& simulator_state,
                                WellState& wellstate) {

        InitConfigConstPtr initConfig        = eclipse_state->getInitConfig();
        IOConfigConstPtr ioConfig            = eclipse_state->getIOConfig();
        int restart_step                     = initConfig->getRestartStep();
        const std::string& restart_file_root = initConfig->getRestartRootName();
        bool output                          = false;
        const std::string& restart_file_name = ioConfig->getRestartFileName(restart_file_root, restart_step, output);

        Opm::restoreSOLUTION(restart_file_name, restart_step, ioConfig->getUNIFIN(), eclipse_state, numcells, phase_usage, simulator_state);
        Opm::restoreOPM_XWELKeyword(restart_file_name, restart_step, ioConfig->getUNIFIN(), wellstate);
    }
Пример #5
0
    void restoreSOLUTION(const std::string& restart_filename,
                         int reportstep,
                         bool unified,
                         EclipseStateConstPtr eclipseState,
                         int numcells,
                         const PhaseUsage& phaseUsage,
                         SimulatorState& simulator_state)
    {
        const char* filename = restart_filename.c_str();
        ecl_file_type* file_type = ecl_file_open(filename, 0);

        if (file_type) {
            bool block_selected = unified ? ecl_file_select_rstblock_report_step(file_type , reportstep) : true;

            if (block_selected) {
                restorePressureData(file_type, eclipseState, numcells, simulator_state);
                restoreTemperatureData(file_type, eclipseState, numcells, simulator_state);
                restoreSaturation(file_type, phaseUsage, numcells, simulator_state);
                BlackoilState* blackoilState = dynamic_cast<BlackoilState*>(&simulator_state);
                if (blackoilState) {
                    SimulationConfigConstPtr sim_config = eclipseState->getSimulationConfig();
                    restoreRSandRV(file_type, sim_config, numcells, blackoilState);
                }
            } else {
                std::string error_str = "Restart file " +  restart_filename + " does not contain data for report step " + std::to_string(reportstep) + "!\n";
                throw std::runtime_error(error_str);
            }
            ecl_file_close(file_type);
        } else {
            std::string error_str = "Restart file " + restart_filename + " not found!\n";
            throw std::runtime_error(error_str);
        }
    }
Пример #6
0
// ----------------- Main program -----------------
int
main(int argc, char** argv)
try
{
    using namespace Opm;
    if (argc <= 1) {
        usage();
        exit(1);
    } 
    const char* eclipseFilename = argv[1];
    EclipseStateConstPtr eclState; 
    ParserPtr parser(new Opm::Parser);
    Opm::ParseContext parseContext({{ ParseContext::PARSE_RANDOM_SLASH , InputError::IGNORE }, 
                              { ParseContext::PARSE_UNKNOWN_KEYWORD, InputError::IGNORE},
                              { ParseContext::PARSE_RANDOM_TEXT, InputError::IGNORE},
                              { ParseContext::UNSUPPORTED_SCHEDULE_GEO_MODIFIER, InputError::IGNORE},
                              { ParseContext::UNSUPPORTED_COMPORD_TYPE, InputError::IGNORE},
                              { ParseContext::UNSUPPORTED_INITIAL_THPRES, InputError::IGNORE},
                              { ParseContext::INTERNAL_ERROR_UNINITIALIZED_THPRES, InputError::IGNORE}
                             });
    Opm::DeckConstPtr deck(parser->parseFile(eclipseFilename, parseContext));
    eclState.reset(new EclipseState(deck, parseContext));

    GridManager gm(deck);
    const UnstructuredGrid& grid = *gm.c_grid();
    using boost::filesystem::path; 
    path fpath(eclipseFilename);
    std::string baseName;
    if (boost::to_upper_copy(path(fpath.extension()).string())== ".DATA") {
        baseName = path(fpath.stem()).string();
    } else {
        baseName = path(fpath.filename()).string();
    }

    std::string logFile = baseName + ".SATFUNCLOG";
    Opm::time::StopWatch timer;
    timer.start();
    RelpermDiagnostics diagnostic(logFile);
    diagnostic.diagnosis(eclState, deck, grid);
    timer.stop();
    double tt = timer.secsSinceStart();
    std::cout << "relperm diagnostics: " << tt << " seconds." << std::endl;
}
catch (const std::exception &e) {
    std::cerr << "Program threw an exception: " << e.what() << "\n";
    throw;
}
Пример #7
0
    /*!
     * \brief Implement the temperature part of the water PVT properties.
     */
    void initFromDeck(DeckConstPtr deck,
                      EclipseStateConstPtr eclState)
    {
        //////
        // initialize the isothermal part
        //////
        isothermalPvt_ = new IsothermalPvt;
        isothermalPvt_->initFromDeck(deck, eclState);

        //////
        // initialize the thermal part
        //////
        auto tables = eclState->getTableManager();

        enableThermalDensity_ = deck->hasKeyword("WATDENT");
        enableThermalViscosity_ = deck->hasKeyword("VISCREF");

        unsigned numRegions = isothermalPvt_->numRegions();
        setNumRegions(numRegions);

        if (enableThermalDensity_) {
            const auto& watdentKeyword = deck->getKeyword("WATDENT");

            assert(watdentKeyword.size() == numRegions);
            for (unsigned regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                const auto& watdentRecord = watdentKeyword.getRecord(regionIdx);

                watdentRefTemp_[regionIdx] = watdentRecord.getItem("REFERENCE_TEMPERATURE").getSIDouble(0);
                watdentCT1_[regionIdx] = watdentRecord.getItem("EXPANSION_COEFF_LINEAR").getSIDouble(0);
                watdentCT2_[regionIdx] = watdentRecord.getItem("EXPANSION_COEFF_QUADRATIC").getSIDouble(0);
            }
        }

        if (enableThermalViscosity_) {
            const auto& viscrefKeyword = deck->getKeyword("VISCREF");

            const auto& watvisctTables = tables->getWatvisctTables();

            assert(watvisctTables.size() == numRegions);
            assert(viscrefKeyword.size() == numRegions);

            for (unsigned regionIdx = 0; regionIdx < numRegions; ++ regionIdx) {
                const auto& T = watvisctTables[regionIdx].getColumn("Temperature").vectorCopy();
                const auto& mu = watvisctTables[regionIdx].getColumn("Viscosity").vectorCopy();
                watvisctCurves_[regionIdx].setXYContainers(T, mu);

                const auto& viscrefRecord = viscrefKeyword.getRecord(regionIdx);
                viscrefPress_[regionIdx] = viscrefRecord.getItem("REFERENCE_PRESSURE").getSIDouble(0);
            }
        }
    }
Пример #8
0
    /*!
     * \brief Initialize the parameters for dry gas using an ECL deck.
     *
     * This method assumes that the deck features valid DENSITY and PVDG keywords.
     */
    void initFromDeck(DeckConstPtr deck, EclipseStateConstPtr eclState)
    {
        const auto& pvdgTables = eclState->getTableManager()->getPvdgTables();
        const auto& densityKeyword = deck->getKeyword("DENSITY");

        assert(pvdgTables.size() == densityKeyword.size());

        size_t numRegions = pvdgTables.size();
        setNumRegions(numRegions);

        for (unsigned regionIdx = 0; regionIdx < numRegions; ++ regionIdx) {
            Scalar rhoRefO = densityKeyword.getRecord(regionIdx).getItem("OIL").getSIDouble(0);
            Scalar rhoRefG = densityKeyword.getRecord(regionIdx).getItem("GAS").getSIDouble(0);
            Scalar rhoRefW = densityKeyword.getRecord(regionIdx).getItem("WATER").getSIDouble(0);

            setReferenceDensities(regionIdx, rhoRefO, rhoRefG, rhoRefW);

            // determine the molar masses of the components
            Scalar p = 1.01325e5; // surface pressure, [Pa]
            Scalar T = 273.15 + 15.56; // surface temperature, [K]
            Scalar MO = 175e-3; // [kg/mol]
            Scalar MG = Opm::Constants<Scalar>::R*T*rhoRefG / p; // [kg/mol], consequence of the ideal gas law
            Scalar MW = 18.0e-3; // [kg/mol]
            // TODO (?): the molar mass of the components can possibly specified
            // explicitly in the deck.
            setMolarMasses(regionIdx, MO, MG, MW);

            const auto& pvdgTable = pvdgTables.getTable<PvdgTable>(regionIdx);

            // say 99.97% of all time: "premature optimization is the root of all
            // evil". Eclipse does this "optimization" for apparently no good reason!
            std::vector<Scalar> invB(pvdgTable.numRows());
            const auto& Bg = pvdgTable.getFormationFactorColumn();
            for (unsigned i = 0; i < Bg.size(); ++ i) {
                invB[i] = 1.0/Bg[i];
            }

            size_t numSamples = invB.size();
            inverseGasB_[regionIdx].setXYArrays(numSamples, pvdgTable.getPressureColumn(), invB);
            gasMu_[regionIdx].setXYArrays(numSamples, pvdgTable.getPressureColumn(), pvdgTable.getViscosityColumn());
        }

        initEnd();
    }
Пример #9
0
    /*!
     * \brief Implement the temperature part of the gas PVT properties.
     */
    void initFromDeck(DeckConstPtr deck,
                      EclipseStateConstPtr eclState)
    {
        //////
        // initialize the isothermal part
        //////
        isothermalPvt_ = new IsothermalPvt;
        isothermalPvt_->initFromDeck(deck, eclState);

        //////
        // initialize the thermal part
        //////
        auto tables = eclState->getTableManager();

        enableThermalDensity_ = deck->hasKeyword("TREF");
        enableThermalViscosity_ = deck->hasKeyword("GASVISCT");

        unsigned numRegions = isothermalPvt_->numRegions();
        setNumRegions(numRegions);

        // viscosity
        if (enableThermalViscosity_) {
            const auto& gasvisctTables = tables->getGasvisctTables();
            Opm::DeckKeywordConstPtr viscrefKeyword = deck->getKeyword("VISCREF");
            int gasCompIdx = deck->getKeyword("GCOMPIDX")->getRecord(0)->getItem("GAS_COMPONENT_INDEX")->getInt(0) - 1;
            std::string gasvisctColumnName = "Viscosity"+std::to_string(static_cast<long long>(gasCompIdx));

            for (unsigned regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                const auto& T = gasvisctTables[regionIdx].getColumn("Temperature").vectorCopy();
                const auto& mu = gasvisctTables[regionIdx].getColumn(gasvisctColumnName).vectorCopy();
                gasvisctCurves_[regionIdx].setXYContainers(T, mu);
            }
        }

        // quantities required for density. note that we just always use the values
        // for the first EOS. (since EOS != PVT region.)
        refTemp_ = 0.0;
        if (enableThermalDensity_) {
            refTemp_ = deck->getKeyword("TREF")->getRecord(0)->getItem("TEMPERATURE")->getSIDouble(0);
        }
    }
Пример #10
0
    void restorePressureData(const ecl_file_type* file,
                             EclipseStateConstPtr eclipse_state,
                             int numcells,
                             SimulatorState& simulator_state) {
        const char* pressure = "PRESSURE";

        if (ecl_file_has_kw(file , pressure)) {

            ecl_kw_type* pressure_kw = ecl_file_iget_named_kw(file, pressure, 0);

            if (ecl_kw_get_size(pressure_kw) != numcells) {
                throw std::runtime_error("Read of restart file: Could not restore pressure data, length of data from file not equal number of cells");
            }

            float* pressure_data = ecl_kw_get_float_ptr(pressure_kw);
            const double deck_pressure_unit = (eclipse_state->getDeckUnitSystem().getType() == UnitSystem::UNIT_TYPE_METRIC) ? Opm::unit::barsa : Opm::unit::psia;
            for (size_t index = 0; index < simulator_state.pressure().size(); ++index) {
                simulator_state.pressure()[index] = unit::convert::from((double)pressure_data[index], deck_pressure_unit);
            }
        } else {
            throw std::runtime_error("Read of restart file: File does not contain PRESSURE data\n");
        }
    }
Пример #11
0
    void RelpermDiagnostics::scaledEndPointsCheck_(DeckConstPtr deck,
                                                   EclipseStateConstPtr eclState,
                                                   const GridT& grid)
    {
        const int nc = Opm::UgGridHelpers::numCells(grid);
        const auto& global_cell = Opm::UgGridHelpers::globalCell(grid);
        const auto dims = Opm::UgGridHelpers::cartDims(grid);
        const auto& compressedToCartesianIdx = Opm::compressedToCartesian(nc, global_cell);
        scaledEpsInfo_.resize(nc);
        EclEpsGridProperties epsGridProperties;
        epsGridProperties.initFromDeck(deck, eclState, /*imbibition=*/false);       
        const auto& satnum = eclState->get3DProperties().getIntGridProperty("SATNUM");
        
        const std::string tag = "Scaled endpoints";
        for (int c = 0; c < nc; ++c) {
            const int cartIdx = compressedToCartesianIdx[c];
            const std::string satnumIdx = std::to_string(satnum.iget(cartIdx));
            std::array<int, 3> ijk;
            ijk[0] = cartIdx % dims[0];
            ijk[1] = (cartIdx / dims[0]) % dims[1];
            ijk[2] = cartIdx / dims[0] / dims[1];
            const std::string cellIdx = "(" + std::to_string(ijk[0]) + ", " + 
                                   std::to_string(ijk[1]) + ", " +
                                   std::to_string(ijk[2]) + ")";
            scaledEpsInfo_[c].extractScaled(epsGridProperties, cartIdx);

            // SGU <= 1.0 - SWL
            if (scaledEpsInfo_[c].Sgu > (1.0 - scaledEpsInfo_[c].Swl)) {
                const std::string msg = "For scaled endpoints input, cell" + cellIdx + " SATNUM = " + satnumIdx + ", SGU exceed 1.0 - SWL";
                OpmLog::warning(tag, msg);
            }
            
            // SGL <= 1.0 - SWU
            if (scaledEpsInfo_[c].Sgl > (1.0 - scaledEpsInfo_[c].Swu)) {
                const std::string msg = "For scaled endpoints input, cell" + cellIdx + " SATNUM = " + satnumIdx + ", SGL exceed 1.0 - SWU";
                OpmLog::warning(tag, msg);
            }

            if (deck->hasKeyword("SCALECRS") && fluidSystem_ == FluidSystem::BlackOil) {
                // Mobilility check.
                if ((scaledEpsInfo_[c].Sowcr + scaledEpsInfo_[c].Swcr) >= 1.0) {
                    const std::string msg = "For scaled endpoints input, cell" + cellIdx + " SATNUM = " + satnumIdx + ", SOWCR + SWCR exceed 1.0";
                    OpmLog::warning(tag, msg);
                }

                if ((scaledEpsInfo_[c].Sogcr + scaledEpsInfo_[c].Sgcr + scaledEpsInfo_[c].Swl) >= 1.0) {
                    const std::string msg = "For scaled endpoints input, cell" + cellIdx + " SATNUM = " + satnumIdx + ", SOGCR + SGCR + SWL exceed 1.0";
                    OpmLog::warning(tag, msg);
                }
            }
            ///Following rules come from NEXUS.
            if (fluidSystem_ != FluidSystem::WaterGas) {
                if (scaledEpsInfo_[c].Swl > scaledEpsInfo_[c].Swcr) {
                    const std::string msg = "For scaled endpoints input, cell" + cellIdx + " SATNUM = " + satnumIdx + ", SWL > SWCR";
                    OpmLog::warning(tag, msg);
                }

                if (scaledEpsInfo_[c].Swcr > scaledEpsInfo_[c].Sowcr) {
                    const std::string msg = "For scaled endpoints input, cell" + cellIdx + " SATNUM = " + satnumIdx + ", SWCR > SOWCR";
                    OpmLog::warning(tag, msg);
                }
            
                if (scaledEpsInfo_[c].Sowcr > scaledEpsInfo_[c].Swu) {
                    const std::string msg = "For scaled endpoints input, cell" + cellIdx + " SATNUM = " + satnumIdx + ", SOWCR > SWU";
                    OpmLog::warning(tag, msg);
                }
            }

            if (fluidSystem_ != FluidSystem::OilWater) {
                if (scaledEpsInfo_[c].Sgl > scaledEpsInfo_[c].Sgcr) {
                    const std::string msg = "For scaled endpoints input, cell" + cellIdx + " SATNUM = " + satnumIdx + ", SGL > SGCR";
                    OpmLog::warning(tag, msg);
                }
            }

            if (fluidSystem_ != FluidSystem::BlackOil) {
                if (scaledEpsInfo_[c].Sgcr > scaledEpsInfo_[c].Sogcr) {
                    const std::string msg = "For scaled endpoints input, cell" + cellIdx + " SATNUM = " + satnumIdx + ", SGCR > SOGCR";
                    OpmLog::warning(tag, msg);
                }

                if (scaledEpsInfo_[c].Sogcr > scaledEpsInfo_[c].Sgu) {
                    const std::string msg = "For scaled endpoints input, cell" + cellIdx + " SATNUM = " + satnumIdx + ", SOGCR > SGU";
                    OpmLog::warning(tag, msg);
                }
            }
        } 
    }
Пример #12
0
SolventPropsAdFromDeck::SolventPropsAdFromDeck(DeckConstPtr deck,
                                                     EclipseStateConstPtr eclState,
                                                     const int number_of_cells,
                                                     const int* global_cell)
{
    if (deck->hasKeyword("SOLVENT")) {
        // retrieve the cell specific PVT table index from the deck
        // and using the grid...
        extractPvtTableIndex(cellPvtRegionIdx_, eclState, number_of_cells, global_cell);
        extractTableIndex("SATNUM", eclState, number_of_cells, global_cell, cellSatNumRegionIdx_);

        // surface densities
        if (deck->hasKeyword("SDENSITY")) {
            const auto& densityKeyword = deck->getKeyword("SDENSITY");
            int numRegions = densityKeyword.size();
            solvent_surface_densities_.resize(numRegions);
            for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                solvent_surface_densities_[regionIdx]
                        = densityKeyword.getRecord(regionIdx).getItem("SOLVENT_DENSITY").getSIDouble(0);
            }
        } else {
            OPM_THROW(std::runtime_error, "SDENSITY must be specified in SOLVENT runs\n");
        }

        auto tables = eclState->getTableManager();
        // pvt
        const TableContainer& pvdsTables = tables->getPvdsTables();
        if (!pvdsTables.empty()) {

            int numRegions = pvdsTables.size();
            // resize the attributes of the object
            b_.resize(numRegions);
            viscosity_.resize(numRegions);
            inverseBmu_.resize(numRegions);

            for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                const Opm::PvdsTable& pvdsTable = pvdsTables.getTable<PvdsTable>(regionIdx);

                const auto& press = pvdsTable.getPressureColumn();
                const auto& b = pvdsTable.getFormationFactorColumn();
                const auto& visc = pvdsTable.getViscosityColumn();

                const int sz = b.size();
                std::vector<double> inverseBmu(sz);
                std::vector<double> inverseB(sz);
                for (int i = 0; i < sz; ++i) {
                    inverseB[i] = 1.0 / b[i];
                    inverseBmu[i] = 1.0 / (b[i] * visc[i]);
                }

                b_[regionIdx] = NonuniformTableLinear<double>(press, inverseB);
                viscosity_[regionIdx] = NonuniformTableLinear<double>(press, visc);
                inverseBmu_[regionIdx] = NonuniformTableLinear<double>(press, inverseBmu);
            }
        } else {
            OPM_THROW(std::runtime_error, "PVDS must be specified in SOLVENT runs\n");
        }

        const TableContainer& ssfnTables = tables->getSsfnTables();
        // relative permeabilty multiplier
        if (!ssfnTables.empty()) {

            int numRegions = ssfnTables.size();

            // resize the attributes of the object
            krg_.resize(numRegions);
            krs_.resize(numRegions);
            for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                const Opm::SsfnTable& ssfnTable = ssfnTables.getTable<SsfnTable>(regionIdx);

                // Copy data
                const auto& solventFraction = ssfnTable.getSolventFractionColumn();
                const auto& krg = ssfnTable.getGasRelPermMultiplierColumn();
                const auto& krs = ssfnTable.getSolventRelPermMultiplierColumn();

                krg_[regionIdx] = NonuniformTableLinear<double>(solventFraction, krg);
                krs_[regionIdx] = NonuniformTableLinear<double>(solventFraction, krs);
            }

        } else {
            OPM_THROW(std::runtime_error, "SSFN must be specified in SOLVENT runs\n");
        }


        if (deck->hasKeyword("MISCIBLE") ) {


            // retrieve the cell specific Misc table index from the deck
            // and using the grid...
            extractTableIndex("MISCNUM", eclState, number_of_cells, global_cell, cellMiscRegionIdx_);

            // misicible hydrocabon relative permeability wrt water
            const TableContainer& sof2Tables = tables->getSof2Tables();
            if (!sof2Tables.empty()) {

                int numRegions = sof2Tables.size();

                // resize the attributes of the object
                krn_.resize(numRegions);
                for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                    const Opm::Sof2Table& sof2Table = sof2Tables.getTable<Sof2Table>(regionIdx);

                    // Copy data
                    // Sn = So + Sg + Ss;
                    const auto& sn = sof2Table.getSoColumn();
                    const auto& krn = sof2Table.getKroColumn();

                    krn_[regionIdx] = NonuniformTableLinear<double>(sn, krn);
                }

            } else {
                OPM_THROW(std::runtime_error, "SOF2 must be specified in MISCIBLE (SOLVENT) runs\n");
            }

            const TableContainer& miscTables = tables->getMiscTables();
            if (!miscTables.empty()) {

                int numRegions = miscTables.size();

                // resize the attributes of the object
                misc_.resize(numRegions);
                for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                    const Opm::MiscTable& miscTable = miscTables.getTable<MiscTable>(regionIdx);

                    // Copy data
                    // solventFraction = Ss / (Ss + Sg);
                    const auto& solventFraction = miscTable.getSolventFractionColumn();
                    const auto& misc = miscTable.getMiscibilityColumn();

                    misc_[regionIdx] = NonuniformTableLinear<double>(solventFraction, misc);

                }
            } else {
                OPM_THROW(std::runtime_error, "MISC must be specified in MISCIBLE (SOLVENT) runs\n");
            }

            const TableContainer& pmiscTables = tables->getPmiscTables();
            if (!pmiscTables.empty()) {

                int numRegions = pmiscTables.size();

                // resize the attributes of the object
                pmisc_.resize(numRegions);
                for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                    const Opm::PmiscTable& pmiscTable = pmiscTables.getTable<PmiscTable>(regionIdx);

                    // Copy data
                    const auto& po = pmiscTable.getOilPhasePressureColumn();
                    const auto& pmisc = pmiscTable.getMiscibilityColumn();

                    pmisc_[regionIdx] = NonuniformTableLinear<double>(po, pmisc);

                }
            }

            // miscible relative permeability multipleiers
            const TableContainer& msfnTables = tables->getMsfnTables();
            if (!msfnTables.empty()) {

                int numRegions = msfnTables.size();

                // resize the attributes of the object
                mkrsg_.resize(numRegions);
                mkro_.resize(numRegions);
                for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                    const Opm::MsfnTable& msfnTable = msfnTables.getTable<MsfnTable>(regionIdx);

                    // Copy data
                    // Ssg = Ss + Sg;
                    const auto& Ssg = msfnTable.getGasPhaseFractionColumn();
                    const auto& krsg = msfnTable.getGasSolventRelpermMultiplierColumn();
                    const auto& kro = msfnTable.getOilRelpermMultiplierColumn();

                    mkrsg_[regionIdx] = NonuniformTableLinear<double>(Ssg, krsg);
                    mkro_[regionIdx] = NonuniformTableLinear<double>(Ssg, kro);

                }
            }

            const TableContainer& sorwmisTables = tables->getSorwmisTables();
            if (!sorwmisTables.empty()) {

                int numRegions = sorwmisTables.size();

                // resize the attributes of the object
                sorwmis_.resize(numRegions);
                for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                    const Opm::SorwmisTable& sorwmisTable = sorwmisTables.getTable<SorwmisTable>(regionIdx);

                    // Copy data
                    const auto& sw = sorwmisTable.getWaterSaturationColumn();
                    const auto& sorwmis = sorwmisTable.getMiscibleResidualOilColumn();

                    sorwmis_[regionIdx] = NonuniformTableLinear<double>(sw, sorwmis);
                }
            }

            const TableContainer& sgcwmisTables = tables->getSgcwmisTables();
            if (!sgcwmisTables.empty()) {

                int numRegions = sgcwmisTables.size();

                // resize the attributes of the object
                sgcwmis_.resize(numRegions);
                for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                    const Opm::SgcwmisTable& sgcwmisTable = sgcwmisTables.getTable<SgcwmisTable>(regionIdx);

                    // Copy data
                    const auto& sw = sgcwmisTable.getWaterSaturationColumn();
                    const auto& sgcwmis = sgcwmisTable.getMiscibleResidualGasColumn();

                    sgcwmis_[regionIdx] = NonuniformTableLinear<double>(sw, sgcwmis);
                }
            }

            if (deck->hasKeyword("TLMIXPAR")) {
                const int numRegions = deck->getKeyword("TLMIXPAR").size();

                // resize the attributes of the object
                mix_param_viscosity_.resize(numRegions);
                mix_param_density_.resize(numRegions);
                for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                    const auto& tlmixparRecord = deck->getKeyword("TLMIXPAR").getRecord(regionIdx);
                    const auto& mix_params_viscosity = tlmixparRecord.getItem("TL_VISCOSITY_PARAMETER").getSIDoubleData();
                    mix_param_viscosity_[regionIdx] = mix_params_viscosity[0];
                    const auto& mix_params_density = tlmixparRecord.getItem("TL_DENSITY_PARAMETER").getSIDoubleData();
                    const int numDensityItems = mix_params_density.size();
                    if (numDensityItems == 0) {
                        mix_param_density_[regionIdx] = mix_param_viscosity_[regionIdx];
                    } else if (numDensityItems == 1) {
                        mix_param_density_[regionIdx] = mix_params_density[0];
                    } else {
                        OPM_THROW(std::runtime_error, "Only one value can be entered for the TL parameter pr MISC region.");
                    }
                }
            }

        }
    }

}
Пример #13
0
// ----------------- Main program -----------------
int
main(int argc, char** argv)
try
{
    using namespace Opm;

    std::cout << "\n================    Test program for weakly compressible two-phase flow     ===============\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");
    EclipseStateConstPtr eclipseState;
    std::unique_ptr<GridManager> grid;
    std::unique_ptr<BlackoilPropertiesInterface> props;
    std::unique_ptr<RockCompressibility> rock_comp;

    ParserPtr parser(new Opm::Parser());
    Opm::DeckConstPtr deck;

    BlackoilState state;
    // bool check_well_controls = false;
    // int max_well_control_iterations = 0;
    double gravity[3] = { 0.0 };
    if (use_deck) {
        ParseMode parseMode;
        std::string deck_filename = param.get<std::string>("deck_filename");
        deck = parser->parseFile(deck_filename , parseMode);
        eclipseState.reset(new EclipseState(deck, parseMode));

        // Grid init
        grid.reset(new GridManager(deck));
        // Rock and fluid init
        props.reset(new BlackoilPropertiesFromDeck(deck, eclipseState, *grid->c_grid(), param));
        // check_well_controls = param.getDefault("check_well_controls", false);
        // max_well_control_iterations = param.getDefault("max_well_control_iterations", 10);
        // Rock compressibility.
        rock_comp.reset(new RockCompressibility(deck, eclipseState));
        // Gravity.
        gravity[2] = deck->hasKeyword("NOGRAV") ? 0.0 : unit::gravity;
        // Init state variables (saturation and pressure).
        if (param.has("init_saturation")) {
            initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
        } else {
            initStateFromDeck(*grid->c_grid(), *props, deck, gravity[2], state);
        }
        initBlackoilSurfvol(*grid->c_grid(), *props, state);
    } 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));
        // Rock and fluid init.
        props.reset(new BlackoilPropertiesBasic(param, grid->c_grid()->dimensions, grid->c_grid()->number_of_cells));
        // Rock compressibility.
        rock_comp.reset(new RockCompressibility(param));
        // Gravity.
        gravity[2] = param.getDefault("gravity", 0.0);
        // Init state variables (saturation and pressure).
        initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
        initBlackoilSurfvol(*grid->c_grid(), *props, state);
    }

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

    // Initialising src
    int num_cells = grid->c_grid()->number_of_cells;
    std::vector<double> src(num_cells, 0.0);
    if (use_deck) {
        // Do nothing, wells will be the driving force, not source terms.
    } else {
        // Compute pore volumes, in order to enable specifying injection rate
        // terms of total pore volume.
        std::vector<double> porevol;
        if (rock_comp->isActive()) {
            computePorevolume(*grid->c_grid(), props->porosity(), *rock_comp, state.pressure(), porevol);
        } else {
            computePorevolume(*grid->c_grid(), props->porosity(), porevol);
        }
        const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
        const double default_injection = use_gravity ? 0.0 : 0.1;
        const double flow_per_sec = param.getDefault<double>("injected_porevolumes_per_day", default_injection)
            *tot_porevol_init/unit::day;
        src[0] = flow_per_sec;
        src[num_cells - 1] = -flow_per_sec;
    }

    // Boundary conditions.
    FlowBCManager bcs;
    if (param.getDefault("use_pside", false)) {
        int pside = param.get<int>("pside");
        double pside_pressure = param.get<double>("pside_pressure");
        bcs.pressureSide(*grid->c_grid(), FlowBCManager::Side(pside), pside_pressure);
    }

    // Linear solver.
    LinearSolverFactory linsolver(param);

    // Write parameters used for later reference.
    bool output = param.getDefault("output", true);
    std::ofstream epoch_os;
    std::string output_dir;
    if (output) {
        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);
        }
        std::string filename = output_dir + "/epoch_timing.param";
        epoch_os.open(filename.c_str(), std::fstream::trunc | std::fstream::out);
        // open file to clean it. The file is appended to in SimulatorTwophase
        filename = output_dir + "/step_timing.param";
        std::fstream step_os(filename.c_str(), std::fstream::trunc | std::fstream::out);
        step_os.close();
        param.writeParam(output_dir + "/simulation.param");
    }


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

    SimulatorReport rep;
    if (!use_deck) {
        // Simple simulation without a deck.
        WellsManager wells; // no wells.
        SimulatorCompressibleTwophase simulator(param,
                                                *grid->c_grid(),
                                                *props,
                                                rock_comp->isActive() ? rock_comp.get() : 0,
                                                wells,
                                                src,
                                                bcs.c_bcs(),
                                                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;
        SimulatorTimer simtimer;
        // Use timer for last epoch to obtain total time.
        Opm::TimeMapPtr timeMap(new Opm::TimeMap(deck));
        simtimer.init(timeMap);
        const double total_time = simtimer.totalTime();
        for (size_t reportStepIdx = 0; reportStepIdx < timeMap->numTimesteps(); ++reportStepIdx) {
            simtimer.setCurrentStepNum(step);
            simtimer.setTotalTime(total_time);

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

            // Create new wells, well_state
            WellsManager wells(eclipseState , reportStepIdx , *grid->c_grid(), props->permeability());
            // @@@ 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.
            SimulatorCompressibleTwophase simulator(param,
                                                    *grid->c_grid(),
                                                    *props,
                                                    rock_comp->isActive() ? rock_comp.get() : 0,
                                                    wells,
                                                    src,
                                                    bcs.c_bcs(),
                                                    linsolver,
                                                    grav);
            if (reportStepIdx == 0) {
                warnIfUnusedParams(param);
            }
            SimulatorReport epoch_rep = simulator.run(simtimer, state, well_state);
            if (output) {
                epoch_rep.reportParam(epoch_os);
            }
            // 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);

    if (output) {
        std::string filename = output_dir + "/walltime.param";
        std::fstream tot_os(filename.c_str(),std::fstream::trunc | std::fstream::out);
        rep.reportParam(tot_os);
    }

}
catch (const std::exception &e) {
    std::cerr << "Program threw an exception: " << e.what() << "\n";
    throw;
}
Пример #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<EclipseGridParser> deck;
    boost::scoped_ptr<GridManager> grid;
    boost::scoped_ptr<BlackoilPropertiesInterface> props;
    boost::scoped_ptr<RockCompressibility> rock_comp;
    EclipseStateConstPtr eclipseState;
    PolymerBlackoilState state;
    Opm::PolymerProperties poly_props;
    // 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");
        ParserPtr parser(new Opm::Parser());
        eclipseState.reset(new Opm::EclipseState(parser->parseFile(deck_filename)));

        deck.reset(new EclipseGridParser(deck_filename));
        // Grid init
        grid.reset(new GridManager(*deck));
        // Rock and fluid init
        props.reset(new BlackoilPropertiesFromDeck(*deck, *grid->c_grid()));
        // check_well_controls = param.getDefault("check_well_controls", false);
        // max_well_control_iterations = param.getDefault("max_well_control_iterations", 10);
        // Rock compressibility.
        rock_comp.reset(new RockCompressibility(*deck));
        // Gravity.
        gravity[2] = deck->hasField("NOGRAV") ? 0.0 : unit::gravity;
        // Init state variables (saturation and pressure).
        if (param.has("init_saturation")) {
            initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
        } else {
            initStateFromDeck(*grid->c_grid(), *props, *deck, gravity[2], state);
        }
        initBlackoilSurfvol(*grid->c_grid(), *props, state);
        // Init polymer properties.
        poly_props.readFromDeck(*deck);
    } 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));
        // Rock and fluid init.
        props.reset(new BlackoilPropertiesBasic(param, grid->c_grid()->dimensions, grid->c_grid()->number_of_cells));
        // Rock compressibility.
        rock_comp.reset(new RockCompressibility(param));
        // Gravity.
        gravity[2] = param.getDefault("gravity", 0.0);
        // Init state variables (saturation and pressure).
        initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
        initBlackoilSurfvol(*grid->c_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 < grid->c_grid()->number_of_cells; ++cell) {
                double smin[2], smax[2];
                props->satRange(1, &cell, smin, smax);
                if (state.saturation()[2*cell] > 0.5*(smin[0] + smax[0])) {
                    state.concentration()[cell] = poly_init;
                    state.maxconcentration()[cell] = poly_init;
                } else {
                    state.saturation()[2*cell + 0] = 0.;
                    state.saturation()[2*cell + 1] = 1.;
                    state.concentration()[cell] = 0.;
                    state.maxconcentration()[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;
        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);
    }

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

    // Initialising src
    int num_cells = grid->c_grid()->number_of_cells;
    std::vector<double> src(num_cells, 0.0);
    if (use_deck) {
        // Do nothing, wells will be the driving force, not source terms.
    } else {
        // Compute pore volumes, in order to enable specifying injection rate
        // terms of total pore volume.
        std::vector<double> porevol;
        if (rock_comp->isActive()) {
            computePorevolume(*grid->c_grid(), props->porosity(), *rock_comp, state.pressure(), porevol);
        } else {
            computePorevolume(*grid->c_grid(), props->porosity(), porevol);
        }
        const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
        const double default_injection = use_gravity ? 0.0 : 0.1;
        const double flow_per_sec = param.getDefault<double>("injected_porevolumes_per_day", default_injection)
            *tot_porevol_init/unit::day;
        src[0] = flow_per_sec;
        src[num_cells - 1] = -flow_per_sec;
    }

    // Boundary conditions.
    FlowBCManager bcs;
    if (param.getDefault("use_pside", false)) {
        int pside = param.get<int>("pside");
        double pside_pressure = param.get<double>("pside_pressure");
        bcs.pressureSide(*grid->c_grid(), FlowBCManager::Side(pside), pside_pressure);
    }

    // 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"
              << "                        (number of epochs: "
              << (use_deck ? deck->numberOfEpochs() : 1) << ")\n\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,
                                               src,
                                               bcs.c_bcs(),
                                               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;
        SimulatorTimer simtimer;
        // Use timer for last epoch to obtain total time.
        deck->setCurrentEpoch(deck->numberOfEpochs() - 1);
        simtimer.init(*deck);
        const double total_time = simtimer.totalTime();
        // Check for WPOLYMER presence in last epoch to decide
        // polymer injection control type.
        const bool use_wpolymer = deck->hasField("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 (int epoch = 0; epoch < deck->numberOfEpochs(); ++epoch) {
            // Set epoch index.
            deck->setCurrentEpoch(epoch);

            // Update the timer.
            if (deck->hasField("TSTEP")) {
                simtimer.init(*deck);
            } else {
                if (epoch != 0) {
                    OPM_THROW(std::runtime_error, "No TSTEP in deck for epoch " << epoch);
                }
                simtimer.init(param);
            }
            simtimer.setCurrentStepNum(step);
            simtimer.setTotalTime(total_time);

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

            // Create new wells, polymer inflow controls.
            WellsManager wells(eclipseState , epoch , *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(*deck, *wells.c_wells(), props->numCells()));
            } 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 epoch,
            // since number of wells may change etc.
            if (epoch == 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,
                                                   src,
                                                   bcs.c_bcs(),
                                                   linsolver,
                                                   grav);
            if (epoch == 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;
}
Пример #15
0
void computeMaxDp(std::map<std::pair<int, int>, double>& maxDp,
                  const DeckConstPtr& deck,
                  EclipseStateConstPtr eclipseState,
                  const Grid& grid,
                  const BlackoilState& initialState,
                  const BlackoilPropertiesFromDeck& props,
                  const double gravity)
{

    const PhaseUsage& pu = props.phaseUsage();

    const auto& eqlnum = eclipseState->get3DProperties().getIntGridProperty("EQLNUM");
    const auto& eqlnumData = eqlnum.getData();

    const int numPhases = initialState.numPhases();
    const int numCells = UgGridHelpers::numCells(grid);
    const int numPvtRegions = deck->getKeyword("TABDIMS").getRecord(0).getItem("NTPVT").get< int >(0);

    // retrieve the minimum (residual!?) and the maximum saturations for all cells
    std::vector<double> minSat(numPhases*numCells);
    std::vector<double> maxSat(numPhases*numCells);
    std::vector<int> allCells(numCells);
    for (int cellIdx = 0; cellIdx < numCells; ++cellIdx) {
        allCells[cellIdx] = cellIdx;
    }
    props.satRange(numCells, allCells.data(), minSat.data(), maxSat.data());

    // retrieve the surface densities
    std::vector<std::vector<double> > surfaceDensity(numPvtRegions);
    const auto& densityKw = deck->getKeyword("DENSITY");
    for (int regionIdx = 0; regionIdx < numPvtRegions; ++regionIdx) {
        surfaceDensity[regionIdx].resize(numPhases);

        if (pu.phase_used[BlackoilPhases::Aqua]) {
            const int wpos = pu.phase_pos[BlackoilPhases::Aqua];
            surfaceDensity[regionIdx][wpos] =
                densityKw.getRecord(regionIdx).getItem("WATER").getSIDouble(0);
        }

        if (pu.phase_used[BlackoilPhases::Liquid]) {
            const int opos = pu.phase_pos[BlackoilPhases::Liquid];
            surfaceDensity[regionIdx][opos] =
                densityKw.getRecord(regionIdx).getItem("OIL").getSIDouble(0);
        }

        if (pu.phase_used[BlackoilPhases::Vapour]) {
            const int gpos = pu.phase_pos[BlackoilPhases::Vapour];
            surfaceDensity[regionIdx][gpos] =
                densityKw.getRecord(regionIdx).getItem("GAS").getSIDouble(0);
        }
    }

    // retrieve the PVT region of each cell. note that we need c++ instead of
    // Fortran indices.
    const int* gc = UgGridHelpers::globalCell(grid);
    std::vector<int> pvtRegion(numCells);
    const auto& cartPvtRegion = eclipseState->get3DProperties().getIntGridProperty("PVTNUM").getData();
    for (int cellIdx = 0; cellIdx < numCells; ++cellIdx) {
        const int cartCellIdx = gc ? gc[cellIdx] : cellIdx;
        pvtRegion[cellIdx] = std::max(0, cartPvtRegion[cartCellIdx] - 1);
    }

    // compute the initial "phase presence" of each cell (required to calculate
    // the inverse formation volume factors
    std::vector<PhasePresence> cond(numCells);
    for (int cellIdx = 0; cellIdx < numCells; ++cellIdx) {
        if (pu.phase_used[BlackoilPhases::Aqua]) {
            const double sw = initialState.saturation()[numPhases*cellIdx + pu.phase_pos[BlackoilPhases::Aqua]];
            if (sw > 0.0) {
                cond[cellIdx].setFreeWater();
            }
        }

        if (pu.phase_used[BlackoilPhases::Liquid]) {
            const double so = initialState.saturation()[numPhases*cellIdx + pu.phase_pos[BlackoilPhases::Liquid]];
            if (so > 0.0) {
                cond[cellIdx].setFreeOil();
            }
        }

        if (pu.phase_used[BlackoilPhases::Vapour]) {
            const double sg = initialState.saturation()[numPhases*cellIdx + pu.phase_pos[BlackoilPhases::Vapour]];
            if (sg > 0.0) {
                cond[cellIdx].setFreeGas();
            }
        }
    }

    // calculate the initial fluid densities for the gravity correction.
    std::vector<std::vector<double>> rho(numPhases);
    for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
        rho[phaseIdx].resize(numCells);
    }

    // compute the capillary pressures of the active phases
    std::vector<double> capPress(numCells*numPhases);
    std::vector<int> cellIdxArray(numCells);
    for (int cellIdx = 0; cellIdx < numCells; ++ cellIdx) {
        cellIdxArray[cellIdx] = cellIdx;
    }
    props.capPress(numCells, initialState.saturation().data(), cellIdxArray.data(), capPress.data(), NULL);

    // compute the absolute pressure of each active phase: for some reason, E100
    // defines the capillary pressure for the water phase as p_o - p_w while it
    // uses p_g - p_o for the gas phase. (it would be more consistent to use the
    // oil pressure as reference for both the other phases.) probably this is
    // done to always have a positive number for the capillary pressure (as long
    // as the medium is hydrophilic)
    std::vector<std::vector<double> > phasePressure(numPhases);
    for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
        phasePressure[phaseIdx].resize(numCells);
    }

    for (int cellIdx = 0; cellIdx < numCells; ++ cellIdx) {
        // we currently hard-code the oil phase as the reference phase!
        assert(pu.phase_used[BlackoilPhases::Liquid]);

        const int opos = pu.phase_pos[BlackoilPhases::Liquid];
        phasePressure[opos][cellIdx] = initialState.pressure()[cellIdx];

        if (pu.phase_used[BlackoilPhases::Aqua]) {
            const int wpos = pu.phase_pos[BlackoilPhases::Aqua];
            phasePressure[wpos][cellIdx] =
                initialState.pressure()[cellIdx]
                + (capPress[cellIdx*numPhases + opos] - capPress[cellIdx*numPhases + wpos]);
        }

        if (pu.phase_used[BlackoilPhases::Vapour]) {
            const int gpos = pu.phase_pos[BlackoilPhases::Vapour];
            phasePressure[gpos][cellIdx] =
                initialState.pressure()[cellIdx]
                + (capPress[cellIdx*numPhases + gpos] - capPress[cellIdx*numPhases + opos]);
        }
    }

    // calculate the densities of the active phases for each cell
    if (pu.phase_used[BlackoilPhases::Aqua]) {
        const int wpos = pu.phase_pos[BlackoilPhases::Aqua];
        const auto& pvtw = props.waterPvt();
        for (int cellIdx = 0; cellIdx < numCells; ++ cellIdx) {
            int pvtRegionIdx = pvtRegion[cellIdx];

            double T = initialState.temperature()[cellIdx];
            double p = phasePressure[wpos][cellIdx];
            double b = pvtw.inverseFormationVolumeFactor(pvtRegionIdx, T, p);

            rho[wpos][cellIdx] = surfaceDensity[pvtRegionIdx][wpos]*b;
        }
    }

    if (pu.phase_used[BlackoilPhases::Liquid]) {
        const int opos = pu.phase_pos[BlackoilPhases::Liquid];
        const auto& pvto = props.oilPvt();
        for (int cellIdx = 0; cellIdx < numCells; ++ cellIdx) {
            int pvtRegionIdx = pvtRegion[cellIdx];

            double T = initialState.temperature()[cellIdx];
            double p = phasePressure[opos][cellIdx];
            double Rs = initialState.gasoilratio()[cellIdx];
            double RsSat = pvto.saturatedGasDissolutionFactor(pvtRegionIdx, T, p);

            double b;
            if (Rs >= RsSat) {
                b = pvto.saturatedInverseFormationVolumeFactor(pvtRegionIdx, T, p);
            }
            else {
                b = pvto.inverseFormationVolumeFactor(pvtRegionIdx, T, p, Rs);
            }

            rho[opos][cellIdx] = surfaceDensity[pvtRegionIdx][opos]*b;
            if (pu.phase_used[BlackoilPhases::Vapour]) {
                int gpos = pu.phase_pos[BlackoilPhases::Vapour];
                rho[opos][cellIdx] += surfaceDensity[pvtRegionIdx][gpos]*Rs*b;
            }
        }
    }

    if (pu.phase_used[BlackoilPhases::Vapour]) {
        const int gpos = pu.phase_pos[BlackoilPhases::Vapour];
        const auto& pvtg = props.gasPvt();
        for (int cellIdx = 0; cellIdx < numCells; ++ cellIdx) {
            int pvtRegionIdx = pvtRegion[cellIdx];

            double T = initialState.temperature()[cellIdx];
            double p = phasePressure[gpos][cellIdx];
            double Rv = initialState.rv()[cellIdx];
            double RvSat = pvtg.saturatedOilVaporizationFactor(pvtRegionIdx, T, p);

            double b;
            if (Rv >= RvSat) {
                b = pvtg.saturatedInverseFormationVolumeFactor(pvtRegionIdx, T, p);
            }
            else {
                b = pvtg.inverseFormationVolumeFactor(pvtRegionIdx, T, p, Rv);
            }
            rho[gpos][cellIdx] = surfaceDensity[pvtRegionIdx][gpos]*b;
            if (pu.phase_used[BlackoilPhases::Liquid]) {
                int opos = pu.phase_pos[BlackoilPhases::Liquid];
                rho[gpos][cellIdx] += surfaceDensity[pvtRegionIdx][opos]*Rv*b;
            }
        }
    }

    // Calculate the maximum pressure potential difference between all PVT region
    // transitions of the initial solution.
    const int num_faces = UgGridHelpers::numFaces(grid);
    const auto& fc = UgGridHelpers::faceCells(grid);
    for (int face = 0; face < num_faces; ++face) {
        const int c1 = fc(face, 0);
        const int c2 = fc(face, 1);
        if (c1 < 0 || c2 < 0) {
            // Boundary face, skip this.
            continue;
        }
        const int gc1 = (gc == 0) ? c1 : gc[c1];
        const int gc2 = (gc == 0) ? c2 : gc[c2];
        const int eq1 = eqlnumData[gc1];
        const int eq2 = eqlnumData[gc2];

        if (eq1 == eq2) {
            // not an equilibration region boundary. skip this.
            continue;
        }

        // update the maximum pressure potential difference between the two
        // regions
        const auto barrierId = std::make_pair(std::min(eq1, eq2), std::max(eq1, eq2));
        if (maxDp.count(barrierId) == 0) {
            maxDp[barrierId] = 0.0;
        }

        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
            const double z1 = UgGridHelpers::cellCenterDepth(grid, c1);
            const double z2 = UgGridHelpers::cellCenterDepth(grid, c2);

            const double rhoAvg = (rho[phaseIdx][c1] + rho[phaseIdx][c2])/2;

            const double s1 = initialState.saturation()[numPhases*c1 + phaseIdx];
            const double s2 = initialState.saturation()[numPhases*c2 + phaseIdx];

            const double sResid1 = minSat[numPhases*c1 + phaseIdx];
            const double sResid2 = minSat[numPhases*c2 + phaseIdx];

            // compute gravity corrected pressure potentials at the average depth
            const double p1 = phasePressure[phaseIdx][c1];
            const double p2 = phasePressure[phaseIdx][c2] + rhoAvg*gravity*(z1 - z2);

            if ((p1 > p2 && s1 > sResid1) || (p2 > p1 && s2 > sResid2))
                maxDp[barrierId] = std::max(maxDp[barrierId], std::abs(p1 - p2));
        }
    }
}
Пример #16
0
    /*!
     * \brief Implement the temperature part of the oil PVT properties.
     */
    void initFromDeck(DeckConstPtr deck,
                      EclipseStateConstPtr eclState)
    {
        //////
        // initialize the isothermal part
        //////
        isothermalPvt_ = new IsothermalPvt;
        isothermalPvt_->initFromDeck(deck, eclState);

        //////
        // initialize the thermal part
        //////
        auto tables = eclState->getTableManager();

        enableThermalDensity_ = deck->hasKeyword("THERMEX1");
        enableThermalViscosity_ = deck->hasKeyword("VISCREF");

        unsigned numRegions = isothermalPvt_->numRegions();
        setNumRegions(numRegions);

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

            assert(oilvisctTables.size() == numRegions);
            assert(viscrefKeyword->size() == numRegions);

            for (unsigned regionIdx = 0; regionIdx < numRegions; ++regionIdx) {
                const auto& TCol = oilvisctTables[regionIdx].getColumn("Temperature").vectorCopy();
                const auto& muCol = oilvisctTables[regionIdx].getColumn("Viscosity").vectorCopy();
                oilvisctCurves_[regionIdx].setXYContainers(TCol, muCol);

                DeckRecordConstPtr 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...
                Scalar Tref = 273.15 + 20;

                // compute the reference viscosity using the isothermal PVT object.
                viscRef_[regionIdx] =
                    isothermalPvt_->viscosity(regionIdx,
                                              Tref,
                                              viscrefPress_[regionIdx],
                                              viscrefRs_[regionIdx]);
            }
        }

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

            // always use the values of the first EOS
            refTemp_ = deck->getKeyword("TREF")->getRecord(0)->getItem("TEMPERATURE")->getSIDouble(oilCompIdx);
            refPress_ = deck->getKeyword("PREF")->getRecord(0)->getItem("PRESSURE")->getSIDouble(oilCompIdx);
            refC_ = deck->getKeyword("CREF")->getRecord(0)->getItem("COMPRESSIBILITY")->getSIDouble(oilCompIdx);
            thermex1_ = deck->getKeyword("THERMEX1")->getRecord(0)->getItem("EXPANSION_COEFF")->getSIDouble(oilCompIdx);
        }
    }
Пример #17
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;
    Opm::DeckConstPtr deck;
    EclipseStateConstPtr eclipseState;
    std::unique_ptr<PolymerBlackoilState> state;
    Opm::PolymerProperties poly_props;
    // 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");
        ParserPtr parser(new Opm::Parser());
        Opm::ParseContext parseContext({{ ParseContext::PARSE_RANDOM_SLASH , InputError::IGNORE }});
        deck = parser->parseFile(deck_filename , parseContext);
        eclipseState.reset(new Opm::EclipseState(deck , parseContext));

        // Grid init
        grid.reset(new GridManager(deck));
        {
            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(deck, 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::TimeMapPtr timeMap(new Opm::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.
            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;
}