mirror of
https://github.com/OPM/opm-simulators.git
synced 2024-12-24 16:30:02 -06:00
Use Well CF and Kh calculations from opm-common
This commit is contained in:
parent
25248066d8
commit
b9df94a70f
@ -59,7 +59,7 @@ namespace Opm
|
|||||||
const WellConnections& completion_set = well_ecl_->getConnections(current_step_);
|
const WellConnections& completion_set = well_ecl_->getConnections(current_step_);
|
||||||
for (int perf = 0; perf < number_of_perforations_; ++perf) {
|
for (int perf = 0; perf < number_of_perforations_; ++perf) {
|
||||||
const Connection& connection = completion_set.get(perf);
|
const Connection& connection = completion_set.get(perf);
|
||||||
const int segment_index = segmentNumberToIndex(connection.segment_number);
|
const int segment_index = segmentNumberToIndex(connection.segment());
|
||||||
segment_perforations_[segment_index].push_back(perf);
|
segment_perforations_[segment_index].push_back(perf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ namespace Opm
|
|||||||
for (int seg = 0; seg < numberOfSegments(); ++seg) {
|
for (int seg = 0; seg < numberOfSegments(); ++seg) {
|
||||||
const double segment_depth = segmentSet()[seg].depth();
|
const double segment_depth = segmentSet()[seg].depth();
|
||||||
for (const int perf : segment_perforations_[seg]) {
|
for (const int perf : segment_perforations_[seg]) {
|
||||||
perf_depth_[perf] = completion_set.get(perf).center_depth;
|
perf_depth_[perf] = completion_set.get(perf).depth();
|
||||||
perforation_segment_depth_diffs_[perf] = perf_depth_[perf] - segment_depth;
|
perforation_segment_depth_diffs_[perf] = perf_depth_[perf] - segment_depth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,7 +552,7 @@ namespace Opm
|
|||||||
for (const auto& completion : completions) {
|
for (const auto& completion : completions) {
|
||||||
int complnum = completion.first;
|
int complnum = completion.first;
|
||||||
for (int perf = 0; perf < perf_number; ++perf) {
|
for (int perf = 0; perf < perf_number; ++perf) {
|
||||||
if (complnum == connections.get ( perf ).complnum) {
|
if (complnum == connections.get ( perf ).complnum()) {
|
||||||
water_cut_in_completions[complnumIdx] += water_cut_perf[perf];
|
water_cut_in_completions[complnumIdx] += water_cut_perf[perf];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -730,7 +730,7 @@ namespace Opm
|
|||||||
bool allCompletionsClosed = true;
|
bool allCompletionsClosed = true;
|
||||||
const auto& connections = well_ecl_->getConnections(current_step_);
|
const auto& connections = well_ecl_->getConnections(current_step_);
|
||||||
for (const auto& connection : connections) {
|
for (const auto& connection : connections) {
|
||||||
if (!wellTestState.hasCompletion(name(), connection.complnum)) {
|
if (!wellTestState.hasCompletion(name(), connection.complnum())) {
|
||||||
allCompletionsClosed = false;
|
allCompletionsClosed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -802,7 +802,7 @@ namespace Opm
|
|||||||
const auto& connectionSet = well_ecl_->getConnections(current_step_);
|
const auto& connectionSet = well_ecl_->getConnections(current_step_);
|
||||||
for (size_t c=0; c<connectionSet.size(); c++) {
|
for (size_t c=0; c<connectionSet.size(); c++) {
|
||||||
const auto& connection = connectionSet.get(c);
|
const auto& connection = connectionSet.get(c);
|
||||||
if (connection.state == WellCompletion::OPEN) {
|
if (connection.state() == WellCompletion::OPEN) {
|
||||||
const int i = connection.getI();
|
const int i = connection.getI();
|
||||||
const int j = connection.getJ();
|
const int j = connection.getJ();
|
||||||
const int k = connection.getK();
|
const int k = connection.getK();
|
||||||
@ -817,19 +817,14 @@ namespace Opm
|
|||||||
const int cell = cgit->second;
|
const int cell = cgit->second;
|
||||||
|
|
||||||
{
|
{
|
||||||
double radius = 0.5*connection.getDiameter();
|
double radius = connection.rw();
|
||||||
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 =
|
const std::array<double, 3> cubical =
|
||||||
WellsManagerDetail::getCubeDim<3>(cell_to_faces, begin_face_centroids, cell);
|
WellsManagerDetail::getCubeDim<3>(cell_to_faces, begin_face_centroids, cell);
|
||||||
|
|
||||||
double re; // area equivalent radius of the grid block
|
double re; // area equivalent radius of the grid block
|
||||||
double perf_length; // the length of the well perforation
|
double perf_length; // the length of the well perforation
|
||||||
|
|
||||||
switch (connection.dir) {
|
switch (connection.dir()) {
|
||||||
case Opm::WellCompletion::DirectionEnum::X:
|
case Opm::WellCompletion::DirectionEnum::X:
|
||||||
re = std::sqrt(cubical[1] * cubical[2] / M_PI);
|
re = std::sqrt(cubical[1] * cubical[2] / M_PI);
|
||||||
perf_length = cubical[0];
|
perf_length = cubical[0];
|
||||||
@ -918,7 +913,7 @@ namespace Opm
|
|||||||
const auto& connections = well_ecl_->getConnections(current_step_);
|
const auto& connections = well_ecl_->getConnections(current_step_);
|
||||||
int perfIdx = 0;
|
int perfIdx = 0;
|
||||||
for (const auto& connection : connections) {
|
for (const auto& connection : connections) {
|
||||||
if (wellTestState.hasCompletion(name(), connection.complnum)) {
|
if (wellTestState.hasCompletion(name(), connection.complnum())) {
|
||||||
well_index_[perfIdx] = 0.0;
|
well_index_[perfIdx] = 0.0;
|
||||||
}
|
}
|
||||||
perfIdx++;
|
perfIdx++;
|
||||||
|
@ -559,7 +559,7 @@ namespace Opm
|
|||||||
std::vector<std::vector<int>> segment_perforations(well_nseg);
|
std::vector<std::vector<int>> segment_perforations(well_nseg);
|
||||||
for (int perf = 0; perf < nperf; ++perf) {
|
for (int perf = 0; perf < nperf; ++perf) {
|
||||||
const Connection& connection = completion_set.get(perf);
|
const Connection& connection = completion_set.get(perf);
|
||||||
const int segment_index = segment_set.segmentNumberToIndex(connection.segment_number);
|
const int segment_index = segment_set.segmentNumberToIndex(connection.segment());
|
||||||
segment_perforations[segment_index].push_back(perf);
|
segment_perforations[segment_index].push_back(perf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,134 +175,6 @@ namespace WellsManagerDetail
|
|||||||
|
|
||||||
} // namespace InjectionControl
|
} // namespace InjectionControl
|
||||||
|
|
||||||
// Compute direction permutation corresponding to completion's
|
|
||||||
// direction. First two elements of return value are directions
|
|
||||||
// perpendicular to completion while last element is direction
|
|
||||||
// along completion.
|
|
||||||
inline std::array< std::array<double,3>::size_type, 3 >
|
|
||||||
directionIndices(const Opm::WellCompletion::DirectionEnum direction)
|
|
||||||
{
|
|
||||||
typedef std::array<double,3>::size_type idx_t;
|
|
||||||
typedef std::array<idx_t,3> permutation;
|
|
||||||
|
|
||||||
switch (direction) {
|
|
||||||
case Opm::WellCompletion::DirectionEnum::X:
|
|
||||||
return permutation {{ idx_t(1), idx_t(2), idx_t(0) }};
|
|
||||||
|
|
||||||
case Opm::WellCompletion::DirectionEnum::Y:
|
|
||||||
return permutation {{ idx_t(2), idx_t(0), idx_t(1) }};
|
|
||||||
|
|
||||||
case Opm::WellCompletion::DirectionEnum::Z:
|
|
||||||
return permutation {{ idx_t(0), idx_t(1), idx_t(2) }};
|
|
||||||
}
|
|
||||||
// All enum values should be handled above. Therefore
|
|
||||||
// we should never reach this one. Anyway for the sake
|
|
||||||
// of reduced warnings we throw an exception.
|
|
||||||
throw std::invalid_argument("unhandled enum value");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Permute (diagonal) permeability components according to
|
|
||||||
// completion's direction.
|
|
||||||
inline std::array<double,3>
|
|
||||||
permComponents(const Opm::WellCompletion::DirectionEnum direction,
|
|
||||||
const double* perm)
|
|
||||||
{
|
|
||||||
const auto p = directionIndices(direction);
|
|
||||||
const std::array<double,3>::size_type d = 3;
|
|
||||||
|
|
||||||
std::array<double,3>
|
|
||||||
K = {{ perm[ p[0]*(d + 1) ] ,
|
|
||||||
perm[ p[1]*(d + 1) ] ,
|
|
||||||
perm[ p[2]*(d + 1) ] }};
|
|
||||||
|
|
||||||
return K;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Permute cell's geometric extent according to completion's
|
|
||||||
// direction. Honour net-to-gross ratio.
|
|
||||||
//
|
|
||||||
// Note: 'extent' is intentionally accepted by modifiable value
|
|
||||||
// rather than reference-to-const to support NTG manipulation.
|
|
||||||
inline std::array<double,3>
|
|
||||||
effectiveExtent(const Opm::WellCompletion::DirectionEnum direction,
|
|
||||||
const double ntg,
|
|
||||||
std::array<double,3> extent)
|
|
||||||
{
|
|
||||||
// Vertical extent affected by net-to-gross ratio.
|
|
||||||
extent[2] *= ntg;
|
|
||||||
|
|
||||||
const auto p = directionIndices(direction);
|
|
||||||
|
|
||||||
std::array<double,3>
|
|
||||||
D = {{ extent[ p[0] ] ,
|
|
||||||
extent[ p[1] ] ,
|
|
||||||
extent[ p[2] ] }};
|
|
||||||
|
|
||||||
return D;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute Peaceman's effective radius of single completion.
|
|
||||||
inline double
|
|
||||||
effectiveRadius(const std::array<double,3>& K,
|
|
||||||
const std::array<double,3>& D)
|
|
||||||
{
|
|
||||||
const double K01 = K[0] / K[1];
|
|
||||||
const double K10 = K[1] / K[0];
|
|
||||||
|
|
||||||
const double D0_sq = D[0] * D[0];
|
|
||||||
const double D1_sq = D[1] * D[1];
|
|
||||||
|
|
||||||
const double num = std::sqrt((std::sqrt(K10) * D0_sq) +
|
|
||||||
(std::sqrt(K01) * D1_sq));
|
|
||||||
const double den = std::pow(K01, 0.25) + std::pow(K10, 0.25);
|
|
||||||
|
|
||||||
// Note: Analytic constant 0.28 derived for infintely sized
|
|
||||||
// formation with repeating well placement.
|
|
||||||
return 0.28 * (num / den);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the Peaceman well model to compute well indices.
|
|
||||||
// radius is the radius of the well.
|
|
||||||
// cubical contains [dx, dy, dz] of the cell.
|
|
||||||
// (Note that the well model asumes that each cell is a cuboid).
|
|
||||||
// cell_permeability is the permeability tensor of the given cell.
|
|
||||||
// returns the well index of the cell.
|
|
||||||
double
|
|
||||||
computeWellIndex(const double radius,
|
|
||||||
const std::array<double, 3>& cubical,
|
|
||||||
const double* cell_permeability,
|
|
||||||
const double skin_factor,
|
|
||||||
const Opm::WellCompletion::DirectionEnum direction,
|
|
||||||
const double ntg)
|
|
||||||
{
|
|
||||||
const std::array<double,3>& K =
|
|
||||||
permComponents(direction, cell_permeability);
|
|
||||||
|
|
||||||
const std::array<double,3>& D =
|
|
||||||
effectiveExtent(direction, ntg, cubical);
|
|
||||||
|
|
||||||
const double r0 = effectiveRadius(K, D);
|
|
||||||
const double Kh = std::sqrt(K[0] * K[1]) * D[2];
|
|
||||||
|
|
||||||
// Angle of completion exposed to flow. We assume centre
|
|
||||||
// placement so there's complete exposure (= 2\pi).
|
|
||||||
const double angle =
|
|
||||||
6.2831853071795864769252867665590057683943387987502116419498;
|
|
||||||
|
|
||||||
double rw = radius;
|
|
||||||
if (r0 < rw) {
|
|
||||||
std::cerr << "Completion radius exceeds effective radius\n"
|
|
||||||
<< "Reset to effective\n";
|
|
||||||
|
|
||||||
rw = r0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: The formula is originally derived and valid for
|
|
||||||
// Cartesian grids only.
|
|
||||||
return (angle * Kh) / (std::log(r0 / rw) + skin_factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,12 +54,6 @@ namespace WellsManagerDetail
|
|||||||
|
|
||||||
} // namespace InjectionControl
|
} // namespace InjectionControl
|
||||||
|
|
||||||
double computeWellIndex(const double radius,
|
|
||||||
const std::array<double, 3>& cubical,
|
|
||||||
const double* cell_permeability,
|
|
||||||
const double skin_factor,
|
|
||||||
const Opm::WellCompletion::DirectionEnum direction,
|
|
||||||
const double ntg);
|
|
||||||
|
|
||||||
template <int dim, class C2F, class FC>
|
template <int dim, class C2F, class FC>
|
||||||
std::array<double, dim>
|
std::array<double, dim>
|
||||||
@ -165,7 +159,7 @@ void WellsManager::createWellsFromSpecs(std::vector<const Well*>& wells, size_t
|
|||||||
// shut completions and open ones stored in this process will have 1 others 0.
|
// shut completions and open ones stored in this process will have 1 others 0.
|
||||||
|
|
||||||
for(const auto& completion : well->getConnections(timeStep)) {
|
for(const auto& completion : well->getConnections(timeStep)) {
|
||||||
if (completion.state == WellCompletion::OPEN) {
|
if (completion.state() == WellCompletion::OPEN) {
|
||||||
int i = completion.getI();
|
int i = completion.getI();
|
||||||
int j = completion.getJ();
|
int j = completion.getJ();
|
||||||
int k = completion.getK();
|
int k = completion.getK();
|
||||||
@ -193,41 +187,14 @@ void WellsManager::createWellsFromSpecs(std::vector<const Well*>& wells, size_t
|
|||||||
|
|
||||||
PerfData pd;
|
PerfData pd;
|
||||||
pd.cell = cell;
|
pd.cell = cell;
|
||||||
{
|
pd.well_index = completion.CF() * completion.wellPi();
|
||||||
const Value<double>& transmissibilityFactor = completion.getConnectionTransmissibilityFactorAsValueObject();
|
pd.satnumid = completion.satTableId();
|
||||||
const double wellPi = completion.wellPi;
|
|
||||||
if (transmissibilityFactor.hasValue()) {
|
|
||||||
pd.well_index = transmissibilityFactor.getValue();
|
|
||||||
} 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 =
|
|
||||||
WellsManagerDetail::getCubeDim<3>(c2f, begin_face_centroids, cell);
|
|
||||||
|
|
||||||
// overwrite dz values calculated in getCubeDim.
|
|
||||||
if (dz.size() > 0) {
|
|
||||||
cubical[2] = dz[cell];
|
|
||||||
}
|
|
||||||
|
|
||||||
const double* cell_perm = &permeability[dimensions*dimensions*cell];
|
|
||||||
pd.well_index =
|
|
||||||
WellsManagerDetail::computeWellIndex(radius, cubical, cell_perm,
|
|
||||||
completion.getSkinFactor(),
|
|
||||||
completion.dir,
|
|
||||||
ntg[cell]);
|
|
||||||
}
|
|
||||||
pd.satnumid = completion.sat_tableId;
|
|
||||||
pd.well_index *= wellPi;
|
|
||||||
}
|
|
||||||
wellperf_data[active_well_index].push_back(pd);
|
wellperf_data[active_well_index].push_back(pd);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (completion.state != WellCompletion::SHUT) {
|
if (completion.state() != WellCompletion::SHUT) {
|
||||||
OPM_THROW(std::runtime_error, "Completion state: " << WellCompletion::StateEnum2String( completion.state ) << " not handled");
|
OPM_THROW(std::runtime_error, "Completion state: " << WellCompletion::StateEnum2String( completion.state() ) << " not handled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user