Beispiel #1
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);
            }
        }
    }
Beispiel #2
0
    RawKeywordPtr Parser::createRawKeyword(const DeckConstPtr deck, const std::string& filename , size_t lineNR , const std::string& keywordString, bool strictParsing) const {
        if (hasKeyword(keywordString)) {
            ParserKeywordConstPtr parserKeyword = m_parserKeywords.find(keywordString)->second;
            ParserKeywordActionEnum action = parserKeyword->getAction();
            
            if (action == THROW_EXCEPTION)
                throw std::invalid_argument("Parsing terminated by fatal keyword: " + keywordString);
            
            if (parserKeyword->getSizeType() == SLASH_TERMINATED)
                return RawKeywordPtr(new RawKeyword(keywordString , filename , lineNR));
            else {
                size_t targetSize;

                if (parserKeyword->hasFixedSize())
                    targetSize = parserKeyword->getFixedSize();
                else {
                    const std::pair<std::string, std::string> sizeKeyword = parserKeyword->getSizeDefinitionPair();
                    DeckKeywordConstPtr sizeDefinitionKeyword = deck->getKeyword(sizeKeyword.first);
                    DeckItemConstPtr sizeDefinitionItem;
                    {
                        DeckRecordConstPtr record = sizeDefinitionKeyword->getRecord(0);
                        sizeDefinitionItem = record->getItem(sizeKeyword.second);
                    }
                    targetSize = sizeDefinitionItem->getInt(0);
                }
                return RawKeywordPtr(new RawKeyword(keywordString, filename , lineNR , targetSize , parserKeyword->isTableCollection()));
            }
        } else {
            if (strictParsing) {
                throw std::invalid_argument("Keyword " + keywordString + " not recognized ");
            } else {
                return RawKeywordPtr(new RawKeyword(keywordString, filename , lineNR , 0));
            }
        }
    }
 void EclipseState::initTitle(DeckConstPtr deck){
     if (deck->hasKeyword("TITLE")) {
         DeckKeywordConstPtr titleKeyword = deck->getKeyword("TITLE");
         DeckRecordConstPtr record = titleKeyword->getRecord(0);
         DeckItemPtr item = record->getItem(0);
         std::vector<std::string> itemValue = item->getStringData();
         m_title = boost::algorithm::join(itemValue, " ");
     }
 }
Beispiel #4
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);
        }
    }
Beispiel #5
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();
    }
Beispiel #6
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);
        }
    }
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.");
                    }
                }
            }

        }
    }

}
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));
        }
    }
}