void WellConnections::init(const Opm::EclipseStateConstPtr eclipseState, const std::array<int, 3>& cartesianSize, const std::vector<int>& cartesian_to_compressed) { std::vector<const Opm::Well*> wells = eclipseState->getSchedule()->getWells(); int last_time_step = eclipseState->getSchedule()->getTimeMap()->size()-1; well_indices_.resize(wells.size()); // We assume that we know all the wells. int index=0; for (const auto well : wells) { std::set<int>& well_indices = well_indices_[index]; Opm::CompletionSetConstPtr completionSet = well->getCompletions(last_time_step); for (size_t c=0; c<completionSet->size(); c++) { Opm::CompletionConstPtr completion = completionSet->get(c); int i = completion->getI(); int j = completion->getJ(); int k = completion->getK(); int cart_grid_idx = i + cartesianSize[0]*(j + cartesianSize[1]*k); int compressed_idx = cartesian_to_compressed[cart_grid_idx]; if ( compressed_idx >= 0 ) // Ignore completions in inactive cells. { well_indices.insert(compressed_idx); } } ++index; } }
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::unordered_set<std::string> computeDefunctWellNames(const std::vector<std::vector<int> >& wells_on_proc, const Opm::EclipseStateConstPtr eclipseState, const CollectiveCommunication<MPI_Comm>& cc, int root) { std::vector<const Opm::Well*> wells = eclipseState->getSchedule()->getWells(); std::vector<int> my_well_indices; const int well_information_tag = 267553; if( root == cc.rank() ) { std::vector<MPI_Request> reqs(cc.size(), MPI_REQUEST_NULL); my_well_indices = wells_on_proc[root]; for ( int i=0; i < cc.size(); ++i ) { if(i==root) { continue; } MPI_Isend(const_cast<int*>(wells_on_proc[i].data()), wells_on_proc[i].size(), MPI_INT, i, well_information_tag, cc, &reqs[i]); } std::vector<MPI_Status> stats(reqs.size()); MPI_Waitall(reqs.size(), reqs.data(), stats.data()); } else { MPI_Status stat; MPI_Probe(root, well_information_tag, cc, &stat); int msg_size; MPI_Get_count(&stat, MPI_INT, &msg_size); my_well_indices.resize(msg_size); MPI_Recv(my_well_indices.data(), msg_size, MPI_INT, root, well_information_tag, cc, &stat); } // Compute defunct wells in parallel run. std::vector<int> defunct_wells(wells.size(), true); for(auto well_index : my_well_indices) { defunct_wells[well_index] = false; } // We need to use well names as only they are consistent. std::unordered_set<std::string> defunct_well_names; for(auto defunct = defunct_wells.begin(); defunct != defunct_wells.end(); ++defunct) { if ( *defunct ) { defunct_well_names.insert(wells[defunct-defunct_wells.begin()]->name()); } } return defunct_well_names; }
CombinedGridWellGraph::CombinedGridWellGraph(const CpGrid& grid, const Opm::EclipseStateConstPtr eclipseState, const double* transmissibilities, bool pretendEmptyGrid) : grid_(grid), eclipseState_(eclipseState), transmissibilities_(transmissibilities) { if ( pretendEmptyGrid ) { // wellsGraph not needed return; } wellsGraph_.resize(grid.numCells()); const auto& cpgdim = grid.logicalCartesianSize(); // create compressed lookup from cartesian. std::vector<Opm::WellConstPtr> wells = eclipseState->getSchedule()->getWells(); std::vector<int> cartesian_to_compressed(cpgdim[0]*cpgdim[1]*cpgdim[2], -1); int last_time_step = eclipseState->getSchedule()->getTimeMap()->size()-1; for( int i=0; i < grid.numCells(); ++i ) { cartesian_to_compressed[grid.globalCell()[i]] = i; } // We assume that we know all the wells. for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) { Opm::WellConstPtr well = (*wellIter); std::set<int> well_indices; Opm::CompletionSetConstPtr completionSet = well->getCompletions(last_time_step); for (size_t c=0; c<completionSet->size(); c++) { Opm::CompletionConstPtr completion = completionSet->get(c); int i = completion->getI(); int j = completion->getJ(); int k = completion->getK(); int cart_grid_idx = i + cpgdim[0]*(j + cpgdim[1]*k); int compressed_idx = cartesian_to_compressed[cart_grid_idx]; if ( compressed_idx >= 0 ) // Ignore completions in inactive cells. { well_indices.insert(compressed_idx); } } addCompletionSetToGraph(well_indices); } }
void WellsManager::init(const Opm::EclipseStateConstPtr eclipseState, const size_t timeStep, int number_of_cells, const int* global_cell, const int* cart_dims, int dimensions, const C2F& cell_to_faces, FC begin_face_centroids, const double* permeability) { if (dimensions != 3) { OPM_THROW(std::runtime_error, "We cannot initialize wells from a deck unless " "the corresponding grid is 3-dimensional."); } if (eclipseState->getSchedule()->numWells() == 0) { OPM_MESSAGE("No wells specified in Schedule section, " "initializing no wells"); return; } std::map<int,int> cartesian_to_compressed; setupCompressedToCartesian(global_cell, number_of_cells, cartesian_to_compressed); // Obtain phase usage data. PhaseUsage pu = phaseUsageFromDeck(eclipseState); // These data structures will be filled in this constructor, // then used to initialize the Wells struct. std::vector<std::string> well_names; std::vector<WellData> well_data; // For easy lookup: std::map<std::string, int> well_names_to_index; ScheduleConstPtr schedule = eclipseState->getSchedule(); std::vector<WellConstPtr> wells = schedule->getWells(timeStep); std::vector<int> wells_on_proc; well_names.reserve(wells.size()); well_data.reserve(wells.size()); typedef GridPropertyAccess::ArrayPolicy::ExtractFromDeck<double> DoubleArray; typedef GridPropertyAccess::Compressed<DoubleArray, GridPropertyAccess::Tag::NTG> NTGArray; DoubleArray ntg_glob(eclipseState, "NTG", 1.0); NTGArray ntg(ntg_glob, global_cell); EclipseGridConstPtr eclGrid = eclipseState->getEclipseGrid(); // use cell thickness (dz) from eclGrid // dz overwrites values calculated by WellDetails::getCubeDim std::vector<double> dz(number_of_cells); { std::vector<int> gc = compressedToCartesian(number_of_cells, global_cell); for (int cell = 0; cell < number_of_cells; ++cell) { dz[cell] = eclGrid->getCellThicknes(gc[cell]); } } createWellsFromSpecs(wells, timeStep, cell_to_faces, cart_dims, begin_face_centroids, dimensions, dz, well_names, well_data, well_names_to_index, pu, cartesian_to_compressed, permeability, ntg, wells_on_proc); setupWellControls(wells, timeStep, well_names, pu, wells_on_proc); { GroupTreeNodeConstPtr fieldNode = schedule->getGroupTree(timeStep)->getNode("FIELD"); GroupConstPtr fieldGroup = schedule->getGroup(fieldNode->name()); well_collection_.addField(fieldGroup, timeStep, pu); addChildGroups(fieldNode, schedule, timeStep, pu); } for (auto w = wells.begin(), e = wells.end(); w != e; ++w) { well_collection_.addWell(*w, timeStep, pu); } well_collection_.setWellsPointer(w_); well_collection_.applyGroupControls(); setupGuideRates(wells, timeStep, well_data, well_names_to_index); // Debug output. #define EXTRA_OUTPUT #ifdef EXTRA_OUTPUT /* std::cout << "\t WELL DATA" << std::endl; for(int i = 0; i< num_wells; ++i) { std::cout << i << ": " << well_data[i].type << " " << well_data[i].control << " " << well_data[i].target << std::endl; } std::cout << "\n\t PERF DATA" << std::endl; for(int i=0; i< int(wellperf_data.size()); ++i) { for(int j=0; j< int(wellperf_data[i].size()); ++j) { std::cout << i << ": " << wellperf_data[i][j].cell << " " << wellperf_data[i][j].well_index << std::endl; } } */ #endif }
void SimulatorFullyImplicitBlackoilPolymer<GridT>:: computeRepRadiusPerfLength(const Opm::EclipseStateConstPtr 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); ScheduleConstPtr schedule = eclipseState->getSchedule(); std::vector<WellConstPtr> wells = schedule->getWells(timeStep); int well_index = 0; for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) { WellConstPtr well = (*wellIter); if (well->getStatus(timeStep) == WellCommon::SHUT) { continue; } { // COMPDAT handling CompletionSetConstPtr completionSet = well->getCompletions(timeStep); for (size_t c=0; c<completionSet->size(); c++) { CompletionConstPtr 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++; } }
std::vector<std::vector<int> > postProcessPartitioningForWells(std::vector<int>& parts, const Opm::EclipseStateConstPtr eclipseState, const WellConnections& well_connections, std::size_t no_procs) { std::vector<const Opm::Well*> wells = eclipseState->getSchedule()->getWells(); // Contains for each process the indices of the wells assigned to it. std::vector<std::vector<int> > well_indices_on_proc(no_procs); if( ! well_connections.size() ) { // No wells to be processed return well_indices_on_proc; } // prevent memory allocation for(auto& well_indices : well_indices_on_proc) { well_indices.reserve(wells.size()); } // Check that all completions of a well have ended up on one process. // If that is not the case for well then move them manually to the // process that already has the most completions on it. int well_index = 0; for (const auto* well: wells) { const auto& well_completions = well_connections[well_index]; std::map<int,std::size_t> no_completions_on_proc; for ( auto completion_index: well_completions ) { ++no_completions_on_proc[parts[completion_index]]; } int owner = no_completions_on_proc.begin()->first; if ( no_completions_on_proc.size() > 1 ) { // partition with the most completions on it becomes new owner int new_owner = std::max_element(no_completions_on_proc.begin(), no_completions_on_proc.end(), [](const std::pair<int,std::size_t>& p1, const std::pair<int,std::size_t>& p2){ return ( p1.second > p2.second ); })->first; std::cout << "Manually moving well " << well->name() << " to partition " << new_owner << std::endl; for ( auto completion_cell : well_completions ) { parts[completion_cell] = new_owner; } owner = new_owner; } well_indices_on_proc[owner].push_back(well_index); ++well_index; } return well_indices_on_proc; }