From 1f1c0ebcf32d4a04825b5e89dbd4889ba26d8144 Mon Sep 17 00:00:00 2001 From: Kristian Flikka Date: Tue, 7 Jan 2014 16:10:45 +0100 Subject: [PATCH] New constructor for WellsManager that also takes the new parser as argument. New test comparing old and new --- opm/core/wells/WellsManager.cpp | 594 ++++++++++++++++++++++++++++++++ opm/core/wells/WellsManager.hpp | 11 +- tests/test_wellsmanager.cpp | 37 ++ 3 files changed, 641 insertions(+), 1 deletion(-) diff --git a/opm/core/wells/WellsManager.cpp b/opm/core/wells/WellsManager.cpp index 007c8b52c..b934c4477 100644 --- a/opm/core/wells/WellsManager.cpp +++ b/opm/core/wells/WellsManager.cpp @@ -18,6 +18,8 @@ */ #include "config.h" + + #include #include #include @@ -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 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 well_names; + std::vector well_data; + std::vector > wellperf_data; + + // For easy lookup: + std::map well_names_to_index; + typedef std::map::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 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::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 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& lines = deck.getWCONINJE().wconinje; + for (size_t i = 0 ; i < lines.size(); ++i) { + const std::map::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& lines = deck.getWCONPROD().wconprod; + for (size_t i = 0; i < lines.size(); ++i) { + const std::map::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 perf_cells(w_num_perf); + std::vector 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::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::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& 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, diff --git a/opm/core/wells/WellsManager.hpp b/opm/core/wells/WellsManager.hpp index 35f7f471d..840e6f362 100644 --- a/opm/core/wells/WellsManager.hpp +++ b/opm/core/wells/WellsManager.hpp @@ -21,6 +21,8 @@ #define OPM_WELLSMANAGER_HEADER_INCLUDED +#include + #include #include @@ -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(); diff --git a/tests/test_wellsmanager.cpp b/tests/test_wellsmanager.cpp index b3465fac6..347f1d2b5 100644 --- a/tests/test_wellsmanager.cpp +++ b/tests/test_wellsmanager.cpp @@ -27,6 +27,10 @@ #define BOOST_TEST_MODULE WellsManagerTests #include + +#include +#include + #include #include #include @@ -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) {