mirror of
				https://github.com/OPM/opm-simulators.git
				synced 2025-02-25 18:55:30 -06:00 
			
		
		
		
	New constructor for WellsManager that also takes the new parser as argument. New test comparing old and new
This commit is contained in:
		| @@ -18,6 +18,8 @@ | ||||
| */ | ||||
|  | ||||
| #include "config.h" | ||||
|  | ||||
|  | ||||
| #include <opm/core/wells/WellsManager.hpp> | ||||
| #include <opm/core/io/eclipse/EclipseGridParser.hpp> | ||||
| #include <opm/core/grid.h> | ||||
| @@ -234,6 +236,598 @@ namespace Opm | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// Construct wells from deck. | ||||
|     WellsManager::WellsManager(const Opm::SchedulePtr schedule, | ||||
|                                const size_t timeStep, | ||||
|                                const Opm::EclipseGridParser& deck, | ||||
|                                const UnstructuredGrid& grid, | ||||
|                                const double* permeability) | ||||
|         : w_(0) | ||||
|     { | ||||
|         if (grid.dimensions != 3) { | ||||
|             OPM_THROW(std::runtime_error, "We cannot initialize wells from a deck unless the corresponding grid is 3-dimensional."); | ||||
|         } | ||||
|         // NOTE: Implementation copied and modified from dune-porsol's class BlackoilWells. | ||||
|         std::vector<std::string> keywords; | ||||
|         keywords.push_back("WELSPECS"); | ||||
|         keywords.push_back("COMPDAT"); | ||||
| //      keywords.push_back("WELTARG"); | ||||
|         if (!deck.hasFields(keywords)) { | ||||
|             OPM_MESSAGE("Missing well keywords in deck, initializing no wells."); | ||||
|             return; | ||||
|         } | ||||
|         if (!(deck.hasField("WCONINJE") || deck.hasField("WCONPROD")) ) { | ||||
|             OPM_THROW(std::runtime_error, "Needed field is missing in file"); | ||||
|         } | ||||
|  | ||||
|         // Obtain phase usage data. | ||||
|         PhaseUsage pu = phaseUsageFromDeck(deck); | ||||
|  | ||||
|         // 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; | ||||
|         std::vector<std::vector<PerfData> > wellperf_data; | ||||
|  | ||||
|         // For easy lookup: | ||||
|         std::map<std::string, int> well_names_to_index; | ||||
|         typedef std::map<std::string, int>::const_iterator WNameIt; | ||||
|  | ||||
|         // Get WELSPECS data. | ||||
|         // It is allowed to have multiple lines corresponding to | ||||
|         // the same well, in which case the last one encountered | ||||
|         // is the one used. | ||||
|         const WELSPECS& welspecs = deck.getWELSPECS(); | ||||
|         const int num_welspecs = welspecs.welspecs.size(); | ||||
|         well_names.reserve(num_welspecs); | ||||
|         well_data.reserve(num_welspecs); | ||||
|         for (int w = 0; w < num_welspecs; ++w) { | ||||
|             // First check if this well has already been encountered. | ||||
|             // If so, we modify it's data instead of appending a new well | ||||
|             // to the well_data and well_names vectors. | ||||
|             const std::string& name = welspecs.welspecs[w].name_; | ||||
|             const double refdepth = welspecs.welspecs[w].datum_depth_BHP_; | ||||
|             WNameIt wit = well_names_to_index.find(name); | ||||
|             if (wit == well_names_to_index.end()) { | ||||
|                 // New well, append data. | ||||
|                 well_names_to_index[welspecs.welspecs[w].name_] = well_data.size(); | ||||
|                 well_names.push_back(name); | ||||
|                 WellData wd; | ||||
|                 // If negative (defaulted), set refdepth to a marker | ||||
|                 // value, will be changed after getting perforation | ||||
|                 // data to the centroid of the cell of the top well | ||||
|                 // perforation. | ||||
|                 wd.reference_bhp_depth = (refdepth < 0.0) ? -1e100 : refdepth; | ||||
|                 wd.welspecsline = w; | ||||
|                 well_data.push_back(wd); | ||||
|             } else { | ||||
|                 // Existing well, change data. | ||||
|                 const int wix = wit->second; | ||||
|                 well_data[wix].reference_bhp_depth = (refdepth < 0.0) ? -1e100 : refdepth; | ||||
|                 well_data[wix].welspecsline = w; | ||||
|             } | ||||
|         } | ||||
|         const int num_wells = well_data.size(); | ||||
|         wellperf_data.resize(num_wells); | ||||
|  | ||||
|  | ||||
|         // global_cell is a map from compressed cells to Cartesian grid cells. | ||||
|         // We must make the inverse lookup. | ||||
|         const int* global_cell = grid.global_cell; | ||||
|         const int* cpgdim = grid.cartdims; | ||||
|         std::map<int,int> cartesian_to_compressed; | ||||
|  | ||||
|         if (global_cell) { | ||||
|             for (int i = 0; i < grid.number_of_cells; ++i) { | ||||
|                 cartesian_to_compressed.insert(std::make_pair(global_cell[i], i)); | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             for (int i = 0; i < grid.number_of_cells; ++i) { | ||||
|                 cartesian_to_compressed.insert(std::make_pair(i, i)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Get COMPDAT data | ||||
|         // It is *not* allowed to have multiple lines corresponding to | ||||
|         // the same perforation! | ||||
|         const COMPDAT& compdat = deck.getCOMPDAT(); | ||||
|         const int num_compdat  = compdat.compdat.size(); | ||||
|         for (int kw = 0; kw < num_compdat; ++kw) { | ||||
|             // Extract well name, or the part of the well name that | ||||
|             // comes before the '*'. | ||||
|             std::string name = compdat.compdat[kw].well_; | ||||
|             std::string::size_type len = name.find('*'); | ||||
|             if (len != std::string::npos) { | ||||
|                 name = name.substr(0, len); | ||||
|             } | ||||
|             // Look for well with matching name. | ||||
|             bool found = false; | ||||
|             for (int wix = 0; wix < num_wells; ++wix) { | ||||
|                 if (well_names[wix].compare(0,len, name) == 0) { // equal | ||||
|                     // Extract corresponding WELSPECS defintion for | ||||
|                     // purpose of default location specification. | ||||
|                     const WelspecsLine& wspec = welspecs.welspecs[well_data[wix].welspecsline]; | ||||
|  | ||||
|                     // We have a matching name. | ||||
|                     int ix = compdat.compdat[kw].grid_ind_[0] - 1; | ||||
|                     int jy = compdat.compdat[kw].grid_ind_[1] - 1; | ||||
|                     int kz1 = compdat.compdat[kw].grid_ind_[2] - 1; | ||||
|                     int kz2 = compdat.compdat[kw].grid_ind_[3] - 1; | ||||
|  | ||||
|                     if (ix < 0) { | ||||
|                         // Defaulted I location.  Extract from WELSPECS. | ||||
|                         ix = wspec.I_ - 1; | ||||
|                     } | ||||
|                     if (jy < 0) { | ||||
|                         // Defaulted J location.  Extract from WELSPECS. | ||||
|                         jy = wspec.J_ - 1; | ||||
|                     } | ||||
|                     if (kz1 < 0) { | ||||
|                         // Defaulted KZ1.  Use top layer. | ||||
|                         kz1 = 0; | ||||
|                     } | ||||
|                     if (kz2 < 0) { | ||||
|                         // Defaulted KZ2.  Use bottom layer. | ||||
|                         kz2 = cpgdim[2] - 1; | ||||
|                     } | ||||
|  | ||||
|                     for (int kz = kz1; kz <= kz2; ++kz) { | ||||
|                         int cart_grid_indx = ix + cpgdim[0]*(jy + cpgdim[1]*kz); | ||||
|                         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 " << ix << ' ' << jy << ' ' | ||||
|                                   << kz << " not found in grid (well = " << name << ')'); | ||||
|                         } | ||||
|                         int cell = cgit->second; | ||||
|                         PerfData pd; | ||||
|                         pd.cell = cell; | ||||
|                         if (compdat.compdat[kw].connect_trans_fac_ > 0.0) { | ||||
|                             pd.well_index = compdat.compdat[kw].connect_trans_fac_; | ||||
|                         } else { | ||||
|                             double radius = 0.5*compdat.compdat[kw].diameter_; | ||||
|                             if (radius <= 0.0) { | ||||
|                                 radius = 0.5*unit::feet; | ||||
|                                 OPM_MESSAGE("**** Warning: Well bore internal radius set to " << radius); | ||||
|                             } | ||||
|                             std::array<double, 3> cubical = getCubeDim(grid, cell); | ||||
|                             const double* cell_perm = &permeability[grid.dimensions*grid.dimensions*cell]; | ||||
|                             pd.well_index = computeWellIndex(radius, cubical, cell_perm, | ||||
|                                                              compdat.compdat[kw].skin_factor_); | ||||
|                         } | ||||
|                         wellperf_data[wix].push_back(pd); | ||||
|                     } | ||||
|                     found = true; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             if (!found) { | ||||
|                 OPM_THROW(std::runtime_error, "Undefined well name: " << compdat.compdat[kw].well_ | ||||
|                       << " in COMPDAT"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Set up reference depths that were defaulted. Count perfs. | ||||
|         int num_perfs = 0; | ||||
|         assert(grid.dimensions == 3); | ||||
|         for (int w = 0; w < num_wells; ++w) { | ||||
|             num_perfs += wellperf_data[w].size(); | ||||
|             if (well_data[w].reference_bhp_depth < 0.0) { | ||||
|                 // It was defaulted. Set reference depth to minimum perforation depth. | ||||
|                 double min_depth = 1e100; | ||||
|                 int num_wperfs = wellperf_data[w].size(); | ||||
|                 for (int perf = 0; perf < num_wperfs; ++perf) { | ||||
|                     double depth = grid.cell_centroids[3*wellperf_data[w][perf].cell + 2]; | ||||
|                     min_depth = std::min(min_depth, depth); | ||||
|                 } | ||||
|                 well_data[w].reference_bhp_depth = min_depth; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Create the well data structures. | ||||
|         w_ = create_wells(pu.num_phases, num_wells, num_perfs); | ||||
|         if (!w_) { | ||||
|             OPM_THROW(std::runtime_error, "Failed creating Wells struct."); | ||||
|         } | ||||
|  | ||||
|         // Classify wells | ||||
|         if (deck.hasField("WCONINJE")) { | ||||
|             const std::vector<WconinjeLine>& lines = deck.getWCONINJE().wconinje; | ||||
|             for (size_t i = 0 ; i < lines.size(); ++i) { | ||||
|                 const std::map<std::string, int>::const_iterator it = well_names_to_index.find(lines[i].well_); | ||||
|                 if (it != well_names_to_index.end()) { | ||||
|                     const int well_index = it->second; | ||||
|                     well_data[well_index].type = INJECTOR; | ||||
|                 } else { | ||||
|                     OPM_THROW(std::runtime_error, "Unseen well name: " << lines[i].well_ << " first seen in WCONINJE"); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (deck.hasField("WCONPROD")) { | ||||
|             const std::vector<WconprodLine>& lines = deck.getWCONPROD().wconprod; | ||||
|             for (size_t i = 0; i < lines.size(); ++i) { | ||||
|                 const std::map<std::string, int>::const_iterator it = well_names_to_index.find(lines[i].well_); | ||||
|                 if (it != well_names_to_index.end()) { | ||||
|                     const int well_index = it->second; | ||||
|                     well_data[well_index].type = PRODUCER; | ||||
|                 } else { | ||||
|                     OPM_THROW(std::runtime_error, "Unseen well name: " << lines[i].well_ << " first seen in WCONPROD"); | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Add wells. | ||||
|         for (int w = 0; w < num_wells; ++w) { | ||||
|             const int w_num_perf = wellperf_data[w].size(); | ||||
|             std::vector<int> perf_cells(w_num_perf); | ||||
|             std::vector<double> perf_prodind(w_num_perf); | ||||
|             for (int perf = 0; perf < w_num_perf; ++perf) { | ||||
|                 perf_cells[perf] = wellperf_data[w][perf].cell; | ||||
|                 perf_prodind[perf] = wellperf_data[w][perf].well_index; | ||||
|             } | ||||
|             const double* comp_frac = NULL; | ||||
|             // We initialize all wells with a null component fraction, | ||||
|             // and must (for injection wells) overwrite it later. | ||||
|             int ok = add_well(well_data[w].type, well_data[w].reference_bhp_depth, w_num_perf, | ||||
|                               comp_frac, &perf_cells[0], &perf_prodind[0], well_names[w].c_str(), w_); | ||||
|             if (!ok) { | ||||
|                 OPM_THROW(std::runtime_error, "Failed adding well " << well_names[w] << " to Wells data structure."); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Get WCONINJE data, add injection controls to wells. | ||||
|         // It is allowed to have multiple lines corresponding to | ||||
|         // the same well, in which case the last one encountered | ||||
|         // is the one used. | ||||
|         if (deck.hasField("WCONINJE")) { | ||||
|             const WCONINJE& wconinjes = deck.getWCONINJE(); | ||||
|             const int num_wconinjes = wconinjes.wconinje.size(); | ||||
|             for (int kw = 0; kw < num_wconinjes; ++kw) { | ||||
|                 const WconinjeLine& wci_line = wconinjes.wconinje[kw]; | ||||
|                 // Extract well name, or the part of the well name that | ||||
|                 // comes before the '*'. | ||||
|                 std::string name = wci_line.well_; | ||||
|                 std::string::size_type len = name.find('*'); | ||||
|                 if (len != std::string::npos) { | ||||
|                     name = name.substr(0, len); | ||||
|                 } | ||||
|                 bool well_found = false; | ||||
|                 for (int wix = 0; wix < num_wells; ++wix) { | ||||
|                     if (well_names[wix].compare(0,len, name) == 0) { //equal | ||||
|                         well_found = true; | ||||
|                         assert(well_data[wix].type == w_->type[wix]); | ||||
|                         if (well_data[wix].type != INJECTOR) { | ||||
|                             OPM_THROW(std::runtime_error, "Found WCONINJE entry for a non-injector well: " << well_names[wix]); | ||||
|                         } | ||||
|  | ||||
|                         // Add all controls that are present in well. | ||||
|                         // First we must clear existing controls, in case the | ||||
|                         // current WCONINJE line is modifying earlier controls. | ||||
|                         clear_well_controls(wix, w_); | ||||
|                         int ok = 1; | ||||
|                         int control_pos[5] = { -1, -1, -1, -1, -1 }; | ||||
|                         if (ok && wci_line.surface_flow_max_rate_ >= 0.0) { | ||||
|                             control_pos[InjectionControl::RATE] = well_controls_get_num(w_->ctrls[wix]); | ||||
|                             double distr[3] = { 0.0, 0.0, 0.0 }; | ||||
|                             if (wci_line.injector_type_ == "WATER") { | ||||
|                                 distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0; | ||||
|                             } else if (wci_line.injector_type_ == "OIL") { | ||||
|                                 distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0; | ||||
|                             } else if (wci_line.injector_type_ == "GAS") { | ||||
|                                 distr[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0; | ||||
|                             } else { | ||||
|                                 OPM_THROW(std::runtime_error, "Injector type " << wci_line.injector_type_ << " not supported." | ||||
|                                       "WellsManager only supports WATER, OIL and GAS injector types."); | ||||
|                             } | ||||
|                             ok = append_well_controls(SURFACE_RATE, wci_line.surface_flow_max_rate_, | ||||
|                                                       distr, wix, w_); | ||||
|                         } | ||||
|                         if (ok && wci_line.reservoir_flow_max_rate_ >= 0.0) { | ||||
|                             control_pos[InjectionControl::RESV] = well_controls_get_num(w_->ctrls[wix]); | ||||
|                             double distr[3] = { 0.0, 0.0, 0.0 }; | ||||
|                             if (wci_line.injector_type_ == "WATER") { | ||||
|                                 distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0; | ||||
|                             } else if (wci_line.injector_type_ == "OIL") { | ||||
|                                 distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0; | ||||
|                             } else if (wci_line.injector_type_ == "GAS") { | ||||
|                                 distr[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0; | ||||
|                             } else { | ||||
|                                 OPM_THROW(std::runtime_error, "Injector type " << wci_line.injector_type_ << " not supported." | ||||
|                                       "WellsManager only supports WATER, OIL and GAS injector types."); | ||||
|                             } | ||||
|                             ok = append_well_controls(RESERVOIR_RATE, wci_line.reservoir_flow_max_rate_, | ||||
|                                                       distr, wix, w_); | ||||
|                         } | ||||
|                         if (ok && wci_line.BHP_limit_ > 0.0) { | ||||
|                             control_pos[InjectionControl::BHP] = well_controls_get_num(w_->ctrls[wix]); | ||||
|                             ok = append_well_controls(BHP, wci_line.BHP_limit_, | ||||
|                                                       NULL, wix, w_); | ||||
|                         } | ||||
|                         if (ok && wci_line.THP_limit_ > 0.0) { | ||||
|                             OPM_THROW(std::runtime_error, "We cannot handle THP limit for well " << well_names[wix]); | ||||
|                         } | ||||
|                         if (!ok) { | ||||
|                             OPM_THROW(std::runtime_error, "Failure occured appending controls for well " << well_names[wix]); | ||||
|                         } | ||||
|                         InjectionControl::Mode mode = InjectionControl::mode(wci_line.control_mode_); | ||||
|                         int cpos = control_pos[mode]; | ||||
|                         if (cpos == -1 && mode != InjectionControl::GRUP) { | ||||
|                             OPM_THROW(std::runtime_error, "Control for " << wci_line.control_mode_ << " not specified in well " << well_names[wix]); | ||||
|                         } | ||||
|                         // We need to check if the well is shut or not | ||||
|                         if (wci_line.open_shut_flag_ == "SHUT") { | ||||
|                             cpos = ~cpos; | ||||
|                         } | ||||
|                         set_current_control(wix, cpos, w_); | ||||
|  | ||||
|                         // Set well component fraction. | ||||
|                         double cf[3] = { 0.0, 0.0, 0.0 }; | ||||
|                         if (wci_line.injector_type_[0] == 'W') { | ||||
|                             if (!pu.phase_used[BlackoilPhases::Aqua]) { | ||||
|                                 OPM_THROW(std::runtime_error, "Water phase not used, yet found water-injecting well."); | ||||
|                             } | ||||
|                             cf[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0; | ||||
|                         } else if (wci_line.injector_type_[0] == 'O') { | ||||
|                             if (!pu.phase_used[BlackoilPhases::Liquid]) { | ||||
|                                 OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil-injecting well."); | ||||
|                             } | ||||
|                             cf[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0; | ||||
|                         } else if (wci_line.injector_type_[0] == 'G') { | ||||
|                             if (!pu.phase_used[BlackoilPhases::Vapour]) { | ||||
|                                 OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas-injecting well."); | ||||
|                             } | ||||
|                             cf[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0; | ||||
|                         } | ||||
|                         std::copy(cf, cf + pu.num_phases, w_->comp_frac + wix*pu.num_phases); | ||||
|                     } | ||||
|                 } | ||||
|                 if (!well_found) { | ||||
|                     OPM_THROW(std::runtime_error, "Undefined well name: " << wci_line.well_ | ||||
|                           << " in WCONINJE"); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Get WCONPROD data | ||||
|         // It is allowed to have multiple lines corresponding to | ||||
|         // the same well, in which case the last one encountered | ||||
|         // is the one used. | ||||
|         if (deck.hasField("WCONPROD")) { | ||||
|             const WCONPROD& wconprods = deck.getWCONPROD(); | ||||
|             const int num_wconprods   = wconprods.wconprod.size(); | ||||
|             for (int kw = 0; kw < num_wconprods; ++kw) { | ||||
|                 const WconprodLine& wcp_line = wconprods.wconprod[kw]; | ||||
|                 std::string name = wcp_line.well_; | ||||
|                 std::string::size_type len = name.find('*'); | ||||
|                 if (len != std::string::npos) { | ||||
|                     name = name.substr(0, len); | ||||
|                 } | ||||
|                 bool well_found = false; | ||||
|                 for (int wix = 0; wix < num_wells; ++wix) { | ||||
|                     if (well_names[wix].compare(0,len, name) == 0) { //equal | ||||
|                         well_found = true; | ||||
|                         assert(well_data[wix].type == w_->type[wix]); | ||||
|                         if (well_data[wix].type != PRODUCER) { | ||||
|                             OPM_THROW(std::runtime_error, "Found WCONPROD entry for a non-producer well: " << well_names[wix]); | ||||
|                         } | ||||
|                         // Add all controls that are present in well. | ||||
|                         // First we must clear existing controls, in case the | ||||
|                         // current WCONPROD line is modifying earlier controls. | ||||
|                         clear_well_controls(wix, w_); | ||||
|                         int control_pos[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; | ||||
|                         int ok = 1; | ||||
|                         if (ok && wcp_line.oil_max_rate_ >= 0.0) { | ||||
|                             if (!pu.phase_used[BlackoilPhases::Liquid]) { | ||||
|                                 OPM_THROW(std::runtime_error, "Oil phase not active and ORAT control specified."); | ||||
|                             } | ||||
|                             control_pos[ProductionControl::ORAT] = well_controls_get_num(w_->ctrls[wix]); | ||||
|                             double distr[3] = { 0.0, 0.0, 0.0 }; | ||||
|                             distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0; | ||||
|                             ok = append_well_controls(SURFACE_RATE, -wcp_line.oil_max_rate_, | ||||
|                                                       distr, wix, w_); | ||||
|                         } | ||||
|                         if (ok && wcp_line.water_max_rate_ >= 0.0) { | ||||
|                             if (!pu.phase_used[BlackoilPhases::Aqua]) { | ||||
|                                 OPM_THROW(std::runtime_error, "Water phase not active and WRAT control specified."); | ||||
|                             } | ||||
|                             control_pos[ProductionControl::WRAT] = well_controls_get_num(w_->ctrls[wix]); | ||||
|                             double distr[3] = { 0.0, 0.0, 0.0 }; | ||||
|                             distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0; | ||||
|                             ok = append_well_controls(SURFACE_RATE, -wcp_line.water_max_rate_, | ||||
|                                                       distr, wix, w_); | ||||
|                         } | ||||
|                         if (ok && wcp_line.gas_max_rate_ >= 0.0) { | ||||
|                             if (!pu.phase_used[BlackoilPhases::Vapour]) { | ||||
|                                 OPM_THROW(std::runtime_error, "Gas phase not active and GRAT control specified."); | ||||
|                             } | ||||
|                             control_pos[ProductionControl::GRAT] = well_controls_get_num(w_->ctrls[wix]); | ||||
|                             double distr[3] = { 0.0, 0.0, 0.0 }; | ||||
|                             distr[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0; | ||||
|                             ok = append_well_controls(SURFACE_RATE, -wcp_line.gas_max_rate_, | ||||
|                                                       distr, wix, w_); | ||||
|                         } | ||||
|                         if (ok && wcp_line.liquid_max_rate_ >= 0.0) { | ||||
|                             if (!pu.phase_used[BlackoilPhases::Aqua]) { | ||||
|                                 OPM_THROW(std::runtime_error, "Water phase not active and LRAT control specified."); | ||||
|                             } | ||||
|                             if (!pu.phase_used[BlackoilPhases::Liquid]) { | ||||
|                                 OPM_THROW(std::runtime_error, "Oil phase not active and LRAT control specified."); | ||||
|                             } | ||||
|                             control_pos[ProductionControl::LRAT] = well_controls_get_num(w_->ctrls[wix]); | ||||
|                             double distr[3] = { 0.0, 0.0, 0.0 }; | ||||
|                             distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0; | ||||
|                             distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0; | ||||
|                             ok = append_well_controls(SURFACE_RATE, -wcp_line.liquid_max_rate_, | ||||
|                                                       distr, wix, w_); | ||||
|                         } | ||||
|                         if (ok && wcp_line.reservoir_flow_max_rate_ >= 0.0) { | ||||
|                             control_pos[ProductionControl::RESV] = well_controls_get_num(w_->ctrls[wix]); | ||||
|                             double distr[3] = { 1.0, 1.0, 1.0 }; | ||||
|                             ok = append_well_controls(RESERVOIR_RATE, -wcp_line.reservoir_flow_max_rate_, | ||||
|                                                  distr, wix, w_); | ||||
|                         } | ||||
|                         if (ok && wcp_line.BHP_limit_ > 0.0) { | ||||
|                             control_pos[ProductionControl::BHP] = well_controls_get_num(w_->ctrls[wix]); | ||||
|                             ok = append_well_controls(BHP, wcp_line.BHP_limit_, | ||||
|                                                  NULL, wix, w_); | ||||
|                         } | ||||
|                         if (ok && wcp_line.THP_limit_ > 0.0) { | ||||
|                             OPM_THROW(std::runtime_error, "We cannot handle THP limit for well " << well_names[wix]); | ||||
|                         } | ||||
|                         if (!ok) { | ||||
|                             OPM_THROW(std::runtime_error, "Failure occured appending controls for well " << well_names[wix]); | ||||
|                         } | ||||
|                         ProductionControl::Mode mode = ProductionControl::mode(wcp_line.control_mode_); | ||||
|                         int cpos = control_pos[mode]; | ||||
|                         if (cpos == -1 && mode != ProductionControl::GRUP) { | ||||
|                             OPM_THROW(std::runtime_error, "Control mode type " << mode << " not present in well " << well_names[wix]); | ||||
|                         } | ||||
|                         // If it's shut, we complement the cpos | ||||
|                         if (wcp_line.open_shut_flag_ == "SHUT") { | ||||
|                             cpos = ~cpos; // So we can easily retrieve the cpos later | ||||
|                         } | ||||
|                         set_current_control(wix, cpos, w_); | ||||
|                     } | ||||
|                 } | ||||
|                 if (!well_found) { | ||||
|                     OPM_THROW(std::runtime_error, "Undefined well name: " << wcp_line.well_ | ||||
|                           << " in WCONPROD"); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Get WELTARG data | ||||
|         if (deck.hasField("WELTARG")) { | ||||
|             OPM_THROW(std::runtime_error, "We currently do not handle WELTARG."); | ||||
|             /* | ||||
|             const WELTARG& weltargs = deck.getWELTARG(); | ||||
|             const int num_weltargs  = weltargs.weltarg.size(); | ||||
|             for (int kw = 0; kw < num_weltargs; ++kw) { | ||||
|                 std::string name = weltargs.weltarg[kw].well_; | ||||
|                 std::string::size_type len = name.find('*'); | ||||
|                 if (len != std::string::npos) { | ||||
|                     name = name.substr(0, len); | ||||
|                 } | ||||
|                 bool well_found = false; | ||||
|                 for (int wix = 0; wix < num_wells; ++wix) { | ||||
|                     if (well_names[wix].compare(0,len, name) == 0) { //equal | ||||
|                         well_found = true; | ||||
|                         well_data[wix].target = weltargs.weltarg[kw].new_value_; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 if (!well_found) { | ||||
|                     OPM_THROW(std::runtime_error, "Undefined well name: " << weltargs.weltarg[kw].well_ | ||||
|                           << " in WELTARG"); | ||||
|                 } | ||||
|             } | ||||
|             */ | ||||
|         } | ||||
|  | ||||
|         // 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 | ||||
|  | ||||
|         if (deck.hasField("WELOPEN")) { | ||||
|             const WELOPEN& welopen = deck.getWELOPEN(); | ||||
|             for (size_t i = 0; i < welopen.welopen.size(); ++i) { | ||||
|                 WelopenLine line = welopen.welopen[i]; | ||||
|                 std::string wellname = line.well_; | ||||
|                 std::map<std::string, int>::const_iterator it = well_names_to_index.find(wellname); | ||||
|                 if (it == well_names_to_index.end()) { | ||||
|                     OPM_THROW(std::runtime_error, "Trying to open/shut well with name: \"" << wellname<<"\" but it's not registered under WELSPECS."); | ||||
|                 } | ||||
|                 const int index = it->second; | ||||
|                 if (line.openshutflag_ == "SHUT") { | ||||
|                     int cur_ctrl = well_controls_get_current(w_->ctrls[index]); | ||||
|                     if (cur_ctrl >= 0) { | ||||
|                         well_controls_invert_current(w_->ctrls[index]); | ||||
|                     } | ||||
|                     assert(well_controls_get_current(w_->ctrls[index]) < 0); | ||||
|                 } else if (line.openshutflag_ == "OPEN") { | ||||
|                     int cur_ctrl = well_controls_get_current(w_->ctrls[index]); | ||||
|                     if (cur_ctrl < 0) { | ||||
|                         well_controls_invert_current(w_->ctrls[index]); | ||||
|                     } | ||||
|                     assert(well_controls_get_current(w_->ctrls[index]) >= 0); | ||||
|                 } else { | ||||
|                     OPM_THROW(std::runtime_error, "Unknown Open/close keyword: \"" << line.openshutflag_<< "\". Allowed values: OPEN, SHUT."); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Build the well_collection_ well group hierarchy. | ||||
|         if (deck.hasField("GRUPTREE")) { | ||||
|             std::cout << "Found gruptree" << std::endl; | ||||
|             const GRUPTREE& gruptree = deck.getGRUPTREE(); | ||||
|             std::map<std::string, std::string>::const_iterator it = gruptree.tree.begin(); | ||||
|             for( ; it != gruptree.tree.end(); ++it) { | ||||
|                 well_collection_.addChild(it->first, it->second, deck); | ||||
|             } | ||||
|         } | ||||
|         for (size_t i = 0; i < welspecs.welspecs.size(); ++i) { | ||||
|             WelspecsLine line = welspecs.welspecs[i]; | ||||
|             well_collection_.addChild(line.name_, line.group_, deck); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         // Set the guide rates: | ||||
|         if (deck.hasField("WGRUPCON")) { | ||||
|             std::cout << "Found Wgrupcon" << std::endl; | ||||
|             WGRUPCON wgrupcon = deck.getWGRUPCON(); | ||||
|             const std::vector<WgrupconLine>& lines = wgrupcon.wgrupcon; | ||||
|             std::cout << well_collection_.getLeafNodes().size() << std::endl; | ||||
|             for (size_t i = 0; i < lines.size(); i++) { | ||||
|                 std::string name = lines[i].well_; | ||||
|                 const int wix = well_names_to_index[name]; | ||||
|                 WellNode& wellnode = *well_collection_.getLeafNodes()[wix]; | ||||
|                 assert(wellnode.name() == name); | ||||
|                 if (well_data[wix].type == PRODUCER) { | ||||
|                     wellnode.prodSpec().guide_rate_ = lines[i].guide_rate_; | ||||
|                     if (lines[i].phase_ == "OIL") { | ||||
|                         wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::OIL; | ||||
|                     } else { | ||||
|                         OPM_THROW(std::runtime_error, "Guide rate type " << lines[i].phase_ << " specified for producer " | ||||
|                               << name << " in WGRUPCON, cannot handle."); | ||||
|                     } | ||||
|                 } else if (well_data[wix].type == INJECTOR) { | ||||
|                     wellnode.injSpec().guide_rate_ = lines[i].guide_rate_; | ||||
|                     if (lines[i].phase_ == "RAT") { | ||||
|                         wellnode.injSpec().guide_rate_type_ = InjectionSpecification::RAT; | ||||
|                     } else { | ||||
|                         OPM_THROW(std::runtime_error, "Guide rate type " << lines[i].phase_ << " specified for injector " | ||||
|                               << name << " in WGRUPCON, cannot handle."); | ||||
|                     } | ||||
|                 } else { | ||||
|                     OPM_THROW(std::runtime_error, "Unknown well type " << well_data[wix].type << " for well " << name); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         well_collection_.setWellsPointer(w_); | ||||
|         well_collection_.applyGroupControls(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /// Construct wells from deck. | ||||
|     WellsManager::WellsManager(const Opm::EclipseGridParser& deck, | ||||
|   | ||||
| @@ -21,6 +21,8 @@ | ||||
| #define OPM_WELLSMANAGER_HEADER_INCLUDED | ||||
|  | ||||
|  | ||||
| #include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp> | ||||
|  | ||||
| #include <opm/core/wells/WellCollection.hpp> | ||||
| #include <opm/core/wells/WellsGroup.hpp> | ||||
|  | ||||
| @@ -56,7 +58,14 @@ namespace Opm | ||||
| 	/// order to approximate these by the Peaceman formula. | ||||
| 	WellsManager(const Opm::EclipseGridParser& deck, | ||||
| 		     const UnstructuredGrid& grid, | ||||
| 		     const double* permeability); | ||||
|              const double* permeability); | ||||
|  | ||||
|  | ||||
|     WellsManager(const Opm::SchedulePtr schedule, | ||||
|                  const size_t timeStep, | ||||
|                  const Opm::EclipseGridParser& deck, | ||||
|                  const UnstructuredGrid& grid, | ||||
|                  const double* permeability); | ||||
|  | ||||
| 	/// Destructor. | ||||
| 	~WellsManager(); | ||||
|   | ||||
| @@ -27,6 +27,10 @@ | ||||
|  | ||||
| #define BOOST_TEST_MODULE WellsManagerTests | ||||
| #include <boost/test/unit_test.hpp> | ||||
|  | ||||
| #include <opm/parser/eclipse/Parser/Parser.hpp> | ||||
| #include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp> | ||||
|  | ||||
| #include <opm/core/wells/WellsManager.hpp> | ||||
| #include <opm/core/wells.h> | ||||
| #include <opm/core/well_controls.h> | ||||
| @@ -195,6 +199,39 @@ BOOST_AUTO_TEST_CASE(Constructor_Works) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| BOOST_AUTO_TEST_CASE(New_Constructor_Works) { | ||||
|  | ||||
|     Opm::ParserPtr parser(new Opm::Parser()); | ||||
|     Opm::SchedulePtr schedule(new Opm::Schedule(parser->parse("wells_manager_data.data"))); | ||||
|  | ||||
|     Opm::EclipseGridParser Deck("wells_manager_data.data"); | ||||
|     Opm::GridManager gridManager(Deck); | ||||
|  | ||||
|     Deck.setCurrentEpoch(0); | ||||
|     { | ||||
|         Opm::WellsManager wellsManager(schedule, 0, Deck, *gridManager.c_grid(), NULL); | ||||
|         Opm::WellsManager oldWellsManager(Deck, *gridManager.c_grid(), NULL); | ||||
|  | ||||
|         const Wells* wells = wellsManager.c_wells(); | ||||
|         wells_static_check( wells ); | ||||
|         check_controls_epoch0( wells->ctrls ); | ||||
|  | ||||
|         BOOST_CHECK(wells_equal(wells, oldWellsManager.c_wells())); | ||||
|     } | ||||
|  | ||||
|     Deck.setCurrentEpoch(1); | ||||
|     { | ||||
|         Opm::WellsManager wellsManager(schedule, 1,Deck, *gridManager.c_grid(), NULL); | ||||
|         Opm::WellsManager oldWellsManager(Deck, *gridManager.c_grid(), NULL); | ||||
|  | ||||
|         const Wells* wells = wellsManager.c_wells(); | ||||
|         wells_static_check( wells ); | ||||
|         check_controls_epoch1( wells->ctrls ); | ||||
|  | ||||
|         BOOST_CHECK(wells_equal(wells, oldWellsManager.c_wells())); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| BOOST_AUTO_TEST_CASE(WellsEqual) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user