IncompPropertiesSinglePhase::IncompPropertiesSinglePhase(Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclState, const UnstructuredGrid& grid) { rock_.init(eclState, grid.number_of_cells, grid.global_cell, grid.cartdims); if (deck->hasKeyword("DENSITY")) { Opm::DeckRecordConstPtr densityRecord = deck->getKeyword("DENSITY")->getRecord(0); surface_density_ = densityRecord->getItem("OIL")->getSIDouble(0); } else { surface_density_ = 1000.0; OPM_MESSAGE("Input is missing DENSITY -- using a standard density of " << surface_density_ << ".\n"); } // This will be modified if we have a PVCDO specification. reservoir_density_ = surface_density_; if (deck->hasKeyword("PVCDO")) { Opm::DeckRecordConstPtr pvcdoRecord = deck->getKeyword("PVCDO")->getRecord(0); if (pvcdoRecord->getItem("OIL_COMPRESSIBILITY")->getSIDouble(0) != 0.0 || pvcdoRecord->getItem("OIL_VISCOSIBILITY")->getSIDouble(0) != 0.0) { OPM_MESSAGE("Compressibility effects in PVCDO are ignored."); } reservoir_density_ /= pvcdoRecord->getItem("OIL_VOL_FACTOR")->getSIDouble(0); viscosity_ = pvcdoRecord->getItem("OIL_VISCOSITY")->getSIDouble(0); } else { viscosity_ = 1.0 * prefix::centi*unit::Poise; OPM_MESSAGE("Input is missing PVCDO -- using a standard viscosity of " << viscosity_ << " and reservoir density equal to surface density.\n"); } }
/// set the tables which specify the temperature dependence of the water viscosity void initFromDeck(std::shared_ptr<const PvtInterface> isothermalPvt, Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclipseState) { isothermalPvt_ = isothermalPvt; watvisctTables_ = 0; // stuff which we need to get from the PVTW keyword const auto& pvtwKeyword = deck->getKeyword("PVTW"); int numRegions = pvtwKeyword.size(); pvtwRefPress_.resize(numRegions); pvtwRefB_.resize(numRegions); pvtwCompressibility_.resize(numRegions); pvtwViscosity_.resize(numRegions); pvtwViscosibility_.resize(numRegions); for (int regionIdx = 0; regionIdx < numRegions; ++ regionIdx) { const auto& pvtwRecord = pvtwKeyword.getRecord(regionIdx); pvtwRefPress_[regionIdx] = pvtwRecord.getItem("P_REF").getSIDouble(0); pvtwRefB_[regionIdx] = pvtwRecord.getItem("WATER_VOL_FACTOR").getSIDouble(0); pvtwViscosity_[regionIdx] = pvtwRecord.getItem("WATER_VISCOSITY").getSIDouble(0); pvtwViscosibility_[regionIdx] = pvtwRecord.getItem("WATER_VISCOSIBILITY").getSIDouble(0); } // quantities required for the temperature dependence of the viscosity // (basically we expect well-behaved VISCREF and WATVISCT keywords.) if (deck->hasKeyword("VISCREF")) { auto tables = eclipseState->getTableManager(); watvisctTables_ = &tables->getWatvisctTables(); const auto& viscrefKeyword = deck->getKeyword("VISCREF"); assert(int(watvisctTables_->size()) == numRegions); assert(int(viscrefKeyword.size()) == numRegions); viscrefPress_.resize(numRegions); for (int regionIdx = 0; regionIdx < numRegions; ++ regionIdx) { const auto& viscrefRecord = viscrefKeyword.getRecord(regionIdx); viscrefPress_[regionIdx] = viscrefRecord.getItem("REFERENCE_PRESSURE").getSIDouble(0); } } // quantities required for the temperature dependence of the density if (deck->hasKeyword("WATDENT")) { const auto& watdentKeyword = deck->getKeyword("WATDENT"); assert(int(watdentKeyword.size()) == numRegions); watdentRefTemp_.resize(numRegions); watdentCT1_.resize(numRegions); watdentCT2_.resize(numRegions); for (int 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); } } }
void BlackoilPVT::init(Opm::DeckConstPtr deck) { Opm::ParseMode parseMode; const auto eclipseState = std::make_shared<EclipseState>(deck , parseMode); region_number_ = 0; // Surface densities. Accounting for different orders in eclipse and our code. if (deck->hasKeyword("DENSITY")) { Opm::DeckRecordConstPtr densityRecord = deck->getKeyword("DENSITY")->getRecord(/*regionIdx=*/0); densities_[Aqua] = densityRecord->getItem("WATER")->getSIDouble(0); densities_[Vapour] = densityRecord->getItem("GAS")->getSIDouble(0); densities_[Liquid] = densityRecord->getItem("OIL")->getSIDouble(0); } else { OPM_THROW(std::runtime_error, "Input is missing DENSITY\n"); } // Water PVT if (deck->hasKeyword("PVTW")) { water_props_.reset(new MiscibilityWater(deck->getKeyword("PVTW"))); } else { water_props_.reset(new MiscibilityWater(0.5*Opm::prefix::centi*Opm::unit::Poise)); // Eclipse 100 default } // Oil PVT const auto& tables = eclipseState->getTableManager(); const auto& pvdoTables = tables->getPvdoTables(); const auto& pvtoTables = tables->getPvtoTables(); if (!pvdoTables.empty()) { const auto& pvdoTable = pvdoTables.getTable<PvdoTable>(0); oil_props_.reset(new MiscibilityDead(pvdoTable)); } else if (pvtoTables.empty()) { // PVTOTables is a std::vector<> const auto& pvtoTable = pvtoTables[0]; oil_props_.reset(new MiscibilityLiveOil(pvtoTable)); } else if (deck->hasKeyword("PVCDO")) { auto *misc_water = new MiscibilityWater(0); misc_water->initFromPvcdo(deck->getKeyword("PVCDO")); oil_props_.reset(misc_water); } else { OPM_THROW(std::runtime_error, "Input is missing PVDO and PVTO\n"); } // Gas PVT const auto& pvdgTables = tables->getPvdgTables(); const auto& pvtgTables = tables->getPvtgTables(); if (!pvdgTables.empty()) { const auto& pvdgTable = pvdgTables.getTable<PvdgTable>(0); gas_props_.reset(new MiscibilityDead(pvdgTable)); } else if (pvtgTables.empty()) { gas_props_.reset(new MiscibilityLiveGas(pvtgTables[0])); } else { OPM_THROW(std::runtime_error, "Input is missing PVDG and PVTG\n"); } }
void PvtPropertiesIncompFromDeck::init(Opm::DeckConstPtr deck) { // So far, this class only supports a single PVT region. TODO? 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]) { OPM_THROW(std::runtime_error, "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->hasKeyword("DENSITY")) { const auto& densityRecord = deck->getKeyword("DENSITY").getRecord(region_number); surface_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] = densityRecord.getItem("OIL").getSIDouble(0); surface_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] = densityRecord.getItem("WATER").getSIDouble(0); } else { OPM_THROW(std::runtime_error, "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->hasKeyword("PVTW")) { const auto& pvtwRecord = deck->getKeyword("PVTW").getRecord(region_number); if (pvtwRecord.getItem("WATER_COMPRESSIBILITY").getSIDouble(0) != 0.0 || pvtwRecord.getItem("WATER_VISCOSIBILITY").getSIDouble(0) != 0.0) { OPM_MESSAGE("Compressibility effects in PVTW are ignored."); } reservoir_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] /= pvtwRecord.getItem("WATER_VOL_FACTOR").getSIDouble(0); viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = pvtwRecord.getItem("WATER_VISCOSITY").getSIDouble(0); } else { // Eclipse 100 default. // viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = 0.5*Opm::prefix::centi*Opm::unit::Poise; OPM_THROW(std::runtime_error, "Input is missing PVTW\n"); } // Oil viscosity. if (deck->hasKeyword("PVCDO")) { const auto& pvcdoRecord = deck->getKeyword("PVCDO").getRecord(region_number); if (pvcdoRecord.getItem("OIL_COMPRESSIBILITY").getSIDouble(0) != 0.0 || pvcdoRecord.getItem("OIL_VISCOSIBILITY").getSIDouble(0) != 0.0) { OPM_MESSAGE("Compressibility effects in PVCDO are ignored."); } reservoir_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] /= pvcdoRecord.getItem("OIL_VOL_FACTOR").getSIDouble(0); viscosity_[phase_usage.phase_pos[PhaseUsage::Liquid]] = pvcdoRecord.getItem("OIL_VISCOSITY").getSIDouble(0); } else { OPM_THROW(std::runtime_error, "Input is missing PVCDO\n"); } }
/*! * \brief Reads all relevant material parameters form a cell of a parsed ECL deck. * * This requires that the opm-parser module is available. */ void initFromDeck(Opm::DeckConstPtr deck) { enableHysteresis_ = false; if (!deck->hasKeyword("SATOPTS")) return; Opm::DeckItemConstPtr satoptsItem = deck->getKeyword("SATOPTS")->getRecord(0)->getItem(0); for (unsigned i = 0; i < satoptsItem->size(); ++i) { std::string satoptsValue = satoptsItem->getString(0); std::transform(satoptsValue.begin(), satoptsValue.end(), satoptsValue.begin(), ::toupper); if (satoptsValue == "HYSTER") enableHysteresis_ = true; } // check for the (deprecated) HYST keyword if (deck->hasKeyword("HYST")) enableHysteresis_ = true; if (!enableHysteresis_) return; if (!deck->hasKeyword("EHYSTR")) OPM_THROW(std::runtime_error, "Enabling hysteresis via the HYST parameter for SATOPTS requires the " "presence of the EHYSTR keyword"); Opm::DeckKeywordConstPtr ehystrKeyword = deck->getKeyword("EHYSTR"); if (deck->hasKeyword("NOHYKR")) krHysteresisModel_ = -1; else { krHysteresisModel_ = ehystrKeyword->getRecord(0)->getItem("relative_perm_hyst")->getInt(0); if (krHysteresisModel_ != 0) OPM_THROW(std::runtime_error, "Only the Carlson kr hystersis model (indicated by a 0 on the second item" " of the 'EHYSTR' keyword) is supported"); } if (deck->hasKeyword("NOHYPC")) pcHysteresisModel_ = -1; else { // if capillary pressure hysteresis is enabled, Eclipse always uses the // Killough model pcHysteresisModel_ = 0; } }
void GridManager::createGrdecl(Opm::DeckConstPtr deck, struct grdecl &grdecl) { // Extract data from deck. const std::vector<double>& zcorn = deck->getKeyword("ZCORN").getSIDoubleData(); const std::vector<double>& coord = deck->getKeyword("COORD").getSIDoubleData(); const int* actnum = NULL; if (deck->hasKeyword("ACTNUM")) { actnum = &(deck->getKeyword("ACTNUM").getIntData()[0]); } std::array<int, 3> dims; if (deck->hasKeyword("DIMENS")) { const auto& dimensKeyword = deck->getKeyword("DIMENS"); dims[0] = dimensKeyword.getRecord(0).getItem(0).get< int >(0); dims[1] = dimensKeyword.getRecord(0).getItem(1).get< int >(0); dims[2] = dimensKeyword.getRecord(0).getItem(2).get< int >(0); } else if (deck->hasKeyword("SPECGRID")) { const auto& specgridKeyword = deck->getKeyword("SPECGRID"); dims[0] = specgridKeyword.getRecord(0).getItem(0).get< int >(0); dims[1] = specgridKeyword.getRecord(0).getItem(1).get< int >(0); dims[2] = specgridKeyword.getRecord(0).getItem(2).get< int >(0); } else { OPM_THROW(std::runtime_error, "Deck must have either DIMENS or SPECGRID."); } // Collect in input struct for preprocessing. grdecl.zcorn = &zcorn[0]; grdecl.coord = &coord[0]; grdecl.actnum = actnum; grdecl.dims[0] = dims[0]; grdecl.dims[1] = dims[1]; grdecl.dims[2] = dims[2]; if (deck->hasKeyword("MAPAXES")) { const auto& mapaxesKeyword = deck->getKeyword("MAPAXES"); const auto& mapaxesRecord = mapaxesKeyword.getRecord(0); // memleak alert: here we need to make sure that C code // can properly take ownership of the grdecl.mapaxes // object. if it is not freed, it will result in a // memleak... double *cWtfMapaxes = static_cast<double*>(malloc(sizeof(double)*mapaxesRecord.size())); for (unsigned i = 0; i < mapaxesRecord.size(); ++i) cWtfMapaxes[i] = mapaxesRecord.getItem(i).getSIDouble(0); grdecl.mapaxes = cWtfMapaxes; } else grdecl.mapaxes = NULL; }
void filterIntegerField(const std::string& keyword, std::vector<int>& output_field) { if (deck_->hasKeyword(keyword)) { const std::vector<int>& field = deck_->getKeyword(keyword)->getIntData(); filterField(field, output_field); } }
void filterDoubleField(const std::string& keyword, std::vector<double>& output_field) { if (deck_->hasKeyword(keyword)) { const std::vector<double>& field = deck_->getKeyword(keyword)->getRawDoubleData(); filterField(field, output_field); } }
RockCompressibility::RockCompressibility(Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclipseState) : pref_(0.0), rock_comp_(0.0) { const auto tables = eclipseState->getTableManager(); const auto& rocktabTables = tables->getRocktabTables(); if (rocktabTables.size() > 0) { const auto& rocktabTable = rocktabTables.getTable<RocktabTable>(0); if (rocktabTables.size() != 1) OPM_THROW(std::runtime_error, "Can only handle a single region in ROCKTAB."); p_ = rocktabTable.getColumn("PO").vectorCopy( ); poromult_ = rocktabTable.getColumn("PV_MULT").vectorCopy(); if (rocktabTable.hasColumn("PV_MULT_TRAN")) { transmult_ = rocktabTable.getColumn("PV_MULT_TRAN").vectorCopy(); } else { transmult_ = rocktabTable.getColumn("PV_MULT_TRANX").vectorCopy(); } } else if (deck->hasKeyword("ROCK")) { Opm::DeckKeywordConstPtr rockKeyword = deck->getKeyword("ROCK"); if (rockKeyword->size() != 1) { // here it would be better not to use std::cout directly but to add the // warning to some "warning list"... std::cout << "Can only handle a single region in ROCK ("<<rockKeyword->size()<<" regions specified)." << " Ignoring all except for the first.\n"; } pref_ = rockKeyword->getRecord(0)->getItem("PREF")->getSIDouble(0); rock_comp_ = rockKeyword->getRecord(0)->getItem("COMPRESSIBILITY")->getSIDouble(0); } else { std::cout << "**** warning: no rock compressibility data found in deck (ROCK or ROCKTAB)." << std::endl; } }
void PolymerInflowFromDeck::setInflowValues(Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclipseState, size_t currentStep) { Opm::DeckKeywordConstPtr keyword = deck->getKeyword("WPOLYMER"); // Schedule schedule(deck); ScheduleConstPtr schedule = eclipseState->getSchedule(); for (size_t recordNr = 0; recordNr < keyword->size(); recordNr++) { DeckRecordConstPtr record = keyword->getRecord(recordNr); const std::string& wellNamesPattern = record->getItem("WELL")->getTrimmedString(0); std::string wellName = record->getItem("WELL")->getTrimmedString(0); std::vector<WellPtr> wells = schedule->getWells(wellNamesPattern); for (auto wellIter = wells.begin(); wellIter != wells.end(); ++wellIter) { WellPtr well = *wellIter; WellInjectionProperties injection = well->getInjectionProperties(currentStep); if (injection.injectorType == WellInjector::WATER) { WellPolymerProperties polymer = well->getPolymerProperties(currentStep); wellPolymerRate_.insert(std::make_pair(wellName, polymer.m_polymerConcentration)); } else { OPM_THROW(std::logic_error, "For polymer injector you must have a water injector"); } } } }
std::vector<double> getMapaxesValues(Opm::DeckConstPtr deck) { Opm::DeckRecordConstPtr mapaxesRecord = deck->getKeyword("MAPAXES")->getRecord(0); std::vector<double> result; for (size_t itemIdx = 0; itemIdx < mapaxesRecord->size(); ++itemIdx) { Opm::DeckItemConstPtr curItem = mapaxesRecord->getItem(itemIdx); for (size_t dataItemIdx = 0; dataItemIdx < curItem->size(); ++dataItemIdx) { result.push_back(curItem->getRawDouble(dataItemIdx)); } } return result; }
std::vector<double> getMapaxesValues(Opm::DeckConstPtr deck) { const auto& mapaxesRecord = deck->getKeyword("MAPAXES").getRecord(0); std::vector<double> result; for (size_t itemIdx = 0; itemIdx < mapaxesRecord.size(); ++itemIdx) { const auto& curItem = mapaxesRecord.getItem(itemIdx); for (size_t dataItemIdx = 0; dataItemIdx < curItem.size(); ++dataItemIdx) { result.push_back(curItem.get< double >(dataItemIdx)); } } return result; }
void Rock<dim>::assignPorosity(Opm::DeckConstPtr deck, const std::vector<int>& global_cell) { porosity_.assign(global_cell.size(), 1.0); if (deck->hasKeyword("PORO")) { const std::vector<double>& poro = deck->getKeyword("PORO").getSIDoubleData(); for (int c = 0; c < int(porosity_.size()); ++c) { porosity_[c] = poro[global_cell[c]]; } } }
/// Mirror keyword SPECGRID in deck void mirror_specgrid(Opm::DeckConstPtr deck, std::string direction, std::ofstream& out) { // We only need to multiply the dimension by 2 in the correct direction. Opm::DeckRecordConstPtr specgridRecord = deck->getKeyword("SPECGRID")->getRecord(0); std::vector<int> dimensions(3); dimensions[0] = specgridRecord->getItem("NX")->getInt(0); dimensions[1] = specgridRecord->getItem("NY")->getInt(0); dimensions[2] = specgridRecord->getItem("NZ")->getInt(0); if (direction == "x") {dimensions[0] *= 2;} else if (direction == "y") {dimensions[1] *= 2;} else {std::cerr << "Direction should be either x or y" << std::endl; exit(1);} out << "SPECGRID" << std::endl << dimensions[0] << " " << dimensions[1] << " " << dimensions[2] << " " << specgridRecord->getItem("NUMRES")->getInt(0) << " " << specgridRecord->getItem("COORD_TYPE")->getString(0) << " " << std::endl << "/" << std::endl << std::endl; }
TimeMap::TimeMap(Opm::DeckConstPtr deck) { // The default start date is not specified in the Eclipse // reference manual. We hence just assume it is same as for // the START keyword for Eclipse R100, i.e., January 1st, // 1983... boost::posix_time::ptime startTime(boost::gregorian::date(1983, 1, 1)); // use the 'START' keyword to find out the start date (if the // keyword was specified) if (deck->hasKeyword("START")) { Opm::DeckKeywordConstPtr keyword = deck->getKeyword("START"); startTime = timeFromEclipse(keyword->getRecord(/*index=*/0)); } m_timeList.push_back( startTime ); // find all "TSTEP" and "DATES" keywords in the deck and deal // with them one after another size_t numKeywords = deck->size(); for (size_t keywordIdx = 0; keywordIdx < numKeywords; ++keywordIdx) { Opm::DeckKeywordConstPtr keyword = deck->getKeyword(keywordIdx); // We're only interested in "TSTEP" and "DATES" keywords, // so we ignore everything else here... if (keyword->name() != "TSTEP" && keyword->name() != "DATES") { continue; } if (keyword->name() == "TSTEP") addFromTSTEPKeyword(keyword); else if (keyword->name() == "DATES") addFromDATESKeyword(keyword); } }
/// Constructor. /// @param[in] deck Input deck expected to contain WPOLYMER. PolymerInflowFromDeck::PolymerInflowFromDeck(Opm::DeckConstPtr deck, const Wells& wells, const int num_cells) : sparse_inflow_(num_cells) { if (!deck->hasKeyword("WPOLYMER")) { OPM_MESSAGE("PolymerInflowFromDeck initialized without WPOLYMER in current epoch."); return; } // Extract concentrations and put into cell->concentration map. Opm::DeckKeywordConstPtr wpolymerKeyword = deck->getKeyword("WPOLYMER"); const int num_wpl = wpolymerKeyword->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 (wpolymerKeyword->getRecord(i)->getItem("WELL")->getString(0) == wells.name[wix]) { break; } } if (wix == wells.number_of_wells) { OPM_THROW(std::runtime_error, "Could not find a match for well " << wpolymerKeyword->getRecord(i)->getItem("WELL")->getString(0) << " 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] = wpolymerKeyword->getRecord(i)->getItem("POLYMER_CONCENTRATION")->getSIDouble(0); } } // 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 mirror_celldata(std::string keyword, Opm::DeckConstPtr deck, std::string direction, std::ofstream& out) { if ( ! deck->hasKeyword(keyword)) { std::cout << "Ignoring keyword " << keyword << " as it was not found." << std::endl; return; } // Get data from eclipse deck Opm::DeckRecordConstPtr specgridRecord = deck->getKeyword("SPECGRID")->getRecord(0); std::vector<int> dimensions(3); dimensions[0] = specgridRecord->getItem("NX")->getInt(0); dimensions[1] = specgridRecord->getItem("NY")->getInt(0); dimensions[2] = specgridRecord->getItem("NZ")->getInt(0); std::vector<T> values = getKeywordValues(keyword, deck, T(0.0)); std::vector<T> values_mirrored(2*dimensions[0]*dimensions[1]*dimensions[2], 0.0); // Handle the two directions differently due to ordering of the pillars. if (direction == "x") { typename std::vector<T>::iterator it_orig = values.begin(); typename std::vector<T>::iterator it_new = values_mirrored.begin(); // Loop through each line and copy old cell data and add new (which are the old reversed) for ( ; it_orig != values.end(); it_orig += dimensions[0]) { // Copy old cell data copy(it_orig, it_orig + dimensions[0], it_new); it_new += dimensions[0]; // Add new cell data std::vector<double> next_vec(it_orig, it_orig + dimensions[0]); std::vector<double> next_reversed = next_vec; reverse(next_reversed.begin(), next_reversed.end()); copy(next_reversed.begin(), next_reversed.end(), it_new); it_new += dimensions[0]; } } else if (direction =="y") { typename std::vector<T>::iterator it_orig = values.begin(); typename std::vector<T>::iterator it_new = values_mirrored.begin(); // Entries per layer const int entries_per_layer = dimensions[0]*dimensions[1]; // Loop through each layer and copy old cell data and add new (which are the old reordered) for ( ; it_orig != values.end(); it_orig += entries_per_layer) { // Copy old cell data copy(it_orig, it_orig + entries_per_layer, it_new); it_new += entries_per_layer; // Add new cell data std::vector<T> next_vec(it_orig, it_orig + entries_per_layer); std::vector<T> next_reordered(entries_per_layer, 0.0); typename std::vector<T>::iterator it_next = next_vec.end(); typename std::vector<T>::iterator it_reordered = next_reordered.begin(); // Reorder next entries for ( ; it_reordered != next_reordered.end(); it_reordered += dimensions[0]) { copy(it_next - dimensions[0], it_next, it_reordered); it_next -= dimensions[0]; } copy(next_reordered.begin(), next_reordered.end(), it_new); it_new += entries_per_layer; } } else { std::cerr << "Direction should be either x or y" << std::endl; exit(1); } // Write new keyword values to output file printKeywordValues(out, keyword, values_mirrored, 8); }
std::vector<double> getKeywordValues(std::string keyword, Opm::DeckConstPtr deck, double dummy) { return deck->getKeyword(keyword)->getRawDoubleData(); }
std::vector<int> getKeywordValues(std::string keyword, Opm::DeckConstPtr deck, int dummy) { return deck->getKeyword(keyword)->getIntData(); }
/// Mirror keyword ZCORN in deck void mirror_zcorn(Opm::DeckConstPtr deck, std::string direction, std::ofstream& out) { Opm::DeckRecordConstPtr specgridRecord = deck->getKeyword("SPECGRID")->getRecord(0); std::vector<int> dimensions(3); dimensions[0] = specgridRecord->getItem("NX")->getInt(0); dimensions[1] = specgridRecord->getItem("NY")->getInt(0); dimensions[2] = specgridRecord->getItem("NZ")->getInt(0); std::vector<double> zcorn = deck->getKeyword("ZCORN")->getRawDoubleData(); std::vector<double> zcorn_mirrored; // Handle the two directions differently due to ordering of the pillars. if (direction == "x") { // Total entries in mirrored ZCORN. Eight corners per cell. const int entries = dimensions[0]*2*dimensions[1]*dimensions[2]*8; zcorn_mirrored.assign(entries, 0.0); // Entries per line in x-direction. Two for each cell. const int entries_per_line = dimensions[0]*2; std::vector<double>::iterator it_new = zcorn_mirrored.begin(); std::vector<double>::iterator it_orig = zcorn.begin(); // Loop through each line and copy old corner-points and add new (which are the old reversed) for ( ; it_orig != zcorn.end(); it_orig += entries_per_line) { std::vector<double> next_vec(it_orig, it_orig + entries_per_line); std::vector<double> next_reversed = next_vec; reverse(next_reversed.begin(), next_reversed.end()); // Copy old corner-points copy(it_orig, it_orig + entries_per_line, it_new); it_new += entries_per_line; // Add new corner-points copy(next_reversed.begin(), next_reversed.end(), it_new); it_new += entries_per_line; } } else if (direction == "y") { // Total entries in mirrored ZCORN. Eight corners per cell. const int entries = dimensions[0]*dimensions[1]*2*dimensions[2]*8; zcorn_mirrored.assign(entries, 0.0); // Entries per line in x-direction. Two for each cell. const int entries_per_line_x = dimensions[0]*2; // Entries per layer of corner-points. Four for each cell const int entries_per_layer = dimensions[0]*dimensions[1]*4; std::vector<double>::iterator it_new = zcorn_mirrored.begin(); std::vector<double>::iterator it_orig = zcorn.begin(); // Loop through each layer and copy old corner-points and add new (which are the old reordered) for ( ; it_orig != zcorn.end(); it_orig += entries_per_layer) { // Copy old corner-points copy(it_orig, it_orig + entries_per_layer, it_new); it_new += entries_per_layer; // Add new corner-points std::vector<double> next_vec(it_orig, it_orig + entries_per_layer); std::vector<double> next_reordered(entries_per_layer, 0.0); std::vector<double>::iterator it_next = next_vec.end(); std::vector<double>::iterator it_reordered = next_reordered.begin(); // Reorder next entries for ( ; it_reordered != next_reordered.end(); it_reordered += entries_per_line_x) { copy(it_next - entries_per_line_x, it_next, it_reordered); it_next -= entries_per_line_x; } copy(next_reordered.begin(), next_reordered.end(), it_new); it_new += entries_per_layer; } } else { std::cerr << "Direction should be either x or y" << std::endl; exit(1); } // Write new ZCORN values to output file printKeywordValues(out, "ZCORN", zcorn_mirrored, 8); }
/// Mirror keyword COORD in deck void mirror_coord(Opm::DeckConstPtr deck, std::string direction, std::ofstream& out) { // We assume uniform spacing in x and y directions and parallel top and bottom faces Opm::DeckRecordConstPtr specgridRecord = deck->getKeyword("SPECGRID")->getRecord(0); std::vector<int> dimensions(3); dimensions[0] = specgridRecord->getItem("NX")->getInt(0); dimensions[1] = specgridRecord->getItem("NY")->getInt(0); dimensions[2] = specgridRecord->getItem("NZ")->getInt(0); std::vector<double> coord = deck->getKeyword("COORD")->getRawDoubleData(); const int entries_per_pillar = 6; std::vector<double> coord_mirrored; // Handle the two directions differently due to ordering of the pillars. if (direction == "x") { // Total entries in mirrored ZCORN. Number of pillars times 6 const int entries = (2*dimensions[0] + 1) * (dimensions[1] + 1) * entries_per_pillar; // Entries per line in x-direction. Number of pillars in x-direction times 6 const int entries_per_line = entries_per_pillar*(dimensions[0] + 1); coord_mirrored.assign(entries, 0.0); // Distance between pillars in x-directiion const double spacing = coord[entries_per_pillar]-coord[0]; std::vector<double>::iterator it_new = coord_mirrored.begin(); std::vector<double>::iterator it_orig; // Loop through each pillar line in the x-direction for (it_orig = coord.begin(); it_orig != coord.end(); it_orig += entries_per_line) { // Copy old pillars copy(it_orig, it_orig + entries_per_line, it_new); // Add new pillars in between it_new += entries_per_line; std::vector<double> next_vec(it_orig + entries_per_line - entries_per_pillar, it_orig + entries_per_line); for (int r=0; r < dimensions[0]; ++r) { next_vec[0] += spacing; next_vec[3] += spacing; copy(next_vec.begin(), next_vec.end(), it_new); it_new += entries_per_pillar; } } } else if (direction == "y") { // Total entries in mirrored ZCORN. Number of pillars times 6 const int entries = (dimensions[0] + 1) * (2*dimensions[1] + 1) * entries_per_pillar; // Entries per line in y-direction. Number of pillars in y-direction times 6 const int entries_per_line = entries_per_pillar*(dimensions[0] + 1); coord_mirrored.assign(entries, 0.0); // Distance between pillars in y-directiion const double spacing = coord[entries_per_line + 1]-coord[1]; std::vector<double>::iterator it_new = coord_mirrored.begin(); // Copy old pillars copy(coord.begin(), coord.end(), it_new); // Add new pillars at the end it_new += coord.size(); std::vector<double> next_vec(coord.end() - entries_per_line, coord.end()); for ( ; it_new != coord_mirrored.end(); it_new += entries_per_line) { for (int i = 1; i < entries_per_line; i += 3) { next_vec[i] += spacing; } copy(next_vec.begin(), next_vec.end(), it_new); } } else { std::cerr << "Direction should be either x or y" << std::endl; exit(1); } // Write new COORD values to output file printKeywordValues(out, "COORD", coord_mirrored, 6); }
void BlackoilPvtProperties::init(Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclipseState, int numSamples) { phase_usage_ = phaseUsageFromDeck(deck); // Surface densities. Accounting for different orders in eclipse and our code. Opm::DeckKeywordConstPtr densityKeyword = deck->getKeyword("DENSITY"); int numRegions = densityKeyword->size(); densities_.resize(numRegions); for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) { if (phase_usage_.phase_used[Liquid]) { densities_[regionIdx][phase_usage_.phase_pos[Liquid]] = densityKeyword->getRecord(regionIdx)->getItem("OIL")->getSIDouble(0); } if (phase_usage_.phase_used[Aqua]) { densities_[regionIdx][phase_usage_.phase_pos[Aqua]] = densityKeyword->getRecord(regionIdx)->getItem("WATER")->getSIDouble(0); } if (phase_usage_.phase_used[Vapour]) { densities_[regionIdx][phase_usage_.phase_pos[Vapour]] = densityKeyword->getRecord(regionIdx)->getItem("GAS")->getSIDouble(0); } } // Resize the property objects container props_.resize(phase_usage_.num_phases); // Water PVT if (phase_usage_.phase_used[Aqua]) { // if water is used, we require the presence of the "PVTW" // keyword for now... std::shared_ptr<PvtConstCompr> pvtw(new PvtConstCompr); pvtw->initFromWater(deck->getKeyword("PVTW")); props_[phase_usage_.phase_pos[Aqua]] = pvtw; } { auto tables = eclipseState->getTableManager(); // Oil PVT if (phase_usage_.phase_used[Liquid]) { // for oil, we support the "PVDO", "PVTO" and "PVCDO" // keywords... const auto &pvdoTables = tables->getPvdoTables(); const auto &pvtoTables = tables->getPvtoTables(); if (pvdoTables.size() > 0) { if (numSamples > 0) { auto splinePvt = std::shared_ptr<PvtDeadSpline>(new PvtDeadSpline); splinePvt->initFromOil(pvdoTables, numSamples); props_[phase_usage_.phase_pos[Liquid]] = splinePvt; } else { auto deadPvt = std::shared_ptr<PvtDead>(new PvtDead); deadPvt->initFromOil(pvdoTables); props_[phase_usage_.phase_pos[Liquid]] = deadPvt; } } else if (pvtoTables.size() > 0) { props_[phase_usage_.phase_pos[Liquid]].reset(new PvtLiveOil(pvtoTables)); } else if (deck->hasKeyword("PVCDO")) { std::shared_ptr<PvtConstCompr> pvcdo(new PvtConstCompr); pvcdo->initFromOil(deck->getKeyword("PVCDO")); props_[phase_usage_.phase_pos[Liquid]] = pvcdo; } else { OPM_THROW(std::runtime_error, "Input is missing PVDO, PVCDO or PVTO\n"); } } // Gas PVT if (phase_usage_.phase_used[Vapour]) { // gas can be specified using the "PVDG" or "PVTG" keywords... const auto &pvdgTables = tables->getPvdgTables(); const auto &pvtgTables = tables->getPvtgTables(); if (pvdgTables.size() > 0) { if (numSamples > 0) { std::shared_ptr<PvtDeadSpline> splinePvt(new PvtDeadSpline); splinePvt->initFromGas(pvdgTables, numSamples); props_[phase_usage_.phase_pos[Vapour]] = splinePvt; } else { std::shared_ptr<PvtDead> deadPvt(new PvtDead); deadPvt->initFromGas(pvdgTables); props_[phase_usage_.phase_pos[Vapour]] = deadPvt; } } else if (pvtgTables.size() > 0) { props_[phase_usage_.phase_pos[Vapour]].reset(new PvtLiveGas(pvtgTables)); } else { OPM_THROW(std::runtime_error, "Input is missing PVDG or PVTG\n"); } } } }
std::vector<std::shared_ptr<PvtInterface> > getProps(Opm::DeckConstPtr deck, PhaseUsage phase_usage_){ Opm::GridManager grid(deck); enum PhaseIndex { Aqua = 0, Liquid = 1, Vapour = 2 }; int samples = 0; std::vector<std::shared_ptr<PvtInterface> > props_; // Set the properties. props_.resize(phase_usage_.num_phases); // Water PVT if (phase_usage_.phase_used[Aqua]) { if (deck->hasKeyword("PVTW")) { std::shared_ptr<PvtConstCompr> pvtw(new PvtConstCompr); pvtw->initFromWater(deck->getKeyword("PVTW")); props_[phase_usage_.phase_pos[Aqua]] = pvtw; } else { // Eclipse 100 default. props_[phase_usage_.phase_pos[Aqua]].reset(new PvtConstCompr(0.5*Opm::prefix::centi*Opm::unit::Poise)); } } // Oil PVT if (phase_usage_.phase_used[Liquid]) { if (deck->hasKeyword("PVDO")) { Opm::DeckKeywordConstPtr pvdoKeyword(deck->getKeyword("PVDO")); if (samples > 0) { std::shared_ptr<PvtDeadSpline> splinePvt(new PvtDeadSpline); splinePvt->initFromOil(pvdoKeyword, samples); props_[phase_usage_.phase_pos[Liquid]] = splinePvt; } else { std::shared_ptr<PvtDead> deadPvt(new PvtDead); deadPvt->initFromOil(pvdoKeyword); props_[phase_usage_.phase_pos[Liquid]] = deadPvt; } } else if (deck->hasKeyword("PVTO")) { props_[phase_usage_.phase_pos[Liquid]].reset(new PvtLiveOil(deck->getKeyword("PVTO"))); } else if (deck->hasKeyword("PVCDO")) { std::shared_ptr<PvtConstCompr> pvcdo(new PvtConstCompr); pvcdo->initFromOil(deck->getKeyword("PVCDO")); props_[phase_usage_.phase_pos[Liquid]] = pvcdo; } else { OPM_THROW(std::runtime_error, "Input is missing PVDO, PVCDO or PVTO\n"); } } // Gas PVT if (phase_usage_.phase_used[Vapour]) { if (deck->hasKeyword("PVDG")) { Opm::DeckKeywordConstPtr pvdgKeyword(deck->getKeyword("PVDG")); if (samples > 0) { std::shared_ptr<PvtDeadSpline> splinePvt(new PvtDeadSpline); splinePvt->initFromGas(pvdgKeyword, samples); props_[phase_usage_.phase_pos[Vapour]] = splinePvt; } else { std::shared_ptr<PvtDead> deadPvt(new PvtDead); deadPvt->initFromGas(pvdgKeyword); props_[phase_usage_.phase_pos[Vapour]] = deadPvt; } } else if (deck->hasKeyword("PVTG")) { props_[phase_usage_.phase_pos[Vapour]].reset(new PvtLiveGas(deck->getKeyword("PVTG"))); } else { OPM_THROW(std::runtime_error, "Input is missing PVDG or PVTG\n"); } } return props_; }
void SatFuncBase<TableType>::init(Opm::DeckConstPtr newParserDeck, const int table_num, const PhaseUsage phase_usg, const int samples) { phase_usage = phase_usg; double swco = 0.0; double swmax = 1.0; if (phase_usage.phase_used[Aqua]) { Opm::SwofTable swof(newParserDeck->getKeyword("SWOF"), table_num); const std::vector<double>& sw = swof.getSwColumn(); const std::vector<double>& krw = swof.getKrwColumn(); const std::vector<double>& krow = swof.getKrowColumn(); const std::vector<double>& pcow = swof.getPcowColumn(); if (krw.front() != 0.0 || krow.back() != 0.0) { OPM_THROW(std::runtime_error, "Error SWOF data - non-zero krw(swco) and/or krow(1-sor)"); } // Extend the tables with constant values such that the // derivatives at the endpoints are zero int n = sw.size(); std::vector<double> sw_ex(n+2); std::vector<double> krw_ex(n+2); std::vector<double> krow_ex(n+2); std::vector<double> pcow_ex(n+2); extendTable(sw,sw_ex,1); extendTable(krw,krw_ex,0); extendTable(krow,krow_ex,0); extendTable(pcow,pcow_ex,0); initializeTableType(krw_,sw_ex, krw_ex, samples); initializeTableType(krow_,sw_ex, krow_ex, samples); initializeTableType(pcow_,sw_ex, pcow_ex, samples); krocw_ = krow[0]; // At connate water -> ecl. SWOF swco = sw[0]; smin_[phase_usage.phase_pos[Aqua]] = sw[0]; swmax = sw.back(); smax_[phase_usage.phase_pos[Aqua]] = sw.back(); krwmax_ = krw.back(); kromax_ = krow.front(); swcr_ = swmax; sowcr_ = 1.0 - swco; krwr_ = krw.back(); krorw_ = krow.front(); for (std::vector<double>::size_type i=1; i<sw.size(); ++i) { if (krw[i]> 0.0) { swcr_ = sw[i-1]; krorw_ = krow[i-1]; break; } } for (std::vector<double>::size_type i=sw.size()-1; i>=1; --i) { if (krow[i-1]> 0.0) { sowcr_ = 1.0 - sw[i]; krwr_ = krw[i]; break; } } } if (phase_usage.phase_used[Vapour]) { Opm::SgofTable sgof(newParserDeck->getKeyword("SGOF"), table_num); const std::vector<double>& sg = sgof.getSgColumn(); const std::vector<double>& krg = sgof.getKrgColumn(); const std::vector<double>& krog = sgof.getKrogColumn(); const std::vector<double>& pcog = sgof.getPcogColumn(); // Extend the tables with constant values such that the // derivatives at the endpoints are zero int n = sg.size(); std::vector<double> sg_ex(n+2); std::vector<double> krg_ex(n+2); std::vector<double> krog_ex(n+2); std::vector<double> pcog_ex(n+2); extendTable(sg,sg_ex,1); extendTable(krg,krg_ex,0); extendTable(krog,krog_ex,0); extendTable(pcog,pcog_ex,0); initializeTableType(krg_,sg_ex, krg_ex, samples); initializeTableType(krog_,sg_ex, krog_ex, samples); initializeTableType(pcog_,sg_ex, pcog_ex, samples); smin_[phase_usage.phase_pos[Vapour]] = sg[0]; if (std::fabs(sg.back() + swco - 1.0) > 1e-3) { OPM_THROW(std::runtime_error, "Gas maximum saturation in SGOF table = " << sg.back() << ", should equal (1.0 - connate water sat) = " << (1.0 - swco)); } smax_[phase_usage.phase_pos[Vapour]] = sg.back(); smin_[phase_usage.phase_pos[Vapour]] = sg.front(); krgmax_ = krg.back(); sgcr_ = sg.front(); sogcr_ = 1.0 - sg.back(); krgr_ = krg.back(); krorg_ = krg.front(); for (std::vector<double>::size_type i=1; i<sg.size(); ++i) { if (krg[i]> 0.0) { sgcr_ = sg[i-1]; krorg_ = krog[i-1]; break; } } for (std::vector<double>::size_type i=sg.size()-1; i>=1; --i) { if (krog[i-1]> 0.0) { sogcr_ = 1.0 - sg[i]; krgr_ = krg[i]; break; } } } if (phase_usage.phase_used[Vapour] && phase_usage.phase_used[Aqua]) { sowcr_ -= smin_[phase_usage.phase_pos[Vapour]]; sogcr_ -= smin_[phase_usage.phase_pos[Aqua]]; smin_[phase_usage.phase_pos[Liquid]] = 0.0; smax_[phase_usage.phase_pos[Liquid]] = 1.0 - smin_[phase_usage.phase_pos[Aqua]] - smin_[phase_usage.phase_pos[Vapour]]; // First entry in SGOF-table supposed to be zero anyway ... } else if (phase_usage.phase_used[Aqua]) { smin_[phase_usage.phase_pos[Liquid]] = 1.0 - smax_[phase_usage.phase_pos[Aqua]]; smax_[phase_usage.phase_pos[Liquid]] = 1.0 - smin_[phase_usage.phase_pos[Aqua]]; } else if (phase_usage.phase_used[Vapour]) { smin_[phase_usage.phase_pos[Liquid]] = 1.0 - smax_[phase_usage.phase_pos[Vapour]]; smax_[phase_usage.phase_pos[Liquid]] = 1.0 - smin_[phase_usage.phase_pos[Vapour]]; } }
/*! * \brief Reads all relevant material parameters form a cell of a parsed ECL deck. * * This requires that the opm-parser module is available. */ void initFromDeck(Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclState, Opm::EclTwoPhaseSystemType twoPhaseSystemType) { // find out if endpoint scaling is used in the first place if (!deck->hasKeyword("ENDSCALE")) { // it is not used, i.e., just set all enable$Foo attributes to 0 and be done // with it. enableSatScaling_ = false; enableThreePointKrSatScaling_ = false; enablePcScaling_ = false; enableKrwScaling_ = false; enableKrnScaling_ = false; return; } // endpoint scaling is used, i.e., at least saturation scaling needs to be enabled enableSatScaling_ = true; // check if three-point scaling is to be used for the saturations of the relative // permeabilities if (deck->hasKeyword("SCALECRS")) { // if the deck features the SCALECRS keyword, it must be set to 'YES' Opm::DeckKeywordConstPtr scalecrsKeyword = deck->getKeyword("SCALECRS"); std::string scalecrsValue = scalecrsKeyword->getRecord(0)->getItem("VALUE")->getString(0); // convert the value of the SCALECRS keyword to upper case, just to be sure std::transform(scalecrsValue.begin(), scalecrsValue.end(), scalecrsValue.begin(), ::toupper); if (scalecrsValue == "YES" || scalecrsValue == "Y") enableThreePointKrSatScaling_ = true; else enableThreePointKrSatScaling_ = false; } else enableThreePointKrSatScaling_ = false; // check if we are supposed to scale the Y axis of the capillary pressure if (twoPhaseSystemType == EclOilWaterSystem) enablePcScaling_ = eclState->hasDoubleGridProperty("PCW") || eclState->hasDoubleGridProperty("SWATINIT"); else { assert(twoPhaseSystemType == EclGasOilSystem); enablePcScaling_ = eclState->hasDoubleGridProperty("PCG"); } // check if we are supposed to scale the Y axis of the wetting phase relperm if (twoPhaseSystemType == EclOilWaterSystem) enableKrwScaling_ = eclState->hasDoubleGridProperty("KRW"); else { assert(twoPhaseSystemType == EclGasOilSystem); enableKrwScaling_ = eclState->hasDoubleGridProperty("KRO"); } // check if we are supposed to scale the Y axis of the non-wetting phase relperm if (twoPhaseSystemType == EclOilWaterSystem) enableKrnScaling_ = eclState->hasDoubleGridProperty("KRO"); else { assert(twoPhaseSystemType == EclGasOilSystem); enableKrnScaling_ = eclState->hasDoubleGridProperty("KRG"); } }