SimulatorFullyImplicitBlackoilPolymer_impl.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013 SINTEF ICT, Applied Mathematics.
3 Copyright 2014 IRIS AS
4 Copyright 2014 STATOIL ASA.
5
6 This file is part of the Open Porous Media project (OPM).
7
8 OPM is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 OPM is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with OPM. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22namespace Opm
23{
24 template <class GridT>
26 SimulatorFullyImplicitBlackoilPolymer(const parameter::ParameterGroup& param,
27 const GridT& grid,
28 DerivedGeology& geo,
29 BlackoilPropsAdInterface& props,
30 const PolymerPropsAd& polymer_props,
31 const RockCompressibility* rock_comp_props,
32 NewtonIterationBlackoilInterface& linsolver,
33 const double* gravity,
34 const bool has_disgas,
35 const bool has_vapoil,
36 const bool has_polymer,
37 const bool has_plyshlog,
38 const bool has_shrate,
39 std::shared_ptr<EclipseState> eclipse_state,
40 BlackoilOutputWriter& output_writer,
41 Opm::DeckConstPtr& deck,
42 const std::vector<double>& threshold_pressures_by_face)
43 : BaseType(param,
44 grid,
45 geo,
46 props,
47 rock_comp_props,
48 linsolver,
49 gravity,
50 has_disgas,
51 has_vapoil,
52 eclipse_state,
53 output_writer,
54 threshold_pressures_by_face)
55 , polymer_props_(polymer_props)
56 , has_polymer_(has_polymer)
57 , has_plyshlog_(has_plyshlog)
58 , has_shrate_(has_shrate)
59 , deck_(deck)
60 {
61 }
62
63 template <class GridT>
65 createSolver(const Wells* wells)
66 -> std::unique_ptr<Solver>
67 {
68 typedef typename Traits::Model Model;
69
70
71 auto model = std::unique_ptr<Model>(new Model(BaseType::model_param_,
72 BaseType::grid_,
73 BaseType::props_,
74 BaseType::geo_,
75 BaseType::rock_comp_props_,
76 polymer_props_,
77 wells,
78 BaseType::solver_,
79 BaseType::eclipse_state_,
80 BaseType::has_disgas_,
81 BaseType::has_vapoil_,
82 has_polymer_,
83 has_plyshlog_,
84 has_shrate_,
85 wells_rep_radius_,
86 wells_perf_length_,
87 wells_bore_diameter_,
88 BaseType::terminal_output_));
89
90 if (!BaseType::threshold_pressures_by_face_.empty()) {
91 model->setThresholdPressures(BaseType::threshold_pressures_by_face_);
92 }
93
94 return std::unique_ptr<Solver>(new Solver(BaseType::solver_param_, std::move(model)));
95 }
96
97
98
99
100 template <class GridT>
102 handleAdditionalWellInflow(SimulatorTimer& timer,
103 WellsManager& wells_manager,
104 typename BaseType::WellState& well_state,
105 const Wells* wells)
106 {
107 // compute polymer inflow
108 std::unique_ptr<PolymerInflowInterface> polymer_inflow_ptr;
109 if (deck_->hasKeyword("WPOLYMER")) {
110 if (wells_manager.c_wells() == 0) {
111 OPM_THROW(std::runtime_error, "Cannot control polymer injection via WPOLYMER without wells.");
112 }
113 polymer_inflow_ptr.reset(new PolymerInflowFromDeck(deck_, BaseType::eclipse_state_, *wells, Opm::UgGridHelpers::numCells(BaseType::grid_), timer.currentStepNum()));
114 } else {
115 polymer_inflow_ptr.reset(new PolymerInflowBasic(0.0*Opm::unit::day,
116 1.0*Opm::unit::day,
117 0.0));
118 }
119 std::vector<double> polymer_inflow_c(Opm::UgGridHelpers::numCells(BaseType::grid_));
120 polymer_inflow_ptr->getInflowValues(timer.simulationTimeElapsed(),
121 timer.simulationTimeElapsed() + timer.currentStepLength(),
122 polymer_inflow_c);
123 well_state.polymerInflow() = polymer_inflow_c;
124
125 computeRepRadiusPerfLength(BaseType::eclipse_state_, timer.currentStepNum(), BaseType::grid_, wells_rep_radius_, wells_perf_length_, wells_bore_diameter_);
126 }
127
128
129 template <class GridT>
131 setupCompressedToCartesian(const int* global_cell, int number_of_cells,
132 std::map<int,int>& cartesian_to_compressed )
133 {
134 if (global_cell) {
135 for (int i = 0; i < number_of_cells; ++i) {
136 cartesian_to_compressed.insert(std::make_pair(global_cell[i], i));
137 }
138 }
139 else {
140 for (int i = 0; i < number_of_cells; ++i) {
141 cartesian_to_compressed.insert(std::make_pair(i, i));
142 }
143 }
144
145 }
146
147
148 template <class GridT>
149 void SimulatorFullyImplicitBlackoilPolymer<GridT>::
150 computeRepRadiusPerfLength(const Opm::EclipseStateConstPtr eclipseState,
151 const size_t timeStep,
152 const GridT& grid,
153 std::vector<double>& wells_rep_radius,
154 std::vector<double>& wells_perf_length,
155 std::vector<double>& wells_bore_diameter)
156 {
157
158 // TODO, the function does not work for parallel running
159 // to be fixed later.
160 int number_of_cells = Opm::UgGridHelpers::numCells(grid);
161 const int* global_cell = Opm::UgGridHelpers::globalCell(grid);
162 const int* cart_dims = Opm::UgGridHelpers::cartDims(grid);
163 auto cell_to_faces = Opm::UgGridHelpers::cell2Faces(grid);
164 auto begin_face_centroids = Opm::UgGridHelpers::beginFaceCentroids(grid);
165
166 if (eclipseState->getSchedule()->numWells() == 0) {
167 OPM_MESSAGE("No wells specified in Schedule section, "
168 "initializing no wells");
169 return;
170 }
171
172 const size_t n_perf = wells_rep_radius.size();
173
174 wells_rep_radius.clear();
175 wells_perf_length.clear();
176 wells_bore_diameter.clear();
177
178 wells_rep_radius.reserve(n_perf);
179 wells_perf_length.reserve(n_perf);
180 wells_bore_diameter.reserve(n_perf);
181
182 std::map<int,int> cartesian_to_compressed;
183
184 setupCompressedToCartesian(global_cell, number_of_cells,
185 cartesian_to_compressed);
186
187 ScheduleConstPtr schedule = eclipseState->getSchedule();
188 std::vector<WellConstPtr> wells = schedule->getWells(timeStep);
189
190 int well_index = 0;
191
192 for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
193 WellConstPtr well = (*wellIter);
194
195 if (well->getStatus(timeStep) == WellCommon::SHUT) {
196 continue;
197 }
198 { // COMPDAT handling
199 CompletionSetConstPtr completionSet = well->getCompletions(timeStep);
200 for (size_t c=0; c<completionSet->size(); c++) {
201 CompletionConstPtr completion = completionSet->get(c);
202 if (completion->getState() == WellCompletion::OPEN) {
203 int i = completion->getI();
204 int j = completion->getJ();
205 int k = completion->getK();
206
207 const int* cpgdim = cart_dims;
208 int cart_grid_indx = i + cpgdim[0]*(j + cpgdim[1]*k);
209 std::map<int, int>::const_iterator cgit = cartesian_to_compressed.find(cart_grid_indx);
210 if (cgit == cartesian_to_compressed.end()) {
211 OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << i << ' ' << j << ' '
212 << k << " not found in grid (well = " << well->name() << ')');
213 }
214 int cell = cgit->second;
215
216 {
217 double radius = 0.5*completion->getDiameter();
218 if (radius <= 0.0) {
219 radius = 0.5*unit::feet;
220 OPM_MESSAGE("**** Warning: Well bore internal radius set to " << radius);
221 }
222
223 const std::array<double, 3> cubical =
224 WellsManagerDetail::getCubeDim<3>(cell_to_faces, begin_face_centroids, cell);
225
226 WellCompletion::DirectionEnum direction = completion->getDirection();
227
228 double re; // area equivalent radius of the grid block
229 double perf_length; // the length of the well perforation
230
231 switch (direction) {
232 case Opm::WellCompletion::DirectionEnum::X:
233 re = std::sqrt(cubical[1] * cubical[2] / M_PI);
234 perf_length = cubical[0];
235 break;
236 case Opm::WellCompletion::DirectionEnum::Y:
237 re = std::sqrt(cubical[0] * cubical[2] / M_PI);
238 perf_length = cubical[1];
239 break;
240 case Opm::WellCompletion::DirectionEnum::Z:
241 re = std::sqrt(cubical[0] * cubical[1] / M_PI);
242 perf_length = cubical[2];
243 break;
244 default:
245 OPM_THROW(std::runtime_error, " Dirtecion of well is not supported ");
246 }
247
248 double repR = std::sqrt(re * radius);
249 wells_rep_radius.push_back(repR);
250 wells_perf_length.push_back(perf_length);
251 wells_bore_diameter.push_back(2. * radius);
252 }
253 } else {
254 if (completion->getState() != WellCompletion::SHUT) {
255 OPM_THROW(std::runtime_error, "Completion state: " << WellCompletion::StateEnum2String( completion->getState() ) << " not handled");
256 }
257 }
258
259 }
260 }
261 well_index++;
262 }
263 }
264
265} // namespace Opm
Basic polymer injection behaviour class. This class gives all injectors the same polymer concentratio...
Definition: PolymerInflow.hpp:60
Polymer injection behaviour class using deck WPOLYMER. This class reads the accumulated WPOLYMER line...
Definition: PolymerInflow.hpp:89
Definition: PolymerPropsAd.hpp:33
Definition: SimulatorFullyImplicitBlackoilPolymer.hpp:100
std::unique_ptr< Solver > createSolver(const Wells *wells)
Definition: SimulatorFullyImplicitBlackoilPolymer_impl.hpp:65
SimulatorFullyImplicitBlackoilPolymer(const parameter::ParameterGroup &param, const GridT &grid, DerivedGeology &geo, BlackoilPropsAdInterface &props, const PolymerPropsAd &polymer_props, const RockCompressibility *rock_comp_props, NewtonIterationBlackoilInterface &linsolver, const double *gravity, const bool disgas, const bool vapoil, const bool polymer, const bool plyshlog, const bool shrate, std::shared_ptr< EclipseState > eclipse_state, BlackoilOutputWriter &output_writer, Opm::DeckConstPtr &deck, const std::vector< double > &threshold_pressures_by_face)
Definition: SimulatorFullyImplicitBlackoilPolymer_impl.hpp:26
void handleAdditionalWellInflow(SimulatorTimer &timer, WellsManager &wells_manager, typename BaseType::WellState &well_state, const Wells *wells)
Definition: SimulatorFullyImplicitBlackoilPolymer_impl.hpp:102
Definition: CompressibleTpfaPolymer.hpp:33