mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Extracted well specification and completion data setup to a function
This commit is contained in:
parent
30df3cab37
commit
e12ec1b25d
@ -47,23 +47,8 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
struct WellData
|
|
||||||
{
|
|
||||||
WellType type;
|
|
||||||
// WellControlType control;
|
|
||||||
// double target;
|
|
||||||
double reference_bhp_depth;
|
|
||||||
// Opm::InjectionSpecification::InjectorType injected_phase;
|
|
||||||
int welspecsline;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct PerfData
|
|
||||||
{
|
|
||||||
int cell;
|
|
||||||
double well_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace ProductionControl
|
namespace ProductionControl
|
||||||
{
|
{
|
||||||
enum Mode { ORAT, WRAT, GRAT,
|
enum Mode { ORAT, WRAT, GRAT,
|
||||||
@ -301,23 +286,8 @@ namespace Opm
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
std::map<int,int> cartesian_to_compressed;
|
||||||
|
setupCompressedToCartesian(grid, 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Obtain phase usage data.
|
// Obtain phase usage data.
|
||||||
PhaseUsage pu = phaseUsageFromDeck(eclipseState);
|
PhaseUsage pu = phaseUsageFromDeck(eclipseState);
|
||||||
@ -330,121 +300,17 @@ namespace Opm
|
|||||||
|
|
||||||
// For easy lookup:
|
// For easy lookup:
|
||||||
std::map<std::string, int> well_names_to_index;
|
std::map<std::string, int> well_names_to_index;
|
||||||
typedef std::map<std::string, int>::const_iterator WNameIt;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Main "well-loop" to populate the data structures (well_names, well_data, ...)
|
|
||||||
ScheduleConstPtr schedule = eclipseState->getSchedule();
|
ScheduleConstPtr schedule = eclipseState->getSchedule();
|
||||||
std::vector<WellConstPtr> wells = schedule->getWells(timeStep);
|
std::vector<WellConstPtr> wells = schedule->getWells(timeStep);
|
||||||
|
|
||||||
well_names.reserve(wells.size());
|
well_names.reserve(wells.size());
|
||||||
well_data.reserve(wells.size());
|
well_data.reserve(wells.size());
|
||||||
wellperf_data.resize(wells.size());
|
wellperf_data.resize(wells.size());
|
||||||
|
|
||||||
|
createWellsFromSpecs(schedule, timeStep, grid, well_names, well_data, wellperf_data, well_names_to_index, pu, cartesian_to_compressed, permeability);
|
||||||
|
|
||||||
int well_index = 0;
|
int well_index = 0;
|
||||||
for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
|
|
||||||
WellConstPtr well = (*wellIter);
|
|
||||||
{ // WELSPECS handling
|
|
||||||
well_names_to_index[well->name()] = well_index;
|
|
||||||
well_names.push_back(well->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 = (well->getRefDepth() < 0.0) ? -1e100 : well->getRefDepth();
|
|
||||||
wd.welspecsline = -1;
|
|
||||||
if (well->isInjector( timeStep ))
|
|
||||||
wd.type = INJECTOR;
|
|
||||||
else
|
|
||||||
wd.type = PRODUCER;
|
|
||||||
well_data.push_back(wd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // COMPDAT handling
|
|
||||||
CompletionSetConstPtr completionSet = well->getCompletions(timeStep);
|
|
||||||
for (size_t c=0; c<completionSet->size(); c++) {
|
|
||||||
CompletionConstPtr completion = completionSet->get(c);
|
|
||||||
int i = completion->getI();
|
|
||||||
int j = completion->getJ();
|
|
||||||
int k = completion->getK();
|
|
||||||
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;
|
|
||||||
PerfData pd;
|
|
||||||
pd.cell = cell;
|
|
||||||
if (completion->getCF() > 0.0) {
|
|
||||||
pd.well_index = completion->getCF();
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
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, completion->getDiameter());
|
|
||||||
}
|
|
||||||
wellperf_data[well_index].push_back(pd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
well_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up reference depths that were defaulted. Count perfs.
|
|
||||||
|
|
||||||
const int num_wells = well_data.size();
|
|
||||||
|
|
||||||
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.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
well_index = 0;
|
|
||||||
for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
|
for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
|
||||||
WellConstPtr well = (*wellIter);
|
WellConstPtr well = (*wellIter);
|
||||||
|
|
||||||
@ -1433,4 +1299,138 @@ namespace Opm
|
|||||||
well_collection_.applyExplicitReinjectionControls(well_reservoirrates_phase, well_surfacerates_phase);
|
well_collection_.applyExplicitReinjectionControls(well_reservoirrates_phase, well_surfacerates_phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WellsManager::setupCompressedToCartesian(const UnstructuredGrid& grid, std::map<int,int>& cartesian_to_compressed ) {
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void WellsManager::createWellsFromSpecs(ScheduleConstPtr schedule, size_t timeStep,
|
||||||
|
const UnstructuredGrid& grid,
|
||||||
|
std::vector<std::string>& well_names,
|
||||||
|
std::vector<WellData>& well_data,
|
||||||
|
std::vector<std::vector<PerfData> >& wellperf_data,
|
||||||
|
std::map<std::string, int>& well_names_to_index,
|
||||||
|
const PhaseUsage& phaseUsage,
|
||||||
|
std::map<int,int> cartesian_to_compressed,
|
||||||
|
const double* permeability)
|
||||||
|
{
|
||||||
|
std::vector<WellConstPtr> wells = schedule->getWells(timeStep);
|
||||||
|
int well_index = 0;
|
||||||
|
for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
|
||||||
|
WellConstPtr well = (*wellIter);
|
||||||
|
{ // WELSPECS handling
|
||||||
|
well_names_to_index[well->name()] = well_index;
|
||||||
|
well_names.push_back(well->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 = (well->getRefDepth() < 0.0) ? -1e100 : well->getRefDepth();
|
||||||
|
wd.welspecsline = -1;
|
||||||
|
if (well->isInjector( timeStep ))
|
||||||
|
wd.type = INJECTOR;
|
||||||
|
else
|
||||||
|
wd.type = PRODUCER;
|
||||||
|
well_data.push_back(wd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // COMPDAT handling
|
||||||
|
CompletionSetConstPtr completionSet = well->getCompletions(timeStep);
|
||||||
|
for (size_t c=0; c<completionSet->size(); c++) {
|
||||||
|
CompletionConstPtr completion = completionSet->get(c);
|
||||||
|
int i = completion->getI();
|
||||||
|
int j = completion->getJ();
|
||||||
|
int k = completion->getK();
|
||||||
|
|
||||||
|
const int* cpgdim = grid.cartdims;
|
||||||
|
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;
|
||||||
|
PerfData pd;
|
||||||
|
pd.cell = cell;
|
||||||
|
if (completion->getCF() > 0.0) {
|
||||||
|
pd.well_index = completion->getCF();
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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, completion->getDiameter());
|
||||||
|
}
|
||||||
|
wellperf_data[well_index].push_back(pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
well_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up reference depths that were defaulted. Count perfs.
|
||||||
|
|
||||||
|
const int num_wells = well_data.size();
|
||||||
|
|
||||||
|
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(phaseUsage.num_phases, num_wells, num_perfs);
|
||||||
|
if (!w_) {
|
||||||
|
OPM_THROW(std::runtime_error, "Failed creating Wells struct.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
} // namespace Opm
|
} // namespace Opm
|
||||||
|
@ -34,7 +34,22 @@ namespace Opm
|
|||||||
{
|
{
|
||||||
|
|
||||||
class EclipseGridParser;
|
class EclipseGridParser;
|
||||||
|
struct WellData
|
||||||
|
{
|
||||||
|
WellType type;
|
||||||
|
// WellControlType control;
|
||||||
|
// double target;
|
||||||
|
double reference_bhp_depth;
|
||||||
|
// Opm::InjectionSpecification::InjectorType injected_phase;
|
||||||
|
int welspecsline;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct PerfData
|
||||||
|
{
|
||||||
|
int cell;
|
||||||
|
double well_index;
|
||||||
|
};
|
||||||
/// This class manages a Wells struct in the sense that it
|
/// This class manages a Wells struct in the sense that it
|
||||||
/// encapsulates creation and destruction of the wells
|
/// encapsulates creation and destruction of the wells
|
||||||
/// data structure.
|
/// data structure.
|
||||||
@ -42,41 +57,41 @@ namespace Opm
|
|||||||
class WellsManager
|
class WellsManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Default constructor -- no wells.
|
/// Default constructor -- no wells.
|
||||||
WellsManager();
|
WellsManager();
|
||||||
|
|
||||||
/// Construct from existing wells object.
|
/// Construct from existing wells object.
|
||||||
/// WellsManager is not properly initialised in the sense that the logic to
|
/// WellsManager is not properly initialised in the sense that the logic to
|
||||||
/// manage control switching does not exist.
|
/// manage control switching does not exist.
|
||||||
///
|
///
|
||||||
/// @param[in] W Existing wells object.
|
/// @param[in] W Existing wells object.
|
||||||
WellsManager(struct Wells* W);
|
WellsManager(struct Wells* W);
|
||||||
|
|
||||||
/// Construct from input deck and grid.
|
/// Construct from input deck and grid.
|
||||||
/// The permeability argument may be zero if the input contain
|
/// The permeability argument may be zero if the input contain
|
||||||
/// well productivity indices, otherwise it must be given in
|
/// well productivity indices, otherwise it must be given in
|
||||||
/// order to approximate these by the Peaceman formula.
|
/// order to approximate these by the Peaceman formula.
|
||||||
WellsManager(const Opm::EclipseGridParser& deck,
|
WellsManager(const Opm::EclipseGridParser& deck,
|
||||||
const UnstructuredGrid& grid,
|
const UnstructuredGrid& grid,
|
||||||
const double* permeability);
|
const double* permeability);
|
||||||
|
|
||||||
|
|
||||||
WellsManager(const Opm::EclipseStateConstPtr eclipseState,
|
WellsManager(const Opm::EclipseStateConstPtr eclipseState,
|
||||||
const size_t timeStep,
|
const size_t timeStep,
|
||||||
const Opm::EclipseGridParser& deck,
|
const Opm::EclipseGridParser& deck,
|
||||||
const UnstructuredGrid& grid,
|
const UnstructuredGrid& grid,
|
||||||
const double* permeability);
|
const double* permeability);
|
||||||
|
|
||||||
/// Destructor.
|
/// Destructor.
|
||||||
~WellsManager();
|
~WellsManager();
|
||||||
|
|
||||||
/// Does the "deck" define any wells?
|
/// Does the "deck" define any wells?
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
|
|
||||||
/// Access the managed Wells.
|
/// Access the managed Wells.
|
||||||
/// The method is named similarly to c_str() in std::string,
|
/// The method is named similarly to c_str() in std::string,
|
||||||
/// to make it clear that we are returning a C-compatible struct.
|
/// to make it clear that we are returning a C-compatible struct.
|
||||||
const Wells* c_wells() const;
|
const Wells* c_wells() const;
|
||||||
|
|
||||||
/// Access the well group hierarchy.
|
/// Access the well group hierarchy.
|
||||||
const WellCollection& wellCollection() const;
|
const WellCollection& wellCollection() const;
|
||||||
@ -117,18 +132,27 @@ namespace Opm
|
|||||||
void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
void applyExplicitReinjectionControls(const std::vector<double>& well_reservoirrates_phase,
|
||||||
const std::vector<double>& well_surfacerates_phase);
|
const std::vector<double>& well_surfacerates_phase);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Disable copying and assignment.
|
// Disable copying and assignment.
|
||||||
WellsManager(const WellsManager& other);
|
WellsManager(const WellsManager& other);
|
||||||
WellsManager& operator=(const WellsManager& other);
|
WellsManager& operator=(const WellsManager& other);
|
||||||
|
static void setupCompressedToCartesian(const UnstructuredGrid& grid, std::map<int,int>& cartesian_to_compressed );
|
||||||
// Data
|
void createWellsFromSpecs( ScheduleConstPtr schedule, size_t timeStep,
|
||||||
Wells* w_;
|
const UnstructuredGrid& grid,
|
||||||
WellCollection well_collection_;
|
std::vector<std::string>& well_names,
|
||||||
|
std::vector<WellData>& well_data,
|
||||||
|
std::vector<std::vector<PerfData> >& wellperf_data,
|
||||||
|
std::map<std::string, int> & well_names_to_index,
|
||||||
|
const PhaseUsage& phaseUsage,
|
||||||
|
const std::map<int,int> cartesian_to_compressed,
|
||||||
|
const double* permeability);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Data
|
||||||
|
Wells* w_;
|
||||||
|
WellCollection well_collection_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Opm
|
} // namespace Opm
|
||||||
|
Loading…
Reference in New Issue
Block a user