/*! * \brief Implement the temperature part of the oil PVT properties. */ void initFromDeck(const Deck& deck, const EclipseState& eclState) { ////// // initialize the isothermal part ////// isothermalPvt_ = new IsothermalPvt; isothermalPvt_->initFromDeck(deck, eclState); ////// // initialize the thermal part ////// const auto& tables = eclState.getTableManager(); enableThermalDensity_ = deck.hasKeyword("OILDENT"); enableThermalViscosity_ = deck.hasKeyword("OILVISCT"); enableInternalEnergy_ = deck.hasKeyword("SPECHEAT"); unsigned numRegions = isothermalPvt_->numRegions(); setNumRegions(numRegions); // viscosity if (deck.hasKeyword("OILVISCT")) { if (!deck.hasKeyword("VISCREF")) throw std::runtime_error("VISCREF is required when OILVISCT is present"); const auto& oilvisctTables = tables.getOilvisctTables(); const auto& 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); const auto& viscrefRecord = viscrefKeyword.getRecord(regionIdx); viscrefPress_[regionIdx] = viscrefRecord.getItem("REFERENCE_PRESSURE").getSIDouble(0); viscrefRs_[regionIdx] = viscrefRecord.getItem("REFERENCE_RS").getSIDouble(0); // temperature used to calculate the reference viscosity [K]. the // value does not really matter if the underlying PVT object really // is isothermal... Scalar Tref = 273.15 + 20; // compute the reference viscosity using the isothermal PVT object. viscRef_[regionIdx] = isothermalPvt_->viscosity(regionIdx, Tref, viscrefPress_[regionIdx], viscrefRs_[regionIdx]); } } // temperature dependence of oil density if (enableThermalDensity_) { const auto& oildentKeyword = deck.getKeyword("OILDENT"); assert(oildentKeyword.size() == numRegions); for (unsigned regionIdx = 0; regionIdx < numRegions; ++regionIdx) { const auto& oildentRecord = oildentKeyword.getRecord(regionIdx); oildentRefTemp_[regionIdx] = oildentRecord.getItem("REFERENCE_TEMPERATURE").getSIDouble(0); oildentCT1_[regionIdx] = oildentRecord.getItem("EXPANSION_COEFF_LINEAR").getSIDouble(0); oildentCT2_[regionIdx] = oildentRecord.getItem("EXPANSION_COEFF_QUADRATIC").getSIDouble(0); } } if (deck.hasKeyword("SPECHEAT")) { // the specific internal energy of liquid oil. be aware that ecl only specifies the // heat capacity (via the SPECHEAT keyword) and we need to integrate it // ourselfs to get the internal energy for (unsigned regionIdx = 0; regionIdx < numRegions; ++regionIdx) { const auto& specheatTable = tables.getSpecheatTables()[regionIdx]; const auto& temperatureColumn = specheatTable.getColumn("TEMPERATURE"); const auto& cvOilColumn = specheatTable.getColumn("CV_OIL"); std::vector<double> uSamples(temperatureColumn.size()); Scalar u = temperatureColumn[0]*cvOilColumn[0]; for (size_t i = 0;; ++i) { uSamples[i] = u; if (i >= temperatureColumn.size() - 1) break; // integrate to the heat capacity from the current sampling point to the next // one. this leads to a quadratic polynomial. Scalar c_v0 = cvOilColumn[i]; Scalar c_v1 = cvOilColumn[i + 1]; Scalar T0 = temperatureColumn[i]; Scalar T1 = temperatureColumn[i + 1]; u += 0.5*(c_v0 + c_v1)*(T1 - T0); } internalEnergyCurves_[regionIdx].setXYContainers(temperatureColumn.vectorCopy(), uSamples); } } }
/*! * \brief Implement the temperature part of the gas PVT properties. */ void initFromDeck(const Deck& deck, const EclipseState& eclState) { ////// // initialize the isothermal part ////// isothermalPvt_ = new IsothermalPvt; isothermalPvt_->initFromDeck(deck, eclState); ////// // initialize the thermal part ////// const auto& tables = eclState.getTableManager(); enableThermalDensity_ = deck.hasKeyword("GASDENT"); enableThermalViscosity_ = deck.hasKeyword("GASVISCT"); enableInternalEnergy_ = deck.hasKeyword("SPECHEAT"); unsigned numRegions = isothermalPvt_->numRegions(); setNumRegions(numRegions); // viscosity if (enableThermalViscosity_) { const auto& gasvisctTables = tables.getGasvisctTables(); int gasCompIdx = deck.getKeyword("GCOMPIDX").getRecord(0).getItem("GAS_COMPONENT_INDEX").get< int >(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); } } // temperature dependence of gas density if (enableThermalDensity_) { const auto& gasdentKeyword = deck.getKeyword("GASDENT"); assert(gasdentKeyword.size() == numRegions); for (unsigned regionIdx = 0; regionIdx < numRegions; ++regionIdx) { const auto& gasdentRecord = gasdentKeyword.getRecord(regionIdx); gasdentRefTemp_[regionIdx] = gasdentRecord.getItem("REFERENCE_TEMPERATURE").getSIDouble(0); gasdentCT1_[regionIdx] = gasdentRecord.getItem("EXPANSION_COEFF_LINEAR").getSIDouble(0); gasdentCT2_[regionIdx] = gasdentRecord.getItem("EXPANSION_COEFF_QUADRATIC").getSIDouble(0); } } if (deck.hasKeyword("SPECHEAT")) { // the specific internal energy of gas. be aware that ecl only specifies the heat capacity // (via the SPECHEAT keyword) and we need to integrate it ourselfs to get the // internal energy for (unsigned regionIdx = 0; regionIdx < numRegions; ++regionIdx) { const auto& specHeatTable = tables.getSpecheatTables()[regionIdx]; const auto& temperatureColumn = specHeatTable.getColumn("TEMPERATURE"); const auto& cvGasColumn = specHeatTable.getColumn("CV_GAS"); std::vector<double> uSamples(temperatureColumn.size()); // the specific enthalpy of vaporization. since ECL does not seem to // feature a proper way to specify this quantity, we use the value for // methane. A proper model would also need to consider the enthalpy // change due to dissolution, i.e. the enthalpies of the gas and oil // phases should depend on the phase composition const Scalar hVap = 480.6e3; // [J / kg] Scalar u = temperatureColumn[0]*cvGasColumn[0] + hVap; for (size_t i = 0;; ++i) { uSamples[i] = u; if (i >= temperatureColumn.size() - 1) break; // integrate to the heat capacity from the current sampling point to the next // one. this leads to a quadratic polynomial. Scalar c_v0 = cvGasColumn[i]; Scalar c_v1 = cvGasColumn[i + 1]; Scalar T0 = temperatureColumn[i]; Scalar T1 = temperatureColumn[i + 1]; u += 0.5*(c_v0 + c_v1)*(T1 - T0); } internalEnergyCurves_[regionIdx].setXYContainers(temperatureColumn.vectorCopy(), uSamples); } } }