void PvtPropertiesIncompFromDeck::init(const EclipseGridParser& deck) { typedef std::vector<std::vector<std::vector<double> > > table_t; // If we need multiple regions, this class and the SinglePvt* classes must change. int region_number = 0; PhaseUsage phase_usage = phaseUsageFromDeck(deck); if (phase_usage.phase_used[PhaseUsage::Vapour] || !phase_usage.phase_used[PhaseUsage::Aqua] || !phase_usage.phase_used[PhaseUsage::Liquid]) { THROW("PvtPropertiesIncompFromDeck::init() -- must have gas and oil phases (only) in deck input.\n"); } // Surface densities. Accounting for different orders in eclipse and our code. if (deck.hasField("DENSITY")) { const std::vector<double>& d = deck.getDENSITY().densities_[region_number]; enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 }; surface_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] = d[ECL_water]; surface_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] = d[ECL_oil]; } else { THROW("Input is missing DENSITY\n"); } // Make reservoir densities the same as surface densities initially. // We will modify them with formation volume factors if found. reservoir_density_ = surface_density_; // Water viscosity. if (deck.hasField("PVTW")) { const std::vector<double>& pvtw = deck.getPVTW().pvtw_[region_number]; if (pvtw[2] != 0.0 || pvtw[4] != 0.0) { MESSAGE("Compressibility effects in PVTW are ignored."); } reservoir_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] /= pvtw[1]; viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = pvtw[3]; } else { // Eclipse 100 default. // viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = 0.5*Opm::prefix::centi*Opm::unit::Poise; THROW("Input is missing PVTW\n"); } // Oil viscosity. if (deck.hasField("PVCDO")) { const std::vector<double>& pvcdo = deck.getPVCDO().pvcdo_[region_number]; if (pvcdo[2] != 0.0 || pvcdo[4] != 0.0) { MESSAGE("Compressibility effects in PVCDO are ignored."); } reservoir_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] /= pvcdo[1]; viscosity_[phase_usage.phase_pos[PhaseUsage::Liquid]] = pvcdo[3]; } else { THROW("Input is missing PVCDO\n"); } }
void SaturationPropsFromDeck<SatFuncSet>::init(const EclipseGridParser& deck, const UnstructuredGrid& grid, const int samples) { phase_usage_ = phaseUsageFromDeck(deck); // Extract input data. // Oil phase should be active. if (!phase_usage_.phase_used[Liquid]) { THROW("SaturationPropsFromDeck::init() -- oil phase must be active."); } // Obtain SATNUM, if it exists, and create cell_to_func_. // Otherwise, let the cell_to_func_ mapping be just empty. int satfuncs_expected = 1; if (deck.hasField("SATNUM")) { const std::vector<int>& satnum = deck.getIntegerValue("SATNUM"); satfuncs_expected = *std::max_element(satnum.begin(), satnum.end()); const int num_cells = grid.number_of_cells; cell_to_func_.resize(num_cells); const int* gc = grid.global_cell; for (int cell = 0; cell < num_cells; ++cell) { const int deck_pos = (gc == NULL) ? cell : gc[cell]; cell_to_func_[cell] = satnum[deck_pos] - 1; } } // Find number of tables, check for consistency. enum { Uninitialized = -1 }; int num_tables = Uninitialized; if (phase_usage_.phase_used[Aqua]) { const SWOF::table_t& swof_table = deck.getSWOF().swof_; num_tables = swof_table.size(); if (num_tables < satfuncs_expected) { THROW("Found " << num_tables << " SWOF tables, SATNUM specifies at least " << satfuncs_expected); } } if (phase_usage_.phase_used[Vapour]) { const SGOF::table_t& sgof_table = deck.getSGOF().sgof_; int num_sgof_tables = sgof_table.size(); if (num_sgof_tables < satfuncs_expected) { THROW("Found " << num_tables << " SGOF tables, SATNUM specifies at least " << satfuncs_expected); } if (num_tables == Uninitialized) { num_tables = num_sgof_tables; } else if (num_tables != num_sgof_tables) { THROW("Inconsistent number of tables in SWOF and SGOF."); } } // Initialize tables. satfuncset_.resize(num_tables); for (int table = 0; table < num_tables; ++table) { satfuncset_[table].init(deck, table, phase_usage_, samples); } }
RockCompressibility::RockCompressibility(const EclipseGridParser& deck) : pref_(0.0), rock_comp_(0.0) { if (deck.hasField("ROCKTAB")) { const table_t& rt = deck.getROCKTAB().rocktab_; int n = rt[0][0].size(); p_.resize(n); poromult_.resize(n); for (int i = 0; i < n; ++i) { p_[i] = rt[0][0][i]; poromult_[i] = rt[0][1][i]; } } else if (deck.hasField("ROCK")) { const ROCK& r = deck.getROCK(); pref_ = r.rock_compressibilities_[0][0]; rock_comp_ = r.rock_compressibilities_[0][1]; } else { std::cout << "**** warning: no rock compressibility data found in deck (ROCK or ROCKTAB)." << std::endl; } }
void initBlackoilStateFromDeck(const UnstructuredGrid& grid, const Props& props, const EclipseGridParser& deck, const double gravity, State& state) { initStateFromDeck(grid, props, deck, gravity, state); initBlackoilSurfvol(grid, props, state); if (deck.hasField("RS")) { const std::vector<double>& rs_deck = deck.getFloatingPointValue("RS"); const int num_cells = grid.number_of_cells; for (int c = 0; c < num_cells; ++c) { int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c]; state.gasoilratio()[c] = rs_deck[c_deck]; } } else { THROW("Temporarily, we require the RS field."); } }
/// Constructor. /// @param[in] deck Input deck expected to contain WPOLYMER. PolymerInflowFromDeck::PolymerInflowFromDeck(const EclipseGridParser& deck, const Wells& wells, const int num_cells) : sparse_inflow_(num_cells) { if (!deck.hasField("WPOLYMER")) { OPM_MESSAGE("PolymerInflowFromDeck initialized without WPOLYMER in current epoch."); return; } // Extract concentrations and put into cell->concentration map. const std::vector<WpolymerLine>& wpl = deck.getWPOLYMER().wpolymer_; const int num_wpl = wpl.size(); std::map<int, double> perfcell_conc; for (int i = 0; i < num_wpl; ++i) { // Only use well name and polymer concentration. // That is, we ignore salt concentration and group // names. int wix = 0; for (; wix < wells.number_of_wells; ++wix) { if (wpl[i].well_ == wells.name[wix]) { break; } } if (wix == wells.number_of_wells) { OPM_THROW(std::runtime_error, "Could not find a match for well " << wpl[i].well_ << " from WPOLYMER."); } for (int j = wells.well_connpos[wix]; j < wells.well_connpos[wix+1]; ++j) { const int perf_cell = wells.well_cells[j]; perfcell_conc[perf_cell] = wpl[i].polymer_concentration_; } } // Build sparse vector from map. std::map<int, double>::const_iterator it = perfcell_conc.begin(); for (; it != perfcell_conc.end(); ++it) { sparse_inflow_.addElement(it->second, it->first); } }
void initStateFromDeck(const UnstructuredGrid& grid, const Props& props, const EclipseGridParser& deck, const double gravity, State& state) { const int num_phases = props.numPhases(); const PhaseUsage pu = phaseUsageFromDeck(deck); if (num_phases != pu.num_phases) { THROW("initStateFromDeck(): user specified property object with " << num_phases << " phases, " "found " << pu.num_phases << " phases in deck."); } state.init(grid, num_phases); if (deck.hasField("EQUIL")) { if (num_phases != 2) { THROW("initStateFromDeck(): EQUIL-based init currently handling only two-phase scenarios."); } if (pu.phase_used[BlackoilPhases::Vapour]) { THROW("initStateFromDeck(): EQUIL-based init currently handling only oil-water scenario (no gas)."); } // Set saturations depending on oil-water contact. const EQUIL& equil= deck.getEQUIL(); if (equil.equil.size() != 1) { THROW("initStateFromDeck(): No region support yet."); } const double woc = equil.equil[0].water_oil_contact_depth_; initWaterOilContact(grid, props, woc, WaterBelow, state); // Set pressure depending on densities and depths. const double datum_z = equil.equil[0].datum_depth_; const double datum_p = equil.equil[0].datum_depth_pressure_; initHydrostaticPressure(grid, props, woc, gravity, datum_z, datum_p, state); } else if (deck.hasField("PRESSURE")) { // Set saturations from SWAT/SGAS, pressure from PRESSURE. std::vector<double>& s = state.saturation(); std::vector<double>& p = state.pressure(); const std::vector<double>& p_deck = deck.getFloatingPointValue("PRESSURE"); const int num_cells = grid.number_of_cells; if (num_phases == 2) { if (!pu.phase_used[BlackoilPhases::Aqua]) { // oil-gas: we require SGAS if (!deck.hasField("SGAS")) { THROW("initStateFromDeck(): missing SGAS keyword in 2-phase init"); } const std::vector<double>& sg_deck = deck.getFloatingPointValue("SGAS"); const int gpos = pu.phase_pos[BlackoilPhases::Vapour]; const int opos = pu.phase_pos[BlackoilPhases::Liquid]; for (int c = 0; c < num_cells; ++c) { int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c]; s[2*c + gpos] = sg_deck[c_deck]; s[2*c + opos] = 1.0 - sg_deck[c_deck]; p[c] = p_deck[c_deck]; } } else { // water-oil or water-gas: we require SWAT if (!deck.hasField("SWAT")) { THROW("initStateFromDeck(): missing SWAT keyword in 2-phase init"); } const std::vector<double>& sw_deck = deck.getFloatingPointValue("SWAT"); const int wpos = pu.phase_pos[BlackoilPhases::Aqua]; const int nwpos = (wpos + 1) % 2; for (int c = 0; c < num_cells; ++c) { int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c]; s[2*c + wpos] = sw_deck[c_deck]; s[2*c + nwpos] = 1.0 - sw_deck[c_deck]; p[c] = p_deck[c_deck]; } } } else if (num_phases == 3) { const bool has_swat_sgas = deck.hasField("SWAT") && deck.hasField("SGAS"); if (!has_swat_sgas) { THROW("initStateFromDeck(): missing SGAS or SWAT keyword in 3-phase init."); } const int wpos = pu.phase_pos[BlackoilPhases::Aqua]; const int gpos = pu.phase_pos[BlackoilPhases::Vapour]; const int opos = pu.phase_pos[BlackoilPhases::Liquid]; const std::vector<double>& sw_deck = deck.getFloatingPointValue("SWAT"); const std::vector<double>& sg_deck = deck.getFloatingPointValue("SGAS"); for (int c = 0; c < num_cells; ++c) { int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c]; s[3*c + wpos] = sw_deck[c_deck]; s[3*c + opos] = 1.0 - (sw_deck[c_deck] + sg_deck[c_deck]); s[3*c + gpos] = sg_deck[c_deck]; p[c] = p_deck[c_deck]; } } else { THROW("initStateFromDeck(): init with SWAT etc. only available with 2 or 3 phases."); } } else { THROW("initStateFromDeck(): we must either have EQUIL, or PRESSURE and SWAT/SOIL/SGAS."); } // Finally, init face pressures. initFacePressure(grid, state); }
/// Constructor wrapping an opm-core black oil interface. BlackoilPropsAdFromDeck::BlackoilPropsAdFromDeck(const EclipseGridParser& deck, const UnstructuredGrid& grid, const bool init_rock) { if (init_rock){ rock_.init(deck, grid); } const int samples = 0; const int region_number = 0; phase_usage_ = phaseUsageFromDeck(deck); // Surface densities. Accounting for different orders in eclipse and our code. if (deck.hasField("DENSITY")) { const std::vector<double>& d = deck.getDENSITY().densities_[region_number]; enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 }; if (phase_usage_.phase_used[Aqua]) { densities_[phase_usage_.phase_pos[Aqua]] = d[ECL_water]; } if (phase_usage_.phase_used[Vapour]) { densities_[phase_usage_.phase_pos[Vapour]] = d[ECL_gas]; } if (phase_usage_.phase_used[Liquid]) { densities_[phase_usage_.phase_pos[Liquid]] = d[ECL_oil]; } } else { OPM_THROW(std::runtime_error, "Input is missing DENSITY\n"); } // Set the properties. props_.resize(phase_usage_.num_phases); // Water PVT if (phase_usage_.phase_used[Aqua]) { if (deck.hasField("PVTW")) { props_[phase_usage_.phase_pos[Aqua]].reset(new SinglePvtConstCompr(deck.getPVTW().pvtw_)); } else { // Eclipse 100 default. props_[phase_usage_.phase_pos[Aqua]].reset(new SinglePvtConstCompr(0.5*Opm::prefix::centi*Opm::unit::Poise)); } } // Oil PVT if (phase_usage_.phase_used[Liquid]) { if (deck.hasField("PVDO")) { if (samples > 0) { props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDeadSpline(deck.getPVDO().pvdo_, samples)); } else { props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDead(deck.getPVDO().pvdo_)); } } else if (deck.hasField("PVTO")) { props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtLiveOil(deck.getPVTO().pvto_)); } else if (deck.hasField("PVCDO")) { props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtConstCompr(deck.getPVCDO().pvcdo_)); } else { OPM_THROW(std::runtime_error, "Input is missing PVDO or PVTO\n"); } } // Gas PVT if (phase_usage_.phase_used[Vapour]) { if (deck.hasField("PVDG")) { if (samples > 0) { props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDeadSpline(deck.getPVDG().pvdg_, samples)); } else { props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDead(deck.getPVDG().pvdg_)); } // } else if (deck.hasField("PVTG")) { // props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtLiveGas(deck.getPVTG().pvtg_)); } else { OPM_THROW(std::runtime_error, "Input is missing PVDG or PVTG\n"); } } SaturationPropsFromDeck<SatFuncGwsegNonuniform>* ptr = new SaturationPropsFromDeck<SatFuncGwsegNonuniform>(); satprops_.reset(ptr); ptr->init(deck, grid, -1); if (phase_usage_.num_phases != satprops_->numPhases()) { OPM_THROW(std::runtime_error, "BlackoilPropsAdFromDeck::BlackoilPropsAdFromDeck() - " "Inconsistent number of phases in pvt data (" << phase_usage_.num_phases << ") and saturation-dependent function data (" << satprops_->numPhases() << ")."); } }
void BlackoilPvtProperties::init(const EclipseGridParser& deck, const int samples) { // If we need multiple regions, this class and the SinglePvt* classes must change. region_number_ = 0; phase_usage_ = phaseUsageFromDeck(deck); // Surface densities. Accounting for different orders in eclipse and our code. if (deck.hasField("DENSITY")) { const std::vector<double>& d = deck.getDENSITY().densities_[region_number_]; enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 }; if (phase_usage_.phase_used[Aqua]) { densities_[phase_usage_.phase_pos[Aqua]] = d[ECL_water]; } if (phase_usage_.phase_used[Vapour]) { densities_[phase_usage_.phase_pos[Vapour]] = d[ECL_gas]; } if (phase_usage_.phase_used[Liquid]) { densities_[phase_usage_.phase_pos[Liquid]] = d[ECL_oil]; } } else { OPM_THROW(std::runtime_error, "Input is missing DENSITY\n"); } // Set the properties. props_.resize(phase_usage_.num_phases); // Water PVT if (phase_usage_.phase_used[Aqua]) { if (deck.hasField("PVTW")) { props_[phase_usage_.phase_pos[Aqua]].reset(new SinglePvtConstCompr(deck.getPVTW().pvtw_)); } else { // Eclipse 100 default. props_[phase_usage_.phase_pos[Aqua]].reset(new SinglePvtConstCompr(0.5*Opm::prefix::centi*Opm::unit::Poise)); } } // Oil PVT if (phase_usage_.phase_used[Liquid]) { if (deck.hasField("PVDO")) { if (samples > 0) { props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDeadSpline(deck.getPVDO().pvdo_, samples)); } else { props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDead(deck.getPVDO().pvdo_)); } } else if (deck.hasField("PVTO")) { props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtLiveOil(deck.getPVTO().pvto_)); } else if (deck.hasField("PVCDO")) { props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtConstCompr(deck.getPVCDO().pvcdo_)); } else { OPM_THROW(std::runtime_error, "Input is missing PVDO or PVTO\n"); } } // Gas PVT if (phase_usage_.phase_used[Vapour]) { if (deck.hasField("PVDG")) { if (samples > 0) { props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDeadSpline(deck.getPVDG().pvdg_, samples)); } else { props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDead(deck.getPVDG().pvdg_)); } } else if (deck.hasField("PVTG")) { props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtLiveGas(deck.getPVTG().pvtg_)); } else { OPM_THROW(std::runtime_error, "Input is missing PVDG or PVTG\n"); } } // Must inform pvt property objects of phase structure. for (int i = 0; i < phase_usage_.num_phases; ++i) { props_[i]->setPhaseConfiguration(phase_usage_.num_phases, phase_usage_.phase_pos); } }