1 #include <opm/parser/eclipse/Units/Units.hpp> 2 #include <opm/core/grid/GridHelpers.hpp> 4 #include <opm/common/ErrorMacros.hpp> 5 #include <opm/common/OpmLog/OpmLog.hpp> 6 #include <opm/core/utility/compressedToCartesian.hpp> 7 #include <opm/core/props/rock/RockFromDeck.hpp> 8 #include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp> 9 #include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp> 10 #include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp> 23 namespace ProductionControl
25 enum Mode { ORAT, WRAT, GRAT,
34 Mode mode(
const std::string& control);
37 Mode mode(Opm::WellProducer::ControlModeEnum controlMode);
41 namespace InjectionControl
43 enum Mode { RATE, RESV,
BHP,
51 Mode mode(
const std::string& control);
53 Mode mode(Opm::WellInjector::ControlModeEnum controlMode);
57 double computeWellIndex(
const double radius,
58 const std::array<double, 3>& cubical,
59 const double* cell_permeability,
60 const double skin_factor,
61 const Opm::WellCompletion::DirectionEnum direction,
64 template <
int dim,
class C2F,
class FC>
65 std::array<double, dim>
66 getCubeDim(
const C2F& c2f,
67 FC begin_face_centroids,
70 std::array< std::vector<double>, dim > X;
72 const std::vector<double>::size_type
73 nf = std::distance(c2f[cell].begin(),
76 for (
int d = 0; d < dim; ++d) {
81 typedef typename C2F::row_type::const_iterator FI;
83 for (FI f = c2f[cell].begin(), e = c2f[cell].end(); f != e; ++f) {
84 using Opm::UgGridHelpers::increment;
85 using Opm::UgGridHelpers::getCoordinate;
87 const FC& fc = increment(begin_face_centroids, *f, dim);
89 for (
int d = 0; d < dim; ++d) {
90 X[d].push_back(getCoordinate(fc, d));
94 std::array<double, dim> cube;
95 for (
int d = 0; d < dim; ++d) {
96 typedef std::vector<double>::iterator VI;
97 typedef std::pair<VI,VI> PVI;
99 const PVI m = std::minmax_element(X[d].begin(), X[d].end());
101 cube[d] = *m.second - *m.first;
110 template<
class C2F,
class FC,
class NTG>
111 void WellsManager::createWellsFromSpecs(std::vector<const Well*>& wells,
size_t timeStep,
113 const int* cart_dims,
114 FC begin_face_centroids,
116 std::vector<double>& dz,
117 std::vector<std::string>& well_names,
118 std::vector<WellData>& well_data,
119 std::map<std::string, int>& well_names_to_index,
120 const PhaseUsage& phaseUsage,
121 const std::map<int,int>& cartesian_to_compressed,
122 const double* permeability,
124 std::vector<int>& wells_on_proc,
125 const std::unordered_set<std::string>& ignored_wells,
126 const DynamicListEconLimited& list_econ_limited)
128 if (dimensions != 3) {
129 OPM_THROW(std::domain_error,
130 "WellsManager::createWellsFromSpecs() only " 131 "supported in three space dimensions");
134 std::vector<std::vector<PerfData> > wellperf_data;
135 wellperf_data.resize(wells.size());
136 wells_on_proc.resize(wells.size(), 1);
142 int active_well_index = 0;
143 for (
auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
144 const auto* well = (*wellIter);
146 if (well->getStatus(timeStep) == WellCommon::SHUT) {
150 if ( ignored_wells.find(well->name()) != ignored_wells.end() ) {
151 wells_on_proc[ wellIter - wells.begin() ] = 0;
155 if (list_econ_limited.wellShutEconLimited(well->name())) {
159 std::vector<int> cells_connection_closed;
160 if (list_econ_limited.anyConnectionClosedForWell(well->name())) {
161 cells_connection_closed = list_econ_limited.getClosedConnectionsForWell(well->name());
167 for(
const auto& completion : well->getCompletions(timeStep)) {
168 if (completion.getState() == WellCompletion::OPEN) {
169 int i = completion.getI();
170 int j = completion.getJ();
171 int k = completion.getK();
173 const int* cpgdim = cart_dims;
174 int cart_grid_indx = i + cpgdim[0]*(j + cpgdim[1]*k);
175 std::map<int, int>::const_iterator cgit = cartesian_to_compressed.find(cart_grid_indx);
176 if (cgit == cartesian_to_compressed.end()) {
177 OPM_MESSAGE(
"****Warning: Cell with i,j,k indices " << i <<
' ' << j <<
' ' 178 << k <<
" not found in grid. The completion will be igored (well = " 179 << well->name() <<
')');
183 int cell = cgit->second;
185 if (!cells_connection_closed.empty()) {
186 const bool connection_found = std::find(cells_connection_closed.begin(),
187 cells_connection_closed.end(), cell)
188 != cells_connection_closed.end();
189 if (connection_found) {
197 const Value<double>& transmissibilityFactor = completion.getConnectionTransmissibilityFactorAsValueObject();
198 const double wellPi = completion.getWellPi();
199 if (transmissibilityFactor.hasValue()) {
200 pd.well_index = transmissibilityFactor.getValue();
202 double radius = 0.5*completion.getDiameter();
204 radius = 0.5*unit::feet;
205 OPM_MESSAGE(
"**** Warning: Well bore internal radius set to " << radius);
208 std::array<double, 3> cubical =
209 WellsManagerDetail::getCubeDim<3>(c2f, begin_face_centroids, cell);
213 cubical[2] = dz[cell];
216 const double* cell_perm = &permeability[dimensions*dimensions*cell];
218 WellsManagerDetail::computeWellIndex(radius, cubical, cell_perm,
219 completion.getSkinFactor(),
220 completion.getDirection(),
223 pd.satnumid = completion.getSatTableId();
224 pd.well_index *= wellPi;
226 wellperf_data[active_well_index].push_back(pd);
229 if (completion.getState() != WellCompletion::SHUT) {
230 OPM_THROW(std::runtime_error,
"Completion state: " << WellCompletion::StateEnum2String( completion.getState() ) <<
" not handled");
236 well_names_to_index[well->name()] = active_well_index;
237 well_names.push_back(well->name());
240 wd.reference_bhp_depth = well->getRefDepth( timeStep );
241 wd.welspecsline = -1;
242 if (well->isInjector( timeStep ))
247 wd.allowCrossFlow = well->getAllowCrossFlow();
248 well_data.push_back(wd);
256 const int num_wells = well_data.size();
259 assert (dimensions == 3);
260 for (
int w = 0; w < num_wells; ++w) {
261 num_perfs += wellperf_data[w].size();
265 w_ =
create_wells(phaseUsage.num_phases, num_wells, num_perfs);
267 OPM_THROW(std::runtime_error,
"Failed creating Wells struct.");
272 for (
int w = 0; w < num_wells; ++w) {
273 const int w_num_perf = wellperf_data[w].size();
274 std::vector<int> perf_cells (w_num_perf);
275 std::vector<double> perf_prodind(w_num_perf);
276 std::vector<int> perf_satnumid(w_num_perf);
278 for (
int perf = 0; perf < w_num_perf; ++perf) {
279 perf_cells [perf] = wellperf_data[w][perf].cell;
280 perf_prodind[perf] = wellperf_data[w][perf].well_index;
281 perf_satnumid[perf] = wellperf_data[w][perf].satnumid;
284 const double* comp_frac = NULL;
290 well_data[w].reference_bhp_depth,
295 perf_satnumid.data(),
296 well_names[w].c_str(),
297 well_data[w].allowCrossFlow,
301 OPM_THROW(std::runtime_error,
302 "Failed adding well " 304 <<
" to Wells data structure.");
309 template <
class C2F,
class FC>
312 const size_t timeStep,
314 const int* global_cell,
315 const int* cart_dims,
317 const C2F& cell_to_faces,
318 FC begin_face_centroids,
319 const DynamicListEconLimited& list_econ_limited,
320 bool is_parallel_run,
321 const std::unordered_set<std::string>& deactivated_wells)
322 : w_(0), is_parallel_run_(is_parallel_run)
324 init(eclipseState, timeStep, number_of_cells, global_cell,
325 cart_dims, dimensions,
326 cell_to_faces, begin_face_centroids, list_econ_limited, deactivated_wells);
330 template <
class C2F,
class FC>
332 WellsManager::init(
const Opm::EclipseState& eclipseState,
333 const size_t timeStep,
335 const int* global_cell,
336 const int* cart_dims,
338 const C2F& cell_to_faces,
339 FC begin_face_centroids,
340 const DynamicListEconLimited& list_econ_limited,
341 const std::unordered_set<std::string>& deactivated_wells)
343 if (dimensions != 3) {
344 OPM_THROW(std::runtime_error,
345 "We cannot initialize wells from a deck unless " 346 "the corresponding grid is 3-dimensional.");
349 if (eclipseState.getSchedule().numWells() == 0) {
350 OPM_MESSAGE(
"No wells specified in Schedule section, " 351 "initializing no wells");
355 std::map<int,int> cartesian_to_compressed;
356 setupCompressedToCartesian(global_cell, number_of_cells,
357 cartesian_to_compressed);
360 PhaseUsage pu = phaseUsageFromDeck(eclipseState);
364 std::vector<std::string> well_names;
365 std::vector<WellData> well_data;
369 std::map<std::string, int> well_names_to_index;
371 const auto& schedule = eclipseState.getSchedule();
372 auto wells = schedule.getWells(timeStep);
373 std::vector<int> wells_on_proc;
375 well_names.reserve(wells.size());
376 well_data.reserve(wells.size());
378 typedef GridPropertyAccess::ArrayPolicy::ExtractFromDeck<double> DoubleArray;
379 typedef GridPropertyAccess::Compressed<DoubleArray, GridPropertyAccess::Tag::NTG> NTGArray;
381 DoubleArray ntg_glob(eclipseState,
"NTG", 1.0);
382 NTGArray ntg(ntg_glob, global_cell);
384 const auto& eclGrid = eclipseState.getInputGrid();
388 std::vector<double> dz(number_of_cells);
390 std::vector<int> gc = compressedToCartesian(number_of_cells, global_cell);
391 for (
int cell = 0; cell < number_of_cells; ++cell) {
392 dz[cell] = eclGrid.getCellThicknes(gc[cell]);
397 std::vector<double> interleavedPerm;
405 createWellsFromSpecs(wells, timeStep, cell_to_faces,
407 begin_face_centroids,
410 well_names, well_data, well_names_to_index,
411 pu, cartesian_to_compressed, interleavedPerm.data(), ntg,
412 wells_on_proc, deactivated_wells, list_econ_limited);
414 setupWellControls(wells, timeStep, well_names, pu, wells_on_proc, list_econ_limited);
417 const auto& fieldGroup = schedule.getGroup(
"FIELD" );
418 well_collection_.addField(fieldGroup, timeStep, pu);
420 const auto& grouptree = schedule.getGroupTree( timeStep );
421 std::vector< std::string > group_stack = {
"FIELD" };
424 auto parent = group_stack.back();
425 group_stack.pop_back();
426 const auto& children = grouptree.children( parent );
427 group_stack.insert( group_stack.end(), children.begin(), children.end() );
429 for(
const auto& child : children ) {
430 well_collection_.addGroup( schedule.getGroup( child ), parent, timeStep, pu );
433 }
while( !group_stack.empty() );
436 for (
size_t i = 0; i < wells_on_proc.size(); ++i) {
438 if (wells_on_proc[i]) {
439 well_collection_.addWell(wells[i], timeStep, pu);
447 setupGuideRates(wells, timeStep, well_data, well_names_to_index);
Well constrained by BHP target.
Definition: well_controls.h:35
Well constrained by THP target.
Definition: well_controls.h:36
Definition: WellsManager.cpp:51
static void extractInterleavedPermeability(const Opm::EclipseState &eclState, const int number_of_cells, const int *global_cell, const int *cart_dims, const double perm_threshold, std::vector< double > &permeability)
Convert the permeabilites for the logically Cartesian grid in EclipseState to an array of size number...
Definition: RockFromDeck.cpp:110
Definition: AnisotropicEikonal.cpp:446
bool groupControlActive() const
Whether we have active group control.
Definition: WellCollection.cpp:327
Well is an injector.
Definition: wells.h:42
struct Wells * create_wells(int nphases, int nwells, int nperf)
Construct a Wells object initially capable of managing a given number of wells and total number of we...
Definition: wells.c:262
WellsManager()
Default constructor – no wells.
Definition: WellsManager.cpp:317
Well is a producer.
Definition: wells.h:43
void setWellsPointer(Wells *wells)
Adds the well pointer to each leaf node (does not take ownership).
Definition: WellCollection.cpp:185
int add_well(enum WellType type, double depth_ref, int nperf, const double *comp_frac, const int *cells, const double *WI, const int *sat_table_id, const char *name, int allow_cf, struct Wells *W)
Append a new well to an existing Wells object.
Definition: wells.c:365