/// Looks at presence of WATER, OIL and GAS keywords in state object /// to determine active phases. inline PhaseUsage phaseUsageFromDeck(const Opm::EclipseState& eclipseState) { PhaseUsage pu; std::fill(pu.phase_used, pu.phase_used + BlackoilPhases::MaxNumPhases, 0); const auto& phase = eclipseState.runspec().phases(); // Discover phase usage. if (phase.active(Phase::WATER)) { pu.phase_used[BlackoilPhases::Aqua] = 1; } if (phase.active(Phase::OIL)) { pu.phase_used[BlackoilPhases::Liquid] = 1; } if (phase.active(Phase::GAS)) { pu.phase_used[BlackoilPhases::Vapour] = 1; } pu.num_phases = 0; for (int i = 0; i < BlackoilPhases::MaxNumPhases; ++i) { pu.phase_pos[i] = pu.num_phases; pu.num_phases += pu.phase_used[i]; } // Only 2 or 3 phase systems handled. if (pu.num_phases < 2 || pu.num_phases > 3) { OPM_THROW(std::runtime_error, "Cannot handle cases with " << pu.num_phases << " phases."); } // We need oil systems, since we do not support the keywords needed for // water-gas systems. if (!pu.phase_used[BlackoilPhases::Liquid]) { OPM_THROW(std::runtime_error, "Cannot handle cases with no OIL, i.e. water-gas systems."); } return pu; }
void extractPvtTableIndex(std::vector<int> &pvtTableIdx, const Opm::EclipseState& eclState, size_t numCompressed, const int *compressedToCartesianCellIdx) { //Get the PVTNUM data const std::vector<int>& pvtnumData = eclState.get3DProperties().getIntGridProperty("PVTNUM").getData(); // Convert this into an array of compressed cells // Eclipse uses Fortran-style indices which start at 1 // instead of 0, we subtract 1. pvtTableIdx.resize(numCompressed); for (size_t cellIdx = 0; cellIdx < numCompressed; ++ cellIdx) { size_t cartesianCellIdx = compressedToCartesianCellIdx ? compressedToCartesianCellIdx[cellIdx]:cellIdx; assert(cartesianCellIdx < pvtnumData.size()); pvtTableIdx[cellIdx] = pvtnumData[cartesianCellIdx] - 1; } }
void SimulatorFullyImplicitBlackoilPolymer<GridT>:: computeRepRadiusPerfLength(const Opm::EclipseState& eclipseState, const size_t timeStep, const GridT& grid, std::vector<double>& wells_rep_radius, std::vector<double>& wells_perf_length, std::vector<double>& wells_bore_diameter) { // TODO, the function does not work for parallel running // to be fixed later. int number_of_cells = Opm::UgGridHelpers::numCells(grid); const int* global_cell = Opm::UgGridHelpers::globalCell(grid); const int* cart_dims = Opm::UgGridHelpers::cartDims(grid); auto cell_to_faces = Opm::UgGridHelpers::cell2Faces(grid); auto begin_face_centroids = Opm::UgGridHelpers::beginFaceCentroids(grid); if (eclipseState.getSchedule().numWells() == 0) { OPM_MESSAGE("No wells specified in Schedule section, " "initializing no wells"); return; } const size_t n_perf = wells_rep_radius.size(); wells_rep_radius.clear(); wells_perf_length.clear(); wells_bore_diameter.clear(); wells_rep_radius.reserve(n_perf); wells_perf_length.reserve(n_perf); wells_bore_diameter.reserve(n_perf); std::map<int,int> cartesian_to_compressed; setupCompressedToCartesian(global_cell, number_of_cells, cartesian_to_compressed); const auto& schedule = eclipseState.getSchedule(); auto wells = schedule.getWells(timeStep); int well_index = 0; for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) { const auto* well = (*wellIter); if (well->getStatus(timeStep) == WellCommon::SHUT) { continue; } { // COMPDAT handling const auto& completionSet = well->getCompletions(timeStep); for (size_t c=0; c<completionSet.size(); c++) { const auto& completion = completionSet.get(c); if (completion.getState() == WellCompletion::OPEN) { int i = completion.getI(); int j = completion.getJ(); int k = completion.getK(); const int* cpgdim = cart_dims; int cart_grid_indx = i + cpgdim[0]*(j + cpgdim[1]*k); std::map<int, int>::const_iterator cgit = cartesian_to_compressed.find(cart_grid_indx); if (cgit == cartesian_to_compressed.end()) { OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << i << ' ' << j << ' ' << k << " not found in grid (well = " << well->name() << ')'); } int cell = cgit->second; { double radius = 0.5*completion.getDiameter(); if (radius <= 0.0) { radius = 0.5*unit::feet; OPM_MESSAGE("**** Warning: Well bore internal radius set to " << radius); } const std::array<double, 3> cubical = WellsManagerDetail::getCubeDim<3>(cell_to_faces, begin_face_centroids, cell); WellCompletion::DirectionEnum direction = completion.getDirection(); double re; // area equivalent radius of the grid block double perf_length; // the length of the well perforation switch (direction) { case Opm::WellCompletion::DirectionEnum::X: re = std::sqrt(cubical[1] * cubical[2] / M_PI); perf_length = cubical[0]; break; case Opm::WellCompletion::DirectionEnum::Y: re = std::sqrt(cubical[0] * cubical[2] / M_PI); perf_length = cubical[1]; break; case Opm::WellCompletion::DirectionEnum::Z: re = std::sqrt(cubical[0] * cubical[1] / M_PI); perf_length = cubical[2]; break; default: OPM_THROW(std::runtime_error, " Dirtecion of well is not supported "); } double repR = std::sqrt(re * radius); wells_rep_radius.push_back(repR); wells_perf_length.push_back(perf_length); wells_bore_diameter.push_back(2. * radius); } } else { if (completion.getState() != WellCompletion::SHUT) { OPM_THROW(std::runtime_error, "Completion state: " << WellCompletion::StateEnum2String( completion.getState() ) << " not handled"); } } } } well_index++; } }
/// Looks at presence of WATER, OIL and GAS keywords in state object /// to determine active phases. inline PhaseUsage phaseUsageFromDeck(const Opm::EclipseState& eclipseState) { const auto& phases = eclipseState.runspec().phases(); return phaseUsage(phases); }
/// set the tables which specify the temperature dependence of the oil viscosity void initFromDeck(std::shared_ptr<const PvtInterface> isothermalPvt, const Opm::Deck& deck, const Opm::EclipseState& eclipseState) { isothermalPvt_ = isothermalPvt; int numRegions; auto tables = eclipseState->getTableManager(); if (deck->hasKeyword("PVTO")) numRegions = tables->getPvtoTables().size(); else if (deck->hasKeyword("PVDO")) numRegions = tables->getPvdoTables().size(); else if (deck->hasKeyword("PVCDO")) numRegions = deck->getKeyword("PVCDO").size(); else OPM_THROW(std::runtime_error, "Oil phase was not initialized using a known way"); // viscosity if (deck->hasKeyword("VISCREF")) { oilvisctTables_ = &tables->getOilvisctTables(); const auto& viscrefKeyword = deck->getKeyword("VISCREF"); assert(int(oilvisctTables_->size()) == numRegions); assert(int(viscrefKeyword.size()) == numRegions); viscrefPress_.resize(numRegions); viscrefRs_.resize(numRegions); muRef_.resize(numRegions); for (int regionIdx = 0; regionIdx < numRegions; ++regionIdx) { 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... double Tref = 273.15 + 20; // compute the reference viscosity using the isothermal PVT object. double tmp1, tmp2; isothermalPvt_->mu(1, ®ionIdx, &viscrefPress_[regionIdx], &Tref, &viscrefRs_[regionIdx], &muRef_[regionIdx], &tmp1, &tmp2); } } // quantities required for density. note that we just always use the values // for the first EOS. (since EOS != PVT region.) tref_ = 0.0; if (deck->hasKeyword("THERMEX1")) { oilCompIdx_ = deck->getKeyword("OCOMPIDX").getRecord(0).getItem("OIL_COMPONENT_INDEX").get< int >(0) - 1; // always use the values of the first EOS tref_ = deck->getKeyword("TREF").getRecord(0).getItem("TEMPERATURE").getSIDouble(oilCompIdx_); pref_ = deck->getKeyword("PREF").getRecord(0).getItem("PRESSURE").getSIDouble(oilCompIdx_); cref_ = deck->getKeyword("CREF").getRecord(0).getItem("COMPRESSIBILITY").getSIDouble(oilCompIdx_); thermex1_ = deck->getKeyword("THERMEX1").getRecord(0).getItem("EXPANSION_COEFF").getSIDouble(oilCompIdx_); } }