00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 namespace Opm
00023 {
00024 template <class GridT>
00025 SimulatorFullyImplicitBlackoilPolymer<GridT>::
00026 SimulatorFullyImplicitBlackoilPolymer(const ParameterGroup& param,
00027 const GridT& grid,
00028 DerivedGeology& geo,
00029 BlackoilPropsAdFromDeck& props,
00030 const PolymerPropsAd& polymer_props,
00031 const RockCompressibility* rock_comp_props,
00032 NewtonIterationBlackoilInterface& linsolver,
00033 const double* gravity,
00034 const bool has_disgas,
00035 const bool has_vapoil,
00036 const bool has_polymer,
00037 const bool has_plyshlog,
00038 const bool has_shrate,
00039 std::shared_ptr<EclipseState> eclipse_state,
00040 BlackoilOutputWriter& output_writer,
00041 std::shared_ptr< Deck > deck,
00042 const std::vector<double>& threshold_pressures_by_face)
00043 : BaseType(param,
00044 grid,
00045 geo,
00046 props,
00047 rock_comp_props,
00048 linsolver,
00049 gravity,
00050 has_disgas,
00051 has_vapoil,
00052 eclipse_state,
00053 output_writer,
00054 threshold_pressures_by_face,
00055
00056 std::unordered_set<std::string>())
00057 , polymer_props_(polymer_props)
00058 , has_polymer_(has_polymer)
00059 , has_plyshlog_(has_plyshlog)
00060 , has_shrate_(has_shrate)
00061 , deck_(deck)
00062 {
00063 }
00064
00065 template <class GridT>
00066 auto SimulatorFullyImplicitBlackoilPolymer<GridT>::
00067 createSolver(const WellModel& well_model)
00068 -> std::unique_ptr<Solver>
00069 {
00070 typedef typename Traits::Model Model;
00071
00072
00073 auto model = std::unique_ptr<Model>(new Model(BaseType::model_param_,
00074 BaseType::grid_,
00075 BaseType::props_,
00076 BaseType::geo_,
00077 BaseType::rock_comp_props_,
00078 polymer_props_,
00079 well_model,
00080 BaseType::solver_,
00081 BaseType::eclipse_state_,
00082 BaseType::has_disgas_,
00083 BaseType::has_vapoil_,
00084 has_polymer_,
00085 has_plyshlog_,
00086 has_shrate_,
00087 wells_rep_radius_,
00088 wells_perf_length_,
00089 wells_bore_diameter_,
00090 BaseType::terminal_output_));
00091
00092 if (!BaseType::threshold_pressures_by_face_.empty()) {
00093 model->setThresholdPressures(BaseType::threshold_pressures_by_face_);
00094 }
00095
00096 return std::unique_ptr<Solver>(new Solver(BaseType::solver_param_, std::move(model)));
00097 }
00098
00099
00100
00101
00102 template <class GridT>
00103 void SimulatorFullyImplicitBlackoilPolymer<GridT>::
00104 handleAdditionalWellInflow(SimulatorTimer& timer,
00105 WellsManager& wells_manager,
00106 typename BaseType::WellState& well_state,
00107 const Wells* wells)
00108 {
00109
00110 std::unique_ptr<PolymerInflowInterface> polymer_inflow_ptr;
00111 if (deck_->hasKeyword("WPOLYMER")) {
00112 if (wells_manager.c_wells() == 0) {
00113 OPM_THROW(std::runtime_error, "Cannot control polymer injection via WPOLYMER without wells.");
00114 }
00115 polymer_inflow_ptr.reset(new PolymerInflowFromDeck(*BaseType::eclipse_state_, *wells, Opm::UgGridHelpers::numCells(BaseType::grid_), timer.currentStepNum()));
00116 } else {
00117 OPM_MESSAGE("Warning: simulating with no WPOLYMER in deck (no polymer will be injected).");
00118 polymer_inflow_ptr.reset(new PolymerInflowBasic(0.0*Opm::unit::day,
00119 1.0*Opm::unit::day,
00120 0.0));
00121 }
00122 std::vector<double> polymer_inflow_c(Opm::UgGridHelpers::numCells(BaseType::grid_));
00123 polymer_inflow_ptr->getInflowValues(timer.simulationTimeElapsed(),
00124 timer.simulationTimeElapsed() + timer.currentStepLength(),
00125 polymer_inflow_c);
00126 well_state.polymerInflow() = polymer_inflow_c;
00127
00128 if (has_plyshlog_) {
00129 computeRepRadiusPerfLength(*BaseType::eclipse_state_, timer.currentStepNum(), BaseType::grid_, wells_rep_radius_, wells_perf_length_, wells_bore_diameter_);
00130 }
00131 }
00132
00133
00134 template <class GridT>
00135 void SimulatorFullyImplicitBlackoilPolymer<GridT>::
00136 setupCompressedToCartesian(const int* global_cell, int number_of_cells,
00137 std::map<int,int>& cartesian_to_compressed )
00138 {
00139 if (global_cell) {
00140 for (int i = 0; i < number_of_cells; ++i) {
00141 cartesian_to_compressed.insert(std::make_pair(global_cell[i], i));
00142 }
00143 }
00144 else {
00145 for (int i = 0; i < number_of_cells; ++i) {
00146 cartesian_to_compressed.insert(std::make_pair(i, i));
00147 }
00148 }
00149
00150 }
00151
00152
00153 template <class GridT>
00154 void SimulatorFullyImplicitBlackoilPolymer<GridT>::
00155 computeRepRadiusPerfLength(const Opm::EclipseState& eclipseState,
00156 const size_t timeStep,
00157 const GridT& grid,
00158 std::vector<double>& wells_rep_radius,
00159 std::vector<double>& wells_perf_length,
00160 std::vector<double>& wells_bore_diameter)
00161 {
00162
00163
00164
00165 int number_of_cells = Opm::UgGridHelpers::numCells(grid);
00166 const int* global_cell = Opm::UgGridHelpers::globalCell(grid);
00167 const int* cart_dims = Opm::UgGridHelpers::cartDims(grid);
00168 auto cell_to_faces = Opm::UgGridHelpers::cell2Faces(grid);
00169 auto begin_face_centroids = Opm::UgGridHelpers::beginFaceCentroids(grid);
00170
00171 if (eclipseState.getSchedule().numWells() == 0) {
00172 OPM_MESSAGE("No wells specified in Schedule section, "
00173 "initializing no wells");
00174 return;
00175 }
00176
00177 const size_t n_perf = wells_rep_radius.size();
00178
00179 wells_rep_radius.clear();
00180 wells_perf_length.clear();
00181 wells_bore_diameter.clear();
00182
00183 wells_rep_radius.reserve(n_perf);
00184 wells_perf_length.reserve(n_perf);
00185 wells_bore_diameter.reserve(n_perf);
00186
00187 std::map<int,int> cartesian_to_compressed;
00188
00189 setupCompressedToCartesian(global_cell, number_of_cells,
00190 cartesian_to_compressed);
00191
00192 const auto& schedule = eclipseState.getSchedule();
00193 auto wells = schedule.getWells(timeStep);
00194
00195 int well_index = 0;
00196
00197 for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
00198 const auto* well = (*wellIter);
00199
00200 if (well->getStatus(timeStep) == WellCommon::SHUT) {
00201 continue;
00202 }
00203 {
00204 const auto& completionSet = well->getCompletions(timeStep);
00205 for (size_t c=0; c<completionSet.size(); c++) {
00206 const auto& completion = completionSet.get(c);
00207 if (completion.getState() == WellCompletion::OPEN) {
00208 int i = completion.getI();
00209 int j = completion.getJ();
00210 int k = completion.getK();
00211
00212 const int* cpgdim = cart_dims;
00213 int cart_grid_indx = i + cpgdim[0]*(j + cpgdim[1]*k);
00214 std::map<int, int>::const_iterator cgit = cartesian_to_compressed.find(cart_grid_indx);
00215 if (cgit == cartesian_to_compressed.end()) {
00216 OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << i << ' ' << j << ' '
00217 << k << " not found in grid (well = " << well->name() << ')');
00218 }
00219 int cell = cgit->second;
00220
00221 {
00222 double radius = 0.5*completion.getDiameter();
00223 if (radius <= 0.0) {
00224 radius = 0.5*unit::feet;
00225 OPM_MESSAGE("**** Warning: Well bore internal radius set to " << radius);
00226 }
00227
00228 const std::array<double, 3> cubical =
00229 WellsManagerDetail::getCubeDim<3>(cell_to_faces, begin_face_centroids, cell);
00230
00231 WellCompletion::DirectionEnum direction = completion.getDirection();
00232
00233 double re;
00234 double perf_length;
00235
00236 switch (direction) {
00237 case Opm::WellCompletion::DirectionEnum::X:
00238 re = std::sqrt(cubical[1] * cubical[2] / M_PI);
00239 perf_length = cubical[0];
00240 break;
00241 case Opm::WellCompletion::DirectionEnum::Y:
00242 re = std::sqrt(cubical[0] * cubical[2] / M_PI);
00243 perf_length = cubical[1];
00244 break;
00245 case Opm::WellCompletion::DirectionEnum::Z:
00246 re = std::sqrt(cubical[0] * cubical[1] / M_PI);
00247 perf_length = cubical[2];
00248 break;
00249 default:
00250 OPM_THROW(std::runtime_error, " Dirtecion of well is not supported ");
00251 }
00252
00253 double repR = std::sqrt(re * radius);
00254 wells_rep_radius.push_back(repR);
00255 wells_perf_length.push_back(perf_length);
00256 wells_bore_diameter.push_back(2. * radius);
00257 }
00258 } else {
00259 if (completion.getState() != WellCompletion::SHUT) {
00260 OPM_THROW(std::runtime_error, "Completion state: " << WellCompletion::StateEnum2String( completion.getState() ) << " not handled");
00261 }
00262 }
00263
00264 }
00265 }
00266 well_index++;
00267 }
00268 }
00269
00270 }