/*! * \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); } } }
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, " "); } }
/*! * \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); } }
/*! * \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(); }
/*! * \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)); } } }