diff --git a/opm/autodiff/BlackoilModelBase.hpp b/opm/autodiff/BlackoilModelBase.hpp index ecac81179..bd931a53c 100644 --- a/opm/autodiff/BlackoilModelBase.hpp +++ b/opm/autodiff/BlackoilModelBase.hpp @@ -131,9 +131,20 @@ namespace Opm { struct SimulatorData { SimulatorData(int num_phases); + + enum FipId { + FIP_AQUA = Opm::Phases::Water, + FIP_LIQUID = Opm::Phases::Oil, + FIP_VAPOUR = Opm::Phases::Gas, + FIP_DISSOLVED_GAS = 3, + FIP_VAPORIZED_OIL = 4, + FIP_PV = 5, //< Pore volume + FIP_WEIGHTED_PRESSURE = 6 + }; std::vector rq; - ADB rsSat; - ADB rvSat; + ADB rsSat; // Saturated gas-oil ratio + ADB rvSat; // Saturated oil-gas ratio + std::array fip; }; typedef typename ModelTraits::ReservoirState ReservoirState; diff --git a/opm/autodiff/BlackoilModelBase_impl.hpp b/opm/autodiff/BlackoilModelBase_impl.hpp index d5ab0d3be..87e760bfe 100644 --- a/opm/autodiff/BlackoilModelBase_impl.hpp +++ b/opm/autodiff/BlackoilModelBase_impl.hpp @@ -490,6 +490,7 @@ namespace detail { : rq(num_phases) , rsSat(ADB::null()) , rvSat(ADB::null()) + , fip() { } @@ -2363,21 +2364,18 @@ namespace detail { const ADB pv_mult = poroMult(pressure); const V& pv = geo_.poreVolume(); const int maxnp = Opm::BlackoilPhases::MaxNumPhases; - std::vector fip(5, V::Zero(nc)); for (int phase = 0; phase < maxnp; ++phase) { if (active_[ phase ]) { const int pos = pu.phase_pos[ phase ]; const auto& b = asImpl().fluidReciprocFVF(phase, canonical_phase_pressures[phase], temperature, rs, rv, cond); - fip[phase] = ((pv_mult * b * saturation[pos] * pv).value()); + sd_.fip[phase] = ((pv_mult * b * saturation[pos] * pv).value()); } } if (active_[ Oil ] && active_[ Gas ]) { // Account for gas dissolved in oil and vaporized oil - const int po = pu.phase_pos[Oil]; - const int pg = pu.phase_pos[Gas]; - fip[3] = rs.value() * fip[po]; - fip[4] = rv.value() * fip[pg]; + sd_.fip[SimulatorData::FIP_DISSOLVED_GAS] = rs.value() * sd_.fip[SimulatorData::FIP_LIQUID]; + sd_.fip[SimulatorData::FIP_VAPORIZED_OIL] = rv.value() * sd_.fip[SimulatorData::FIP_VAPOUR]; } // For a parallel run this is just a local maximum and needs to be updated later @@ -2390,23 +2388,57 @@ namespace detail { if ( !isParallel() ) { - for (int i = 0; i < 5; ++i) { + //Accumulate phases for each region + for (int phase = 0; phase < maxnp; ++phase) { for (int c = 0; c < nc; ++c) { - if (fipnum[c] != 0) { - values[fipnum[c]-1][i] += fip[i][c]; + const int region = fipnum[c] - 1; + if (region != -1) { + values[region][phase] += sd_.fip[phase][c]; } } } + //Accumulate RS and RV-volumes for each region + if (active_[ Oil ] && active_[ Gas ]) { + for (int c = 0; c < nc; ++c) { + const int region = fipnum[c] - 1; + if (region != -1) { + values[region][SimulatorData::FIP_DISSOLVED_GAS] += sd_.fip[SimulatorData::FIP_DISSOLVED_GAS][c]; + values[region][SimulatorData::FIP_VAPORIZED_OIL] += sd_.fip[SimulatorData::FIP_VAPORIZED_OIL][c]; + } + } + } + + hcpv = V::Zero(dims); pres = V::Zero(dims); for (int c = 0; c < nc; ++c) { - if (fipnum[c] != 0) { - hcpv[fipnum[c]-1] += pv[c] * hydrocarbon[c]; - pres[fipnum[c]-1] += pv[c] * pressure.value()[c]; - values[fipnum[c]-1][5] += pv[c]; - values[fipnum[c]-1][6] += pv[c] * pressure.value()[c] * hydrocarbon[c]; + const int region = fipnum[c] - 1; + if (region != -1) { + hcpv[region] += pv[c] * hydrocarbon[c]; + pres[region] += pv[c] * pressure.value()[c]; + } + } + + sd_.fip[SimulatorData::FIP_PV] = V::Zero(nc); + sd_.fip[SimulatorData::FIP_WEIGHTED_PRESSURE] = V::Zero(nc); + + for (int c = 0; c < nc; ++c) { + const int region = fipnum[c] - 1; + if (region != -1) { + sd_.fip[SimulatorData::FIP_PV][c] = pv[c]; + + //Compute hydrocarbon pore volume weighted average pressure. + //If we have no hydrocarbon in region, use pore volume weighted average pressure instead + if (hcpv[region] != 0) { + sd_.fip[SimulatorData::FIP_WEIGHTED_PRESSURE][c] = pv[c] * pressure.value()[c] * hydrocarbon[c] / hcpv[region]; + } else { + sd_.fip[SimulatorData::FIP_WEIGHTED_PRESSURE][c] = pres[region] / pv[c]; + } + + values[region][SimulatorData::FIP_PV] += sd_.fip[SimulatorData::FIP_PV][c]; + values[region][SimulatorData::FIP_WEIGHTED_PRESSURE] += sd_.fip[SimulatorData::FIP_WEIGHTED_PRESSURE][c]; } } } @@ -2422,10 +2454,23 @@ namespace detail { dims = comm.max(dims); values.resize(dims, V::Zero(7)); - for (int i = 0; i < 5; ++i) { + //Accumulate phases for each region + for (int phase = 0; phase < maxnp; ++phase) { for (int c = 0; c < nc; ++c) { - if (fipnum[c] != 0 && mask[c]) { - values[fipnum[c]-1][i] += fip[i][c]; + const int region = fipnum[c] - 1; + if (region != -1 && mask[c]) { + values[region][phase] += sd_.fip[phase][c]; + } + } + } + + //Accumulate RS and RV-volumes for each region + if (active_[ Oil ] && active_[ Gas ]) { + for (int c = 0; c < nc; ++c) { + const int region = fipnum[c] - 1; + if (region != -1 && mask[c]) { + values[region][SimulatorData::FIP_DISSOLVED_GAS] += sd_.fip[SimulatorData::FIP_DISSOLVED_GAS][c]; + values[region][SimulatorData::FIP_VAPORIZED_OIL] += sd_.fip[SimulatorData::FIP_VAPORIZED_OIL][c]; } } } @@ -2434,11 +2479,29 @@ namespace detail { pres = V::Zero(dims); for (int c = 0; c < nc; ++c) { - if (fipnum[c] != 0 && mask[c]) { - hcpv[fipnum[c]-1] += pv[c] * hydrocarbon[c]; - pres[fipnum[c]-1] += pv[c] * pressure.value()[c]; - values[fipnum[c]-1][5] += pv[c]; - values[fipnum[c]-1][6] += pv[c] * pressure.value()[c] * hydrocarbon[c]; + const int region = fipnum[c] - 1; + if (region != -1 && mask[c]) { + hcpv[region] += pv[c] * hydrocarbon[c]; + pres[region] += pv[c] * pressure.value()[c]; + } + } + + sd_.fip[SimulatorData::FIP_PV] = V::Zero(nc); + sd_.fip[SimulatorData::FIP_WEIGHTED_PRESSURE] = V::Zero(nc); + + for (int c = 0; c < nc; ++c) { + const int region = fipnum[c] - 1; + if (region != -1 && mask[c]) { + sd_.fip[SimulatorData::FIP_PV][c] = pv[c]; + + if (hcpv[region] != 0) { + sd_.fip[SimulatorData::FIP_WEIGHTED_PRESSURE][c] = pv[c] * pressure.value()[c] * hydrocarbon[c] / hcpv[region]; + } else { + sd_.fip[SimulatorData::FIP_WEIGHTED_PRESSURE][c] = pres[region] / pv[c]; + } + + values[region][SimulatorData::FIP_PV] += sd_.fip[SimulatorData::FIP_PV][c]; + values[region][SimulatorData::FIP_WEIGHTED_PRESSURE] += sd_.fip[SimulatorData::FIP_WEIGHTED_PRESSURE][c]; } } @@ -2458,15 +2521,6 @@ namespace detail { #endif } - // compute PAV and PORV for every regions. - for (int reg = 0; reg < dims; ++reg) { - if (hcpv[reg] != 0) { - values[reg][6] /= hcpv[reg]; - } else { - values[reg][6] = pres[reg] / values[reg][5]; - } - } - return values; } diff --git a/opm/autodiff/BlackoilSequentialModel.hpp b/opm/autodiff/BlackoilSequentialModel.hpp index 0b67b756c..01727e067 100644 --- a/opm/autodiff/BlackoilSequentialModel.hpp +++ b/opm/autodiff/BlackoilSequentialModel.hpp @@ -253,7 +253,6 @@ namespace Opm { /// Compute fluid in place. /// \param[in] ReservoirState - /// \param[in] WellState /// \param[in] FIPNUM for active cells not global cells. /// \return fluid in place, number of fip regions, each region contains 5 values which are liquid, vapour, water, free gas and dissolved gas. std::vector diff --git a/opm/autodiff/SimulatorFullyImplicitBlackoilOutput.hpp b/opm/autodiff/SimulatorFullyImplicitBlackoilOutput.hpp index d6d551c8e..d217cc008 100644 --- a/opm/autodiff/SimulatorFullyImplicitBlackoilOutput.hpp +++ b/opm/autodiff/SimulatorFullyImplicitBlackoilOutput.hpp @@ -422,13 +422,32 @@ namespace Opm namespace detail { + /** + * Converts an ADB::V into a standard vector by copy + */ + inline std::vector adbVToDoubleVector(const Opm::AutoDiffBlock::V& adb_v) { + std::vector vec(adb_v.data(), adb_v.data() + adb_v.size()); + return vec; + } + + /** * Converts an ADB into a standard vector by copy */ inline std::vector adbToDoubleVector(const Opm::AutoDiffBlock& adb) { - const auto& adb_v = adb.value(); - std::vector vec(adb_v.data(), adb_v.data() + adb_v.size()); - return vec; + return adbVToDoubleVector(adb.value()); + } + + /** + * Checks if the summaryConfig has a keyword with the standardized field, region, or block prefixes. + */ + inline bool hasFRBKeyword(const SummaryConfig& summaryConfig, const std::string keyword) { + std::string field_kw = "F" + keyword; + std::string region_kw = "R" + keyword; + std::string block_kw = "B" + keyword; + return summaryConfig.hasKeyword(field_kw) + || summaryConfig.hasKeyword(region_kw) + || summaryConfig.hasKeyword(block_kw); } @@ -437,15 +456,18 @@ namespace Opm const Opm::PhaseUsage& phaseUsage, const Model& model, const RestartConfig& restartConfig, + const SummaryConfig& summaryConfig, const int reportStepNum, const bool log) { + typedef Opm::AutoDiffBlock ADB; + //Our return vector of properties std::vector simProps; - //Get the value of each of the keys - std::map outKeywords = restartConfig.getRestartKeywords(reportStepNum); - for (auto& keyValue : outKeywords) { + //Get the value of each of the keys for the restart keywords + std::map rstKeywords = restartConfig.getRestartKeywords(reportStepNum); + for (auto& keyValue : rstKeywords) { keyValue.second = restartConfig.getKeyword(keyValue.first, reportStepNum); } @@ -464,88 +486,98 @@ namespace Opm /** * Formation volume factors for water, oil, gas */ - if (aqua_active && outKeywords["BW"] > 0) { - outKeywords["BW"] = 0; + if (aqua_active && rstKeywords["BW"] > 0) { + rstKeywords["BW"] = 0; simProps.emplace_back(data::CellData{ "1OVERBW", Opm::UnitSystem::measure::water_inverse_formation_volume_factor, - std::move(adbToDoubleVector(sd.rq[aqua_idx].b))}); + std::move(adbToDoubleVector(sd.rq[aqua_idx].b)), + true}); } - if (liquid_active && outKeywords["BO"] > 0) { - outKeywords["BO"] = 0; + if (liquid_active && rstKeywords["BO"] > 0) { + rstKeywords["BO"] = 0; simProps.emplace_back(data::CellData{ "1OVERBO", Opm::UnitSystem::measure::oil_inverse_formation_volume_factor, - std::move(adbToDoubleVector(sd.rq[liquid_idx].b))}); + std::move(adbToDoubleVector(sd.rq[liquid_idx].b)), + true}); } - if (vapour_active && outKeywords["BG"] > 0) { - outKeywords["BG"] = 0; + if (vapour_active && rstKeywords["BG"] > 0) { + rstKeywords["BG"] = 0; simProps.emplace_back(data::CellData{ "1OVERBG", Opm::UnitSystem::measure::gas_inverse_formation_volume_factor, - std::move(adbToDoubleVector(sd.rq[vapour_idx].b))}); + std::move(adbToDoubleVector(sd.rq[vapour_idx].b)), + true}); } /** * Densities for water, oil gas */ - if (outKeywords["DEN"] > 0) { - outKeywords["DEN"] = 0; + if (rstKeywords["DEN"] > 0) { + rstKeywords["DEN"] = 0; if (aqua_active) { simProps.emplace_back(data::CellData{ "WAT_DEN", Opm::UnitSystem::measure::density, - std::move(adbToDoubleVector(sd.rq[aqua_idx].rho))}); + std::move(adbToDoubleVector(sd.rq[aqua_idx].rho)), + true}); } if (liquid_active) { simProps.emplace_back(data::CellData{ "OIL_DEN", Opm::UnitSystem::measure::density, - std::move(adbToDoubleVector(sd.rq[liquid_idx].rho))}); + std::move(adbToDoubleVector(sd.rq[liquid_idx].rho)), + true}); } if (vapour_active) { simProps.emplace_back(data::CellData{ "GAS_DEN", Opm::UnitSystem::measure::density, - std::move(adbToDoubleVector(sd.rq[vapour_idx].rho))}); + std::move(adbToDoubleVector(sd.rq[vapour_idx].rho)), + true}); } } /** * Viscosities for water, oil gas */ - if (outKeywords["VISC"] > 0) { - outKeywords["VISC"] = 0; + if (rstKeywords["VISC"] > 0) { + rstKeywords["VISC"] = 0; if (aqua_active) { simProps.emplace_back(data::CellData{ "WAT_VISC", Opm::UnitSystem::measure::viscosity, - std::move(adbToDoubleVector(sd.rq[aqua_idx].mu))}); + std::move(adbToDoubleVector(sd.rq[aqua_idx].mu)), + true}); } if (liquid_active) { simProps.emplace_back(data::CellData{ "OIL_VISC", Opm::UnitSystem::measure::viscosity, - std::move(adbToDoubleVector(sd.rq[liquid_idx].mu))}); + std::move(adbToDoubleVector(sd.rq[liquid_idx].mu)), + true}); } if (vapour_active) { simProps.emplace_back(data::CellData{ "GAS_VISC", Opm::UnitSystem::measure::viscosity, - std::move(adbToDoubleVector(sd.rq[vapour_idx].mu))}); + std::move(adbToDoubleVector(sd.rq[vapour_idx].mu)), + true}); } } /** * Relative permeabilities for water, oil, gas */ - if (aqua_active && outKeywords["KRW"] > 0) { + if (aqua_active && rstKeywords["KRW"] > 0) { if (sd.rq[aqua_idx].kr.size() > 0) { - outKeywords["KRW"] = 0; + rstKeywords["KRW"] = 0; simProps.emplace_back(data::CellData{ "WATKR", Opm::UnitSystem::measure::permeability, - std::move(adbToDoubleVector(sd.rq[aqua_idx].kr))}); + std::move(adbToDoubleVector(sd.rq[aqua_idx].kr)), + true}); } else { if ( log ) @@ -555,13 +587,14 @@ namespace Opm } } } - if (liquid_active && outKeywords["KRO"] > 0) { + if (liquid_active && rstKeywords["KRO"] > 0) { if (sd.rq[liquid_idx].kr.size() > 0) { - outKeywords["KRO"] = 0; + rstKeywords["KRO"] = 0; simProps.emplace_back(data::CellData{ "OILKR", Opm::UnitSystem::measure::permeability, - std::move(adbToDoubleVector(sd.rq[liquid_idx].kr))}); + std::move(adbToDoubleVector(sd.rq[liquid_idx].kr)), + true}); } else { if ( log ) @@ -571,13 +604,14 @@ namespace Opm } } } - if (vapour_active && outKeywords["KRG"] > 0) { + if (vapour_active && rstKeywords["KRG"] > 0) { if (sd.rq[vapour_idx].kr.size() > 0) { - outKeywords["KRG"] = 0; + rstKeywords["KRG"] = 0; simProps.emplace_back(data::CellData{ "GASKR", Opm::UnitSystem::measure::permeability, - std::move(adbToDoubleVector(sd.rq[vapour_idx].kr))}); + std::move(adbToDoubleVector(sd.rq[vapour_idx].kr)), + true}); } else { if ( log ) @@ -591,37 +625,38 @@ namespace Opm /** * Vaporized and dissolved gas/oil ratio */ - if (vapour_active && liquid_active && outKeywords["RSSAT"] > 0) { - outKeywords["RSSAT"] = 0; + if (vapour_active && liquid_active && rstKeywords["RSSAT"] > 0) { + rstKeywords["RSSAT"] = 0; simProps.emplace_back(data::CellData{ "RSSAT", Opm::UnitSystem::measure::gas_oil_ratio, - std::move(adbToDoubleVector(sd.rsSat))}); + std::move(adbToDoubleVector(sd.rsSat)), + true}); } - if (vapour_active && liquid_active && outKeywords["RVSAT"] > 0) { - outKeywords["RVSAT"] = 0; + if (vapour_active && liquid_active && rstKeywords["RVSAT"] > 0) { + rstKeywords["RVSAT"] = 0; simProps.emplace_back(data::CellData{ "RVSAT", Opm::UnitSystem::measure::oil_gas_ratio, - std::move(adbToDoubleVector(sd.rvSat))}); + std::move(adbToDoubleVector(sd.rvSat)), + true}); } /** * Bubble point and dew point pressures */ - if (log && vapour_active && - liquid_active && outKeywords["PBPD"] > 0) { - outKeywords["PBPD"] = 0; + if (log && vapour_active && + liquid_active && rstKeywords["PBPD"] > 0) { + rstKeywords["PBPD"] = 0; Opm::OpmLog::warning("Bubble/dew point pressure output unsupported", "Writing bubble points and dew points (PBPD) to file is unsupported, " "as the simulator does not use these internally."); } //Warn for any unhandled keyword - if (log) - { - for (auto& keyValue : outKeywords) { + if (log) { + for (auto& keyValue : rstKeywords) { if (keyValue.second > 0) { std::string logstring = "Keyword '"; logstring.append(keyValue.first); @@ -631,6 +666,92 @@ namespace Opm } } + + /** + * Now process all of the summary config files + */ + // Water in place + if (aqua_active && hasFRBKeyword(summaryConfig, "WIP")) { + simProps.emplace_back(data::CellData{ + "WIP", + Opm::UnitSystem::measure::volume, + std::move(adbVToDoubleVector(sd.fip[Model::SimulatorData::FIP_AQUA])), + false}); + } + if (liquid_active) { + //Oil in place (liquid phase only) + if (hasFRBKeyword(summaryConfig, "OIPL")) { + simProps.emplace_back(data::CellData{ + "OIPL", + Opm::UnitSystem::measure::volume, + std::move(adbVToDoubleVector(sd.fip[Model::SimulatorData::FIP_LIQUID])), + false}); + } + //Oil in place (gas phase only) + if (hasFRBKeyword(summaryConfig, "OIPG")) { + simProps.emplace_back(data::CellData{ + "OIPG", + Opm::UnitSystem::measure::volume, + std::move(adbVToDoubleVector(sd.fip[Model::SimulatorData::FIP_VAPORIZED_OIL])), + false}); + } + // Oil in place (in liquid and gas phases) + if (hasFRBKeyword(summaryConfig, "OIP")) { + ADB::V oip = sd.fip[Model::SimulatorData::FIP_LIQUID] + + sd.fip[Model::SimulatorData::FIP_VAPORIZED_OIL]; + simProps.emplace_back(data::CellData{ + "OIP", + Opm::UnitSystem::measure::volume, + std::move(adbVToDoubleVector(oip)), + false}); + } + } + if (vapour_active) { + // Gas in place (gas phase only) + if (hasFRBKeyword(summaryConfig, "GIPG")) { + simProps.emplace_back(data::CellData{ + "GIPG", + Opm::UnitSystem::measure::volume, + std::move(adbVToDoubleVector(sd.fip[Model::SimulatorData::FIP_VAPOUR])), + false}); + } + // Gas in place (liquid phase only) + if (hasFRBKeyword(summaryConfig, "GIPL")) { + simProps.emplace_back(data::CellData{ + "GIPL", + Opm::UnitSystem::measure::volume, + std::move(adbVToDoubleVector(sd.fip[Model::SimulatorData::FIP_DISSOLVED_GAS])), + false}); + } + // Gas in place (in both liquid and gas phases) + if (hasFRBKeyword(summaryConfig, "GIP")) { + ADB::V gip = sd.fip[Model::SimulatorData::FIP_VAPOUR] + + sd.fip[Model::SimulatorData::FIP_DISSOLVED_GAS]; + simProps.emplace_back(data::CellData{ + "GIP", + Opm::UnitSystem::measure::volume, + std::move(adbVToDoubleVector(gip)), + false}); + } + } + // Cell pore volume in reservoir conditions + if (hasFRBKeyword(summaryConfig, "RPV")) { + simProps.emplace_back(data::CellData{ + "RPV", + Opm::UnitSystem::measure::volume, + std::move(adbVToDoubleVector(sd.fip[Model::SimulatorData::FIP_PV])), + false}); + } + // Pressure averaged value (hydrocarbon pore volume weighted) + if (summaryConfig.hasKeyword("FPRH") || summaryConfig.hasKeyword("RPRH")) { + simProps.emplace_back(data::CellData{ + "PRH", + Opm::UnitSystem::measure::pressure, + std::move(adbVToDoubleVector(sd.fip[Model::SimulatorData::FIP_WEIGHTED_PRESSURE])), + false}); + } + + return simProps; } @@ -649,11 +770,13 @@ namespace Opm bool substep) { const RestartConfig& restartConfig = eclipseState_->getRestartConfig(); + const SummaryConfig& summaryConfig = eclipseState_->getSummaryConfig(); const int reportStepNum = timer.reportStepNum(); bool logMessages = output_ && parallelOutput_->isIORank(); std::vector cellData = - detail::getCellData( phaseUsage_,physicalModel, restartConfig, - reportStepNum, logMessages ); + detail::getCellData( phaseUsage_, physicalModel, restartConfig, + summaryConfig, reportStepNum, logMessages ); + writeTimeStepWithCellProperties(timer, localState, localWellState, cellData, substep); } } diff --git a/opm/polymer/fullyimplicit/FullyImplicitCompressiblePolymerSolver.hpp b/opm/polymer/fullyimplicit/FullyImplicitCompressiblePolymerSolver.hpp index 7a5694530..24aad8c1b 100644 --- a/opm/polymer/fullyimplicit/FullyImplicitCompressiblePolymerSolver.hpp +++ b/opm/polymer/fullyimplicit/FullyImplicitCompressiblePolymerSolver.hpp @@ -80,11 +80,23 @@ namespace Opm { : rq(num_phases) , rsSat(ADB::null()) , rvSat(ADB::null()) + , fip() { } + + enum FipId { + FIP_AQUA = BlackoilPropsAdInterface::Water, + FIP_LIQUID = BlackoilPropsAdInterface::Oil, + FIP_VAPOUR = BlackoilPropsAdInterface::Gas, + FIP_DISSOLVED_GAS = 3, + FIP_VAPORIZED_OIL = 4, + FIP_PV = 5, //< Pore volume + FIP_WEIGHTED_PRESSURE = 6 + }; std::vector rq; ADB rsSat; ADB rvSat; + std::array fip; }; /// Construct a solver. It will retain references to the